Logging in .NET 8 with Serilog and Seq
Tags: aspnet, serilog, seq, logging
Published: 2024-04-06 12:56:33

## Introduction
When developing locally, we can easily use breakpoints and debugging to inspect our code and see how it behaves. This is not possible when we deploy the application to another environment, say staging or production. When we don't have access to debug locally, we can depend on logs.
Logging is a means by which we keep track of what happens in our applications. We can write logs for informational purposes, or to trace errors in our application.

## Logging with Serilog
Serilog is a simple-to-use diagnostic logging library for .NET applications. It runs on all recent .NET versions and can be configured to log to files, the console, and other external providers.

## Installing and Configuring Serilog
We can install Serilog via the command line or the NuGet package manager.

```
dotnet add package Serilog
```
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/znc4zw8b0q3eo0nwxl6o.png)
Once installed, we can setup Serilog at application startup, typically in the program.cs, using the Serilog.Log static class:

```
using Serilog;

Log.Logger = new LoggerConfiguration()
    .CreateLogger();
```
Our configured logger currently does not log to any location. To see our logs we have to configure sinks. Let's see what sinks are.

##Serilog Sinks
Serilog uses sinks to record events to an external representation. When configuring Serilog, we have to specify our desired sinks, if not our events do not get logged anywhere. Serilog sinks are distributed via NuGet. Examples of available sinks include the Console sink, which prints the log data to the console, and the File sink, which writes log events to a file. We can also add these to our application via the command line or NuGet package manager.

```
dotnet add package Serilog.Sinks.Console
dotnet add package Serilog.Sinks.File
```
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/epbenevdtuu9u88u8zpf.png)
We can now configure our logger to write to the desired sinks:

```
Log.Logger = new LoggerConfiguration()
    .WriteTo.Console()
    .WriteTo.File("log.txt",
        rollingInterval: RollingInterval.Day)
    .CreateLogger();
```
WriteTo.Console() specifies that log events should be written to the console.
To use WriteTo.File(), we have to specify the location of the log file. We can also provide some additional parameters like the rollingInterval. Here, we are specifying that a new log file will be created each day.

## Minimum Level
Serilog provides six log levels:
**Verbose**: This is the noisiest level, and logs all trace events. This level is not commonly enabled in production environments.
**Debug**: This level is used to log the application's internal events that are not necessarily observable from outside.
**Information**: This level is used to log information about the normal application processes.
**Warning**: This level is used to log warnings about events that are outside of the application's normal behavior.
**Error**: This is used to log events of broken functionalities in the application. This requires immediate attention.
**Fatal**: This is the most critical level. It is used for logging events which can cause the application to crash. Fatal events also require immediate attention.

We can specify the minimum level at which we want to capture events while configuring our logger.
```
Log.Logger = new LoggerConfiguration()
    .MinimumLevel.Information()
    .WriteTo.Console()
    .WriteTo.File("log.txt",
        rollingInterval: RollingInterval.Day,
        rollOnFileSizeLimit: true)
    .CreateLogger();
```
If not specified, Serilog uses Information as the minimum level by default.

We can write log events by using methods of the Log class that match the event level. For example we can write a warning event like this:

```
Log.Warning("Unable to load some services");
```

##Using the Logger in Application Classes
The easiest way to use the logger in our application classes is via the global Log class. For example:

```
[Route("api/[controller]")]
[ApiController]
public class TestController : ControllerBase
{ 
    [HttpPost("test-logger")]
    public IActionResult TestLogger()
    {
        Log.Information("This log is from the global Log class");
        return Ok();
    }
}
```
When we run our application and call the test-logger endpoint, we see this in the console:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/888dbsnsa0ond7xnga9s.png)

Another way we can make use of the logger is by injecting it into the class as an ILogger. We first have to configure Serilog as our logging provider. To do this we have to install the Serilog.AspNetCore NuGet package.

```
dotnet add package Serilog.AspNetCore
```
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/99rzmplwlhlu5q2uyvcm.png)
NOTE: Serilog.AspNetCore has Serilog and a few sinks as dependencies. So when you install Serilog.AspNetCore, you don't have to install Serilog, Serilog.Sinks.Console and Serilog.Sinks.File.

After installing the package, we can call UseSerilog() on the Host object of the application builder in our program.cs to configure Serilog as our logging provider and pass in the log object:

```
builder.Host.UseSerilog(Log.Logger);
```
We can now make use of the logger in our application class by injecting the ILogger interface in the constructor:
```
[Route("api/[controller]")]
[ApiController]
public class TestController : ControllerBase
{ 
    private readonly ILogger<TestController> _logger;

    public TestController(ILogger<TestController> logger)
    {
        _logger = logger;
    }

    [HttpPost("test-logger")]
    public IActionResult TestLogger()
    {
        _logger.Information("This log is from the injected ILogger");
        return Ok();
    }
}
```
When we run our application and call the test-logger endpoint, we see this in the console:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qvoausgxqxi3cnk1kt2z.png)



##Writing Logs to Seq
Seq is a self-hosted search and analysis server for structured logs. Events are captured as fully structured JSON data and Seq makes it easy to search and filter through with various parameters. This provides a more efficient way to access and make sense of our logs than writing to files.
Seq can be installed on your local machine or on a Windows or Linux server.

##Installing Seq Locally
You can download Seq .msi from https://datalust.co/download, and follow the default installation guide to install it on your local machine.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mrf6760u08awf6c83zox.png)

You can choose to start the Seq service once the installer has finished copying the files. This will open the Seq Service Administration dialog for the initial setup. You will be prompted to provide the desired location to store Seq's data files and a URL to host Seq's user interface and HTTP API. You can leave these as the defaults. You can also optionally set an administrator username and password.
When you're done with the setup you can open the Seq UI by visiting the default URL, http://localhost:5341, or the one you configured.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bcuuak7hpk6v0p2a5pdy.png)

After logging in you can access the Seq UI
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ld5f0o4fe90magq15z0c.png)

We are now ready to configure our logger to write to Seq. To do this we have to install the Seq sink.

```
dotnet add package Serilog.Sinks.Seq
```
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hnpskd0mejm6mnow9cac.png)

In our logger configuration we can now write to Seq and provide the Seq URL:
```
Log.Logger = new LoggerConfiguration()
    .MinimumLevel.Information()
    .WriteTo.Seq("http://localhost:5341")
    .CreateLogger();

Log.Information("Starting up application");
```
Let us check the Seq UI again to see if our informational log appears:
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yvhej2f2ahjra552q3b9.png)

##Conclusion
Logging is an important part of our applications. It can save time in figuring out production issues and also provide necessary information when monitoring. We have seen how to combine Serilog logging with a powerful search and analysis server like Seq.
You can get the sample code for this tutorial [here](https://github.com/ChinonsoIke/SerilogTutorial).

To learn more about Serilog, you can visit the documentation on their [GitHub project](https://github.com/serilog/serilog/wiki/Getting-Started).
To learn more about Seq, you can visit the documentation on their [website](https://docs.datalust.co/docs/an-overview-of-seq).