Serilog in .NET: Complete Guide to Structured Logging in ASP.NET Core
Serilog in .NET: Complete Guide to Structured Logging in ASP.NET Core
Serilog in .NET is a popular logging library for developers who need structured, searchable, and flexible application logs. While the built-in logging infrastructure in ASP.NET Core is powerful, Serilog provides additional capabilities for writing logs to files, consoles, databases, and external monitoring systems. It also makes it easier to attach structured properties such as UserId, RequestId, OrderId, and execution time to individual log events. This information becomes extremely useful when troubleshooting production applications. In this guide, you will learn what Serilog is, why it is useful in .NET applications, how to install and configure it in ASP.NET Core, how to use different log levels and sinks, how to log exceptions, and which practices should be followed when using Serilog in production environments.
Why Use Serilog in ASP.NET Core?
Serilog is a structured logging library designed for .NET applications. It allows developers to create log events containing both a human-readable message and structured data. Unlike traditional text logging, structured logging stores important values as properties that can later be searched, filtered, and analyzed.
For example, instead of writing a message such as “Order 125 failed”, an application can record an event with an OrderId property containing 125 and an appropriate exception or error message. Logging systems can then search specifically for OrderId, request identifiers, usernames, or other properties.
Why Use Serilog in ASP.NET Core?
ASP.NET Core already provides Microsoft.Extensions.Logging, but Serilog is useful when an application requires more control over log formatting, destinations, filtering, and structured properties. Serilog can integrate with the standard Microsoft logging abstractions, allowing application code to continue using familiar ILogger interfaces.
- Supports structured logging.
- Provides multiple log destinations called sinks.
- Supports configuration through appsettings.json.
- Allows filtering by log level and category.
- Can enrich logs with additional properties.
- Works well with ASP.NET Core applications and APIs.
- Can write logs to files, console, databases, and external systems.
This flexibility makes Serilog particularly useful for enterprise applications where developers need reliable diagnostic information without changing the application code every time a logging destination changes.
Installing Serilog in an ASP.NET Core Project
Structured logging means storing log information as meaningful properties instead of creating only a long formatted string. This approach makes logs easier for humans to read and easier for monitoring systems to process.
Traditional Logging
logger.LogInformation("User " + userId + " created order " + orderId);
Structured Logging with Serilog
Log.Information("User {UserId} created order {OrderId}", userId, orderId);
In the second example, UserId and OrderId are structured properties. A log analysis platform can search or filter these values independently. This becomes especially valuable when thousands of requests are processed every day.
Installing Serilog in an ASP.NET Core Project
The first step is to add the required Serilog packages to your ASP.NET Core project. The exact packages can vary depending on which features and sinks you want to use. For a basic console and configuration-based setup, install the core Serilog package and the ASP.NET Core integration packages.
dotnet add package Serilog.AspNetCore dotnet add package Serilog.Settings.Configuration dotnet add package Serilog.Sinks.Console dotnet add package Serilog.Sinks.File
The Serilog.AspNetCore package provides integration with ASP.NET Core’s logging system. The configuration package allows settings to be loaded from configuration files, while the Console and File packages provide common logging destinations.
Configure Serilog in Program.cs
In a modern ASP.NET Core application, Serilog can be configured at application startup. The following example creates a logger and connects it to the ASP.NET Core host.
using Serilog;
var builder = WebApplication.CreateBuilder(args);
Log.Logger = new LoggerConfiguration()
.WriteTo.Console()
.CreateLogger();
builder.Host.UseSerilog();
builder.Services.AddControllers();
var app = builder.Build();
app.MapControllers();
app.Run();
The UseSerilog method tells ASP.NET Core to use Serilog as the logging provider. Once configured, application components that use ILogger can write through the Serilog pipeline.
Configure Serilog Using appsettings.json
For production applications, keeping logging configuration inside appsettings.json can be more convenient than hard-coding every logging option in Program.cs. It also allows logging behavior to be changed without modifying application source code.
{
"Serilog": {
"Using": [
"Serilog.Sinks.Console",
"Serilog.Sinks.File"
],
"MinimumLevel": "Information",
"WriteTo": [
{
"Name": "Console"
},
{
"Name": "File",
"Args": {
"path": "logs/application-.log",
"rollingInterval": "Day"
}
}
]
}
}
The configuration above writes Information-level and higher events to the configured destinations. The rollingInterval setting creates separate log files according to the selected time period, which helps prevent a single log file from becoming unnecessarily large.
Understanding Serilog Log Levels
Log levels help developers control the amount of information generated by an application. Choosing an appropriate minimum level is important because excessive logging can increase storage requirements and make important events harder to identify.
- Verbose: Extremely detailed diagnostic information.
- Debug: Information useful during development and troubleshooting.
- Information: Normal application activity and important business events.
- Warning: Unexpected situations that do not necessarily stop execution.
- Error: Errors that affect an operation but may not terminate the application.
- Fatal: Critical failures that may prevent the application from continuing.
For production environments, Information is often a practical starting point, while Debug and Verbose logging can be enabled selectively when deeper investigation is required.
Writing Logs with ILogger
ASP.NET Core applications commonly use the ILogger abstraction inside controllers, services, middleware, and background processes. This keeps application code independent of the specific logging implementation.
public class ProductService
{
private readonly ILogger<ProductService> _logger;
public ProductService(ILogger<ProductService> logger)
{
_logger = logger;
}
public void ProcessProduct(int productId)
{
_logger.LogInformation(
"Processing product {ProductId}",
productId);
}
}
Using ILogger is generally preferable to directly calling a static logging API throughout the application because dependency injection makes the component easier to test and keeps the logging abstraction consistent.
Logging Exceptions with Serilog
Exception logging is one of the most important uses of Serilog. When an exception occurs, the complete exception object should normally be supplied to the logging method rather than converting it into a simple string. This allows the logger to preserve useful exception information such as the message and stack trace.
try
{
ProcessOrder();
}
catch (Exception ex)
{
_logger.LogError(
ex,
"Error occurred while processing order {OrderId}",
orderId);
}
The exception should be logged internally while the API should return an appropriate response to the client. Production applications should avoid exposing stack traces, database details, connection strings, or internal implementation information through HTTP responses.
Serilog with Global Exception Handling
Centralized exception handling works particularly well with structured logging. Instead of adding try-catch blocks to every controller action, an application can use exception-handling middleware to capture unexpected exceptions in one place and log them consistently.
This approach also separates two responsibilities: the application logs detailed diagnostic information for developers and administrators, while the client receives a safe and standardized error response. For a deeper explanation of this architecture, see our Exception Handling in ASP.NET Core guide.
Logging HTTP Requests
Web applications often need information about incoming HTTP requests, response status codes, execution time, and other request-related details. Serilog.AspNetCore provides request logging capabilities that can generate a structured event for each HTTP request.
app.UseSerilogRequestLogging();
Request logging can provide valuable information when diagnosing slow endpoints or unexpected status codes. Instead of manually adding logging statements to every controller, request-level logging gives developers a consistent view of application traffic.
Using File Sinks for Application Logs
File logging is useful for applications where local diagnostic files are required, particularly during development, testing, or in environments where centralized logging has not yet been introduced. Serilog’s file sink supports rolling files so that logs can be separated by day or another configured interval.
Log.Logger = new LoggerConfiguration()
.WriteTo.File(
"logs/application-.log",
rollingInterval: RollingInterval.Day)
.CreateLogger();
Developers should monitor the size and retention of log files. Production servers can eventually run out of disk space if old log files are never removed. A suitable retention strategy should therefore be part of the deployment design.
Adding Context to Logs
One major advantage of structured logging is the ability to attach contextual information to events. Examples include correlation IDs, customer IDs, request IDs, environment names, and service names.
Log.Information(
"Payment completed for customer {CustomerId}",
customerId);
Context becomes especially important in distributed systems. When a request travels through multiple APIs or services, a shared correlation identifier can help developers follow the complete transaction across different application components.
Serilog and Dependency Injection
Serilog works naturally with the ASP.NET Core dependency injection model through Microsoft.Extensions.Logging. Services can request ILogger through their constructors without knowing whether the underlying provider is Serilog or another logging implementation.
This design keeps business logic clean and makes it easier to replace or modify logging infrastructure later. Developers working with dependency injection can also use logging as part of the same application architecture instead of creating logger instances manually inside every class. You can learn more about this design approach in our Dependency Injection in ASP.NET Core article.
Serilog for ASP.NET Core Web APIs
Serilog is particularly useful for REST APIs because API applications generate many requests that need to be diagnosed independently. Logging request information, response status codes, validation failures, authentication problems, and unexpected exceptions can significantly reduce troubleshooting time.
For applications using JWT authentication, logs can also help administrators understand authentication failures without exposing sensitive token contents. Never log passwords, access tokens, API secrets, connection strings, or other credentials. For related authentication concepts, see our JWT Authentication in ASP.NET Core guide.
Serilog Best Practices for Production
Production logging should be designed carefully. Logging every possible value may appear useful during development, but excessive logging can create performance, storage, privacy, and operational problems.
- Use structured properties instead of manually concatenating values.
- Choose an appropriate minimum log level for production.
- Do not log passwords, tokens, secrets, or sensitive personal information.
- Use centralized logging when multiple application instances are involved.
- Configure file retention when using local file sinks.
- Include useful identifiers such as request or correlation IDs.
- Log exceptions with the complete exception object.
- Avoid logging the same exception repeatedly at multiple application layers.
- Monitor log volume and storage consumption.
- Use different configuration settings for development, staging, and production.
Serilog vs Built-in ASP.NET Core Logging
The built-in ASP.NET Core logging framework provides an excellent abstraction and supports multiple providers. Serilog does not necessarily replace that abstraction; instead, it can act as the logging provider behind it while adding structured logging capabilities and a broad ecosystem of sinks and enrichers.
For a small application, the built-in logging providers may be sufficient. For enterprise applications that require advanced structured events, flexible destinations, custom enrichment, and detailed filtering, Serilog can provide additional capabilities without forcing application code to abandon ILogger.
Serilog and Application Monitoring
Logging should not be treated as a replacement for monitoring. Logs explain what happened, while monitoring and observability systems can help identify trends such as increasing response times, high error rates, resource consumption, and service availability problems.
A mature production environment can therefore combine structured Serilog events with centralized log storage, dashboards, alerts, metrics, and distributed tracing. This provides a more complete picture of application health and makes production incidents easier to investigate.
Common Serilog Mistakes to Avoid
- Writing every message at Error level.
- Logging sensitive information.
- Creating huge unstructured log messages.
- Ignoring log file retention.
- Using Debug or Verbose logging everywhere in production.
- Logging the same exception repeatedly.
- Returning internal exception details to API clients.
- Failing to include useful contextual properties.
- Hard-coding configuration that should be environment-specific.
Useful Serilog Resources
For the latest package information, configuration options, sinks, integrations, and official project documentation, developers should refer to the official Serilog website.
You can also continue learning about application logging through our Logging in ASP.NET Core guide, which covers the broader logging architecture and monitoring concepts used in ASP.NET Core applications.
Conclusion
Serilog in .NET provides a practical and flexible approach to structured application logging. Its integration with ASP.NET Core allows developers to keep using ILogger while gaining additional control over log destinations, structured properties, filtering, request logging, and production diagnostics. A well-designed Serilog configuration can make application problems easier to reproduce, investigate, and resolve, especially when an application handles many requests or runs across multiple services. The most important principle is to treat logging as part of the application’s architecture rather than simply adding messages whenever an error occurs. Use meaningful log levels, structured properties, centralized exception handling, secure configuration, and appropriate retention policies. When combined with monitoring and observability practices, Serilog can become an important part of building reliable and maintainable .NET applications.
[…] Avoid logging large objects or sensitive information on every request. For a deeper discussion of structured logging, see Serilog in .NET. […]