Logging in .NET
Logging is a common and critical part of modern applications. It helps in tracking the flow of the application, troubleshooting issues, and monitoring the overall health of the system.
In .NET, logging is built into the framework and can be configured to log information from various parts of your application.
Logging Overview
In .NET, logging is handled through the ILogger<T>
interface, which can be injected into any class. This provides a unified API to write log messages at different levels, such as Information
, Warning
, Error
, and more.
ILogger
ILogger<T>
is the core logging interface in .NET. The T
in ILogger<T>
refers to the class where the logger is injected, helping to provide context about which part of the application is generating log messages.
public class MyService
{
private readonly ILogger<MyService> _logger;
public MyService(ILogger<MyService> logger)
{
_logger = logger;
}
public void DoWork()
{
_logger.LogInformation("Starting work...");
}
}
In this example, the logger is injected via constructor injection and is used to log an informational message.
Log Levels
.NET supports several logging levels, each representing the severity of the message being logged:
- Trace: Typically only useful for debugging purposes. Used to log very detailed information about the flow of the application. (e.g. "Starting DoWork method")
- Debug: Information useful for debugging during development. (e.g. "DoWork processed employee 123456")
- Information: General application flow information. (e.g. "DoWork method completed successfully")
- Warning: Something unexpected happened, but the application can still function correctly - usually to call out issues with the application your code handled correctly, but may need investigation. (e.g. "FileNotFoundException for file log.txt, but continued processing")
- Error: An error occurred, and the application might not be able to function as expected. (e.g. "Failed to connect to database")
- Critical: A critical failure that requires immediate attention. (e.g. "Application is shutting down due to unrecoverable error")
Example of logging at different levels:
public void DoWork()
{
_logger.LogTrace("This is a trace log.");
_logger.LogDebug("This is a debug log.");
_logger.LogInformation("This is an informational log.");
_logger.LogWarning("This is a warning log.");
_logger.LogError("This is an error log.");
_logger.LogCritical("This is a critical log.");
}
Configuring Logging
Logging is configured using the ILoggerFactory
and ILoggingBuilder
. By default, ASP.NET Core provides built-in logging providers such as:
- Console: Logs messages to the console.
- Debug: Logs messages to the Visual Studio debug output window.
- EventLog: Logs messages to the Windows Event Log (on Windows).
- EventSource: Logs messages to EventSource.
- TraceSource: Logs messages to System.Diagnostics.TraceSource.
Example of adding console and debug logging in Startup.cs
:
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddLogging(loggingBuilder =>
{
loggingBuilder.AddConsole();
loggingBuilder.AddDebug();
});
}
}
Logging to Files
To log messages to a file, you can use third-party logging providers, such as Serilog
or NLog
. Here’s an example of integrating Serilog:
public class Program
{
public static void Main(string[] args)
{
Log.Logger = new LoggerConfiguration()
.WriteTo.File("logs/log.txt")
.CreateLogger();
try
{
Log.Information("Application starting up...");
CreateHostBuilder(args).Build().Run();
}
finally
{
Log.CloseAndFlush();
}
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.UseSerilog() // Use Serilog instead of default logging
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
}
Microsoft does not provide a file logger by default. See GitHub issue here for context.
In most cloud systems, it's best to log to a centralized system. Examples include Azure Application Insights and Datadog.
Structured Logging
Structured logging allows you to log data in a structured format, which can be useful for querying and analyzing log data. Here's an example of using structured logging with ILogger
:
public void DoWork()
{
_logger.LogInformation("Processing order {OrderId} for customer {CustomerId}", 123, "cust-456");
}
This will log a message with placeholders for OrderId
and CustomerId
, allowing you to search for specific values in your logs.
Filtering Logs
You can configure log filtering to control which log levels are recorded for specific categories or providers. This is done in the appsettings.json
file:
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
}
}
In this example, the default log level is set to Information
, but Microsoft
logs are set to Warning
to reduce verbosity from the framework.
Logging in ASP.NET Core
In ASP.NET Core, logging is configured automatically by default, using the logging providers defined in the appsettings.json
file. You can further configure this by modifying the ConfigureLogging
method in your host builder.
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureLogging(logging =>
{
logging.ClearProviders();
logging.AddConsole();
})
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});