In this article, let's learn about how to do
Structured Logging of errors using
Web API in ASP.NET Core.
Note: If you have not done so already, I recommend you read the article on Global Exception Handling in ASP.NET WEB API.
Table of Contents
- Why Structured Logging ?
- Write to Sink
- Implementing Logging with Serilog
- Enriching Logs with additional information
- Log Scope using Serilog
Logging is needed in all applications. This will help to find root cause or track user activity in any
By default logging is baked into ASP.NET Core. It is very easy to use and logs are stored in
plain text format. This will be difficult to read and analyse.
Serilog is a popular
structured logging library for .NET applications.
It is very easy to use and configure. It has many
sinks available to store the logs in different places. It
enrichers available to enrich the logs with additional information. It also supports
scoping logs events to enrich logs for a particular scope.
This is the
second thing that I do when I create new Web API Projects or when I work on existing code base.
Let's focus on how to implement
structured logging in ASP.NET Web API.
Why Structured Logging ?
plain-text logs can be hard to read and analyze.
is a practice where you apply the same message format
(JSON Structure) to all of your application logs. The end
result is that all your logs will have a similar structure, allowing them to be easily searched and analyzed.
Write to Sink
Sink in Serilog is a destination where your log events are sent. There are sinks for various outputs like the
console, files, databases, and even other logging platforms like Seq, which we'll explore in more detail.
The most commonly used Sinks are,
Console- To log to console
File- To log to file
Seq- To log to Seq (useful in docker based development)
Application Insights- To log to Azure Application Insights
Database- To log to database
Log Group- To log to AWS cloud watch log groups
Implementing Logging with Serilog
Let's see how to implement
structured logging with Serilog in ASP.NET Web API.
The next step is to pass
Configurationto and use it to create Serilog Logger. These can be done programmatically or using
appsettings.json. I prefer appsettings.json as it gives more flexibility.
Code Sample - App Settings for Serilog in ASP.NET Core
The above configuration will create a Serilog logger with
The next step is to create log configuration using above configuration and use it to create
Serilog loggeras shown below.
Code Sample - Use Configuration and Create logger
UseSerilog()in app to replace default Logger in .NET
Code Sample - Use Serilog as default logger
Enriching Logs with additional information
So far so good. But wouldn't it be nice if we can add extra information to our logs?? Serilog
add properties to log events. Enrichers are a great way to
to your logs. For example, you can add properties that contain the current user's ID, the current request path, or the current machine name.
Most commonly used enrichers are
environment, etc. Let's see how to add these enrichers to Serilog.
Install the following Nuget Packages.
Serilog.Enrichers.Environment- To add / enrich with app environment in logs
Serilog.Enrichers.Process- To add / enrich with process id in logs
Serilog.Enrichers.Thread- To add / enrich with thread id in logs
Update the Serilog logger configuration to enrich log events with these properties.
Code Sample - Enriching logs with additional details
From the above code snippet, you can see that we are enriching the log events with
Log Scope using Serilog
Now what if we want to add some properties to all the logs events in a request in a single place?? Serilog supports logging
scopes. Scopes are a way to add properties to log events that are in effect for a limited period of time.
Scopes provide a global way to add properties to all log events in a particular request. For example, you can add a scope for a particular request
User ID or a
Tenant ID. All log events within that scope will have the
User ID or Tenant ID property in log output.
Code Sample - Configuration to enrich log with scopes
To do that we need to enrich the configuration with
FromLogContext() as shown above.
Note: If you have not done so already, I recommend you read the article on Introducing Middleware in ASP.NET.
Now we need to create a Middleware to do the actual work of adding the scope. Let's create a middleware called
LogScopeMiddleware and use it in
request pipeline. This will add the
scope to all the log events in a request.
Code Sample - Log Scope Middleware to enrich all logs in a request
That's it now all you need to do is to inject
ILogger<T> in your apps and start logging.
The advantages of using Serilog are,
Structured Logging- Simple JSON structure for all log events
Multiple Sinks- Can write / output to multiple sinks
Enrichers- Can enrich logs with additional information
Scopes- Can enrich logs with additional information for a particular scope
Easy to use- Very easy to use and configure
Improved Searching and readbility- This is more powerful when linked with Seq or Elastic Search
Improved Analytics- Because of the structured nature easy to get analytics
In this article, we learnt about how to do
structured logging using
in ASP.NET Core. We learnt about
Enrichers. We also learnt about
how to use Serilog
Scopes to enrich logs for a particular request. We also learnt about the advantages of using
Serilog. I hope you enjoyed reading it.