Skip to content

Logging Principles

Mike Lyttle edited this page Oct 31, 2024 · 2 revisions

Log Levels

  • Critical

    • used for errors that the application cannot recover from, requiring a restart

    • not common in our solution

  • Error

    • used for errors that indicate an issue the team needs to address

    • e.g. uncaught exceptions, missing/invalid configuration settings, database connection problems

  • Warning

    • used for errors and responses that might indicate an issue the team needs to address

    • e.g. unsuccessful responses from partners, database concurrency exceptions

  • Information

    • used for application startup messages and limited information about individual requests

    • e.g. single message summarizing the results of a request

  • Debug

    • used for major steps and decisions taken within a request

    • e.g. requests to partners, database operations

  • Trace

    • used for detailed information about particular methods and parameter values

    • not generally useful to commit, as this log level is not enabled by default, and we shouldn't need this level of detail outside local development

Environments

By default, local development and the dev environment are set to log everything at Debug level and above, while the test and prod environments are set to log everything at Information level and above.

Minimizing Duplicate Logs

Because of the way the code is organized, a single request may flow from a controller, into a method in a service, into another method in that service, into a different service, into another method, before eventually visiting a delegate or Refit API. Sometimes this results in duplicate logs, as similar messages and values are logged multiple times.

Several steps have been taken to reduce this:

  • Logs are made directly before performing actions (e.g. retrieving a resource through a Refit API), not at the start of methods. This means higher-level methods can count on lower-level details being logged and not need to repeat them.

    • An exception may be made if the low-level log does not convey enough information. For example, logging "Updating last login date and year of birth" in a service when calling a DB delegate that will log "Updating user profile in DB".
  • Important parameters (HDIDs, file IDs, etc.) are added as baggage to activities, ensuring they are attached to all logs made within those activities and within sub-activities. An activity is created automatically for each request, and additional activities can be created using ActivitySources as needed to separate particular operations. Baggage added to these additional activities persists only while that activity is not disposed, which is ideal for storing parameters that are particular to the operation rather than the request. Parameters associated with requests, like file IDs, can be added to the request activity (accessible via Activity.Current) in the controller.

    • Some baggage items are populated in Observability.cs for every request, negating the need to add them manually. "Subject" will be populated with the HDID of the requested resource and "User" will be populated with the HDID of the user making the request.
Clone this wiki locally