Structured Logging with Serilog in ASP.NET WEB API
WebAPI
19 Articles
In this article, let's learn about how to do Structured Logging
of errors using
Serilog
in 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
- Introduction
- Why Structured Logging ?
- Write to Sink
- Implementing Logging with Serilog
- Enriching Logs with additional information
- Log Scope using Serilog
- Advantages
- Summary
Introduction
Logging
is needed in all applications. This will help to find root cause or track user activity in any
environment. 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
has many 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 ?
Traditional plain-text
logs can be hard to read and analyze. Structured logging
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
A 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 consoleFile
- To log to fileSeq
- To log to Seq (useful in docker based development)Application Insights
- To log to Azure Application InsightsDatabase
- To log to databaseLog 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.
Install the
Serilog.AspNetCore
Nuget Packages.The next step is to pass
Configuration
to and use it to create Serilog Logger. These can be done programmatically or usingappsettings.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
File
sink.The next step is to create log configuration using above configuration and use it to create
Serilog logger
as shown below.Code Sample - Use Configuration and Create logger
Finally
UseSerilog()
in app to replace default Logger in .NETCode 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 enrichers
are
packages that add properties
to log events. Enrichers are a great way to add context
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 machine name
, process id
,
thread id
, 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 logsSerilog.Enrichers.Process
- To add / enrich with process id in logsSerilog.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 MachineName
,
ProcessId
, ThreadId
, Environment
and ApplicationName
.
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
with 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.
Advantages
The advantages of using Serilog are,
Structured Logging
- Simple JSON structure for all log eventsMultiple Sinks
- Can write / output to multiple sinksEnrichers
- Can enrich logs with additional informationScopes
- Can enrich logs with additional information for a particular scopeEasy to use
- Very easy to use and configureImproved Searching and readbility
- This is more powerful when linked with Seq or Elastic SearchImproved Analytics
- Because of the structured nature easy to get analytics
Summary
In this article, we learnt about how to do structured logging
using SeriLog
in ASP.NET Core. We learnt about Sinks
and 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.