In the previous examples, we used the LogInformation method to log information messages, but there are other levels as well, shown in the following table:
Level | Method | Description | Production |
Trace | LogTrace | This is used to capture detailed information about the program, instrument execution speed, and debugging. You can also log sensitive information when using traces. | Disabled. |
Debug | LogDebug | This is used to log debugging and development information. | Disabled unless troubleshooting. |
Information | LogInformation | This is used to track the flow of the application. Normal events that occur in the system are often information-level events, such as the system started, the system stopped, and a user has signed in. | Enabled. |
Warning | LogWarning | This is used to log abnormal behavior in the application flow that does not cause the program to stop, but that may need to be investigated; for example, handled exceptions, failed network calls, and accessing resources that do not exist. | Enabled. |
Error | LogError | This is used to log errors in the application flow that do not cause the application to stop. Errors must usually be investigated. Examples include the failure of the current operation and an exception that cannot be handled. | Enabled. |
Critical | LogCritical | This is used to log errors that require immediate attention and represent a catastrophic state. The program is most likely about to stop, and the integrity of the application might be compromised; for example, a hard drive is full, the server is out of memory, or the database is in a deadlocked state. | Enabled with some alerts that could be configured to trigger automatically. |
Table 10.2: log entry levels
As described in the preceding table, each log level serves one or more purposes. Those log levels tell the logger what severity a log entry is. Then, we can configure the system to log only entries of at least a certain level so we don’t fill out production logs with traces and debug entries, for example. In a project I led, we benchmarked multiple ways to log simple and complex messages using ASP.NET Core to build clear and optimized guidelines around that. We could not reach a fair conclusion when the messages were logged due to a large time variance between benchmark runs. However, we observed a constant trend when messages were not logged (trace logs with the minimum logging level configured to debug, for example).Based on that conclusion, I recommend logging the Trace and Debug messages using the following construct instead of interpolation, string.Format, or other means. That may sound strange to optimize for not logging something, but if you think about it, those log entries will be skipped in production, so optimizing them will save your production app a few milliseconds of computing time here and there. Moreover, it’s not harder or longer to do, so it’s just a good habit.Let’s look at the fastest way to not write log entries:
_logger.LogTrace(“Some: {variable}”, variable);
// Or
_logger.LogTrace(“Some: {0}”, variable);
When the log level is disabled, such as in production, you only pay the price of a method call because no processing is done on your log entries. On the other hand, if we use interpolation, the processing is done, so that one argument is passed to the Log[Level] method, leading to a higher cost in processing power for each log entry.Here’s an example of interpolation (a.k.a. what not to do):
_logger.LogTrace($”Some: {variable}”);
For warning and higher levels, you can keep the good habit and use the same technique or other methods because we know those lines will be logged anyway. Therefore, using interpolation in the code or letting the logger do it later should yield a similar result.
One last note. I suggest you don’t try to over-optimize your code before there is a need for that. The action of investing a lot of effort in optimizing something that does not need optimizing is known as premature optimization. The idea is to optimize just enough upfront and fix the performance when you find real issues.
Now that we know the log levels that .NET offers us, let’s look at the logging providers.