ℹ️ Information
The code in the following article was tested with ASP.NET 6 and 7.
Logging is an essential component for software development and maintenance. It helps us understand what is happening inside our applications, identify errors and unexpected behaviors, troubleshoot problems, and is also useful for auditing operations.
Create logs
In ASP.NET, logging is typically performed by obtaining an ILogger
or ILogger<T>
instance through dependency injection, and then using that instance to log messages.
Here is a step-by-step guide on how to set up and use logging:
Step 1: Configure logging in appsettings.json
One of the first steps you often do is to set up the logging configuration in your application's appsettings.json
file. This allows you to set the default logging level and define different logging levels for different categories.
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
}
}
Step 2: Add logging services in Program.cs
In your Program.cs
file, you can add and configure various logging providers, such as Console, Debug, or others.
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddLogging(config =>
{
config.AddConsole();
config.AddDebug();
// Other logging providers
});
// ...
Step 3: Set up dependency injection for the logger in your class
Within the classes where you want to do the logging, such as a controller, you would set up dependency injection to get an instance of ILogger
or ILogger<T>
.
public class HomeController : Controller
{
private readonly ILogger<HomeController> _logger;
public HomeController(ILogger<HomeController> logger)
{
_logger = logger;
}
}
Step 4: Use the logger to log messages
Finally, you can use the _logger
instance to log messages at various severity levels (from Trace
to Critical
).
public IActionResult Index()
{
_logger.LogInformation("Calling the Index method");
return View();
}
Configure logging
Logging can be easily configured either in the code or through configuration files, such as appsettings.json
. This configuration file can be used to enable or disable log providers, modify log levels, or even filter log messages. Typically, the Logging
section of the appsettings.{ENVIRONMENT}.json
files (where {ENVIRONMENT}
is the environment placeholder) provides the logging configuration.
A standard example of what a logging configuration might look like in an appsettings.json
file is as follows:
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
}
}
In this example, the default log level is set to Information
, and the log level for all categories that begin with Microsoft.AspNetCore
is set to Warning
.
The LogLevel
can be set for specific providers (like Logging:EventSource:LogLevel:Default:Information
), specific categories (like Logging:LogLevel:Microsoft.AspNetCore:Critical
), or all providers and all categories (like Logging:LogLevel:Default:Warning
). Any logs below the set minimum level will not be logged or displayed.
{
"Logging": {
"LogLevel": {
"Default": "Warning",
"Microsoft.AspNetCore": "Critical"
},
"EventSource": {
"LogLevel": {
"Default": "Information"
}
}
}
}
To mute all logs, you can specify LogLevel.None
.
{
"Logging": {
"LogLevel": {
"Default": "None"
}
}
}
This logging configuration offers a high degree of flexibility, enabling you to customize logging behavior to suit your application's requirements.
Log category
When you make a new ILogger
, you pick a category. Each log message from this ILogger
will have this category attached. Typically, the category is the name of the class. For instance, you might use ILogger<T>
to automatically set the category to be the same as the type name T
.
public class HomeController : Controller
{
private readonly ILogger<HomeController> _logger;
public HomeController(ILogger<HomeController> logger)
{
_logger = logger;
}
public IActionResult Index()
{
_logger.LogInformation("Calling the Index method");
return View();
}
}
If you want to pick the category yourself, you can use CreateLogger
from ILoggerFactory
. This is handy if you want to group log messages from different places under the same category.
public class HomeController : Controller
{
private readonly ILogger _logger;
public HomeController(ILoggerFactory loggerFactory)
{
_logger = loggerFactory.CreateLogger("MyCategory");
}
public IActionResult Index()
{
_logger.LogInformation("Calling the Index method");
return View();
}
}
So, using ILogger<T>
is like using CreateLogger
, but with the category being automatically set to the type name of T
.
Log level
A log level acts as a control mechanism to determine the depth of detail for your log messages. Each log level corresponds to a particular degree of seriousness and is often utilized to exclude logs of less critical nature.
The following table presents an overview of the different log levels:
LogLevel | Value | Method | Description |
---|---|---|---|
Trace | 0 | LogTrace | Contains the most detailed messages. These messages may contain sensitive application data and are typically used for debugging. |
Debug | 1 | LogDebug | Used for informational messages that might be useful during development and debugging. |
Information | 2 | LogInformation | Used to track the general flow of the application. These messages may have long-term value in understanding app behavior. |
Warning | 3 | LogWarning | Used for abnormal or unexpected events. Typically includes errors or conditions that don't cause the app to fail but might indicate potential issues. |
Error | 4 | LogError | Used 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 | Used for severe failures that require immediate attention, such as data loss scenarios or out of disk space. |
None | 6 | Indicates that a logging category should not write any messages. This level is typically used to completely disable logging. |
Logging providers
A logging provider is a component that receives log messages from the application and decides how and where to store or display these messages.
👉 Built-in logging providers
ASP.NET includes some registration providers as part of its shared framework, which are:
- Console: Logs output to the console.
-
Debug: Writes log output by using the
System.Diagnostics.Debug
class. - EventSource: Writes to a cross-platform event source.
-
EventLog: Sends log output to the Windows Event Log. Unlike the other providers, the
EventLog
provider does not inherit the default non-provider settings. IfEventLog
log settings aren't specified, they default toLogLevel.Warning
.
There are other registration providers provided by Microsoft that are not part of the shared framework. To use them, you must install them as extra nuget packages. These include:
- Azure App Services: It is part of the Microsoft.Extensions.Logging.AzureAppServices NuGet package and writes logs to text files in the file system of an Azure App Service application and to a blob archive in an Azure Storage account.
- Azure Application Insights: It is part of the Microsoft.Extensions.Logging.ApplicationInsights NuGet package and writes logs to Azure Application Insights, a service that monitors a web app and provides tools for querying and analyzing telemetry data.
👉 Third-party logging providers
There are various third-party logging tools that are compatible with ASP.NET, including:
Some third-party frameworks can perform semantic logging, also known as structured logging.
Semantic logging is an approach to logging that goes beyond simply logging text messages. Instead of writing unstructured log messages, it writes log events as well-defined data structures.
The advantage of semantic logging is that it makes it much easier to search, filter, and analyze logs. Because the data is structured, you can easily search for all login events by a specific user, or all events that occurred within a certain time range, without having to parse the text of each log message.
High-performance logging
When aiming for high-performance log registration, it is advisable to use LoggerMessage
class. This class provides an efficient approach to create cached delegates that require fewer object allocations and lower computational overhead compared to logger extension methods like LogInformation
and LogDebug
.
LoggerMessage
offers the following performance advantages over logger extension methods:
- It avoids the "boxing conversion" of value types such as
int
toobject
, which is required by logger extension methods. This is achieved by using staticAction
fields and extension methods with strongly-typed parameters in theLoggerMessage
approach. - It reduces the need to parse the message template (a named format string) with each log message write.
LoggerMessage
only requires parsing the template once during the message definition, saving processing time during actual log registration.
using Microsoft.Extensions.Logging;
public class MyClass
{
private static readonly Action<ILogger, string, int, bool> _logMessage = LoggerMessage.Define<string, int, bool>(
LogLevel.Information,
new EventId(1001, "MyEvent"),
"My message: {message}, {number}, {flag}");
private readonly ILogger _logger;
public MyClass(ILogger<MyClass> logger)
{
_logger = logger;
}
public void DoSomething()
{
var message = "Hello world";
var number = 10;
var flag = true;
_logMessage(_logger, message, number, flag);
}
}
In this example, the MyClass
class uses the LoggerMessage
class to define a cached delegate named _logMessage
. The delegate takes three parameters: a string message
, an integer number
, and a boolean flag
.
Inside the DoSomething()
method, the _logMessage
delegate is used to log a message using the _logger
instance. The value of the message
string, the number
integer, and the flag
boolean are passed to the delegate. The log message is formatted using the template specified in the delegate's definition.
This approach allows for avoiding "boxing conversion" of values and parsing the message template only during the definition of the _logMessage
delegate, thus providing better performance compared to logger extension methods.
Conclusion
Logging is a key feature in software development that allows for easy troubleshooting and auditing in applications. ASP.NET provides powerful logging capabilities, including built-in and third-party logging providers, enabling you to configure, categorize, and analyze logs according to your specific needs. The semantic or structured logging approach offers easier log analysis, and for performance-critical applications, the LoggerMessage
class enables efficient creation of cached delegates. Overall, good logging practices can significantly enhance an application's reliability, maintainability, and performance.
Top comments (4)
Great article! Please check out LogScope.NET library as an alternative logging API: github.com/devInstance/LogScope
I was not familiar with this library. I will add it among the third-party providers. Thanks for the suggestion!
I was actually thinking about looking up an article or a video regarding this particular topic, then stumpled upon this post by accident 😃
Great one ❤️
I am glad! Good study 😉