Choosing the Correct LogLevel in ASP.NET Core
ASP.NET Core includes a very powerful and easy to use logging framework. It provides you with a lot of options, including the level you want the log entry to be made. It can be tricky to choose the correct level so let’s explore it a bit.
Assumption I assume you are using the logging API to store logging messages to a persistent store, like a file, or a database.
Logging in ASP.NET
There is a great document provided by Microsoft that describes it’s logging API:
Logging in .NET Core and ASP.NET Core
https://docs.microsoft.com/en-us/aspnet/core/fundamentals/logging
I suggest you give it a read if you aren’t familiar with the logging API. In a nutshell, you use the Dependency Injection (DI) container to register the logging services and then inject loggers into your application code when needed.
Configuring the Proper Logger
When you inject a logger into your object, you choose the logging category by the type of logger you use:
namespace MyProject.Api
{
public class MyController
{
private readonly ILogger<MyController> _logger;
public MyController(ILogger<MyController> logger)
{
_logger = logger;
}
}
}
The logging category is a string containing the fully-qualified class name of MyController
, “MyProject.Api.MyController”. You can use this string in the appsettings.json
to control the logs being created:
{
"Logging": {
"LogLevel": {
"Default": "Information"
"MyProject.Api.MyController": "Warning"
}
}
}
This will log all messages Information
level or higher except for messages in the “MyProject.Api.MyController” category. For this category, only messages Warning
level or higher will be logged.
The Logging Levels
Here are the ‘standard’ logging levels used by the Logging API, and how Microsoft intended them to be used:
LogLevel | Value | Method | Description |
---|---|---|---|
Trace | 0 | LogTrace | Contain the most detailed messages. These messages may contain sensitive app data. These messages are disabled by default and should not be enabled in production. |
Debug | 1 | LogDebug | For debugging and development. Use with caution in production due to the high volume. |
Information | 2 | LogInformation | Tracks the general flow of the app. May have long-term value. |
Warning | 3 | LogWarning | For abnormal or unexpected events. Typically includes errors or conditions that don’t cause the app to fail. |
Error | 4 | LogError | For errors and exceptions that cannot be handled. These messages indicate a failure in the current operation or request, not an app-wide failure. |
Critical | 5 | LogCritical | For failures that require immediate attention. Examples: data loss scenarios, out of disk space. |
None | 6 | Specifies that a logging category should not write any messages. |
Choosing What to Log in an Environment
As demonstrated above, ASP.NET applications can choose what level to create logs by changing levels in the appsettings.json
file. This means the application can be configured differently for each target environment. What you choose to log on your local workstation during development can be much different than what is logged in a Production environment. Here is an example plan you may choose to use:
LogLevel | Development | Staging | Production |
---|---|---|---|
Trace | X | - | - |
Debug | X | - | - |
Information | X | ? | ? |
Warning | X | X | X |
Error | X | X | X |
Critical | X | X | X |
For Warning, Error and Critical Log Levels, You should probably log all of these, all the time. They should be infrequent and provide insights into issues that need attention.
It is not a good idea to configure your logging to produce messages at the Debug
and Trace
level except when developing locally. It should be well understood by all developers that they can use these to their advantage when developing locally, without concern of them being persisted to storage in any of the deployed environments. And the operations staff should also assume that there is never a need to enable logging at these levels (unless asked for explicitly, in order to diagnose an issue in a deployed environment).
That leaves the Information
level. It is probably the hardest thing to get correct. When you are developing the software, you may choose to add a log entry at the Information
level because it helps give you insight into the normal flow of processing requests:
- Log the identifiers of a given request, so you can know the data that was being processed at a particular time.
- Log when the flow enter or exits a given state (‘Starting’ or ‘Stopping’ a task)
- Log when calling an external API or service
But this can lead (rather quickly) to so many log entries being recorded that the storage of these entries becomes unsustainable.
So what should you do?
It has been my experience that most entries recorded at the Information
level only help diagnose issues that may arise. In a way, they are really Debug
level messages. So it may be wise to change the log level to Debug
and not record them in Staging/Production environments.
However, you can eliminate them all. I have found the best thing is to use Information
log level entries only where knowing something in the Staging/Production environments is useful for diagnosing issues that occur.
If the amount of log entries at the Information
level becomes overwhelming, use the overrides in the appsettings.json
to filter out the entries (or ‘noise’) by category.
Using my example above, you can set the default log level to Information
for all categories. Then, for a given category, you can set the warning level higher so that the Information
level messages are no longer logged:
{
"Logging": {
"LogLevel": {
"Default": "Information",
"MyProject.Api.MyController": "Warning"
}
}
}
This provides the necessary flexibility to strike a balance between Information log entries that provide value in Production and those that are noise.
Analyze and Revise
I recommend you analyze the log entries in each environment periodically to determine if the log entries being record are still useful in the given environment. You may find that some messages you once relied on are no longer as important. You may also find that the settings may be configured incorrectly and need to be put back to their proper logging levels.
Summary
Recording log entries is very useful in software development and the Logging API within ASP.NET Core applications is very flexible. Choose the level for each entry that makes sense. Then configure the logging API to only record entries at the proper level, depending on the environment. If you need to only record some messages within a given log level, include/exclude the entries based on their category names.
And don’t forget to periodically look at the logs to see if any of these settings need adjustment.