C# – Serilog

By | 24/01/2024

In this post, we will see how to use Serilog in our .net applications.
But first of all, what is Serilog?
Serilog is a diagnostic logging library for .NET applications. It is designed to be easy to configure and extend, offering a rich set of sinks (outputs) and enrichers. One of the key features of Serilog is its ability to log structured data, which allows for more meaningful and queryable logs.
For all information, we can see the official web site.

To get started with Serilog, we first need to install the Serilog NuGet package along with the necessary sinks. For example, to log messages to the console and a file, we have to install Serilog.Sinks.Console and Serilog.Sinks.File:

Serilog installation

Now, we will see two examples to better understand how to use it.

Example 1:
A basic example of configuring and using Serilog in a .NET console application.
The log output is configured to be written to both the console and a file.
The file logging is set to roll over daily, which means it will create a new log file each day

using Serilog;
    
// Configure Serilog logger
Log.Logger = new LoggerConfiguration()
    .MinimumLevel.Debug() // Set the minimum log level to Debug
    .WriteTo.Console() // Output logs to the console
    .WriteTo.File("logs/myapp.txt", rollingInterval: RollingInterval.Day) // Output logs to a file with daily rolling
    .CreateLogger(); // Create the logger with the above configuration

// Write an informational log
Log.Information("Hello, Serilog!");

// Write a warning log
Log.Warning("Warning: Sample warning message.");

try
{
    // Simulate an error by throwing an exception
    throw new InvalidOperationException("Exception example");
}
catch (Exception ex)
{
    // Log the exception details
    Log.Error(ex, "An error occurred");
}

// Ensure all logs are flushed to their sinks and close the logger
Log.CloseAndFlush();


If we run then application, the following will be the result:

Serilog example 2

Instead, in the folder “\bin\Debug\net7.0\logs”, we will find the file log called (in this case) myapp20240117.txt:

2024-01-17 18:24:20.313 +01:00 [INF] Hello, Serilog!
2024-01-17 18:24:20.368 +01:00 [WRN] Warning: Sample warning message.
2024-01-17 18:24:20.371 +01:00 [ERR] An error occurred
System.InvalidOperationException: Exception example
   at Program.<Main>$(String[] args) in C:\Users\Commander\Desktop\Project_net\SerilogPost\Program.cs:line 19



Example 2:
In this example, the Serilog logger is configured with enrichers to add machine name to each log entry. The program demonstrates structured logging by logging an order’s details and simulating asynchronous operations, each with its own contextual information added to the log (in this case, the operation name). The use of “LogContext.PushProperty” allows for temporarily adding extra information to the log context, which is useful for tracing and debugging.
It is important to highlight that, in order to get the MachineName, we have to add the Serilog.Enrichers library as well.

using Serilog;
using Serilog.Context;
using Serilog.Enrichers;
using System;
using System.Threading;
using System.Threading.Tasks;
    
// Configure the Serilog logger
Log.Logger = new LoggerConfiguration()
    .MinimumLevel.Debug() // Set minimum log level to Debug
    .Enrich.WithMachineName() // Enrich logs with the name of the machine
    .WriteTo.Console(outputTemplate: 
        "[{Timestamp:HH:mm:ss} {Level:u3}] {MachineName} {Message:lj}{NewLine}{Exception}") // Format logs for the console with timestamp, level, machine name, message, and exceptions
    .WriteTo.File("logs/structured-log.txt", 
        outputTemplate: "[{Timestamp:HH:mm:ss} {Level:u3}] {MachineName} {Message:lj}{NewLine}{Exception}",
        rollingInterval: RollingInterval.Day) // Format logs for the console with timestamp, level, machine name, message, and exceptions
    .CreateLogger(); // Create the logger

// Log application start information
Log.Information("Application Starting Up");

// Log using structured data
var orderId = 12345;
var orderAmount = 99.50m;
Log.Information("Order {OrderId} created with amount {OrderAmount}", orderId, orderAmount);

// Execute async operations with enriched log context
await Task.Run(() => SimulateOperation("Operation1"));
await Task.Run(() => SimulateOperation("Operation2"));

// Ensure all logs are flushed and close the logger
Log.CloseAndFlush();


static void SimulateOperation(string operationName)
{
    // Push a property to the log context, which will be included in logs within this scope
    using (LogContext.PushProperty("Operation", operationName))
    {
        // Log the start of an operation
        Log.Information("Starting operation {OperationName}", operationName);

        // Simulate some operation
        Thread.Sleep(1000);

        // Log the completion of an operation
        Log.Information("Completed operation {OperationName}", operationName);
    }
}


If we run then application, the following will be the result:

Serilog example 2

Instead, in the folder “\bin\Debug\net7.0\logs”, we will find the file log called (in this case) structured-log20240117.txt:

[19:05:42 INF] DESKTOP-376N87T Application Starting Up
[19:05:42 INF] DESKTOP-376N87T Order 12345 created with amount 99.50
[19:05:42 INF] DESKTOP-376N87T Starting operation Operation1
[19:05:43 INF] DESKTOP-376N87T Completed operation Operation1
[19:05:43 INF] DESKTOP-376N87T Starting operation Operation2
[19:05:44 INF] DESKTOP-376N87T Completed operation Operation2


In conclusion, Serilog offers a robust and versatile logging solution for .NET applications, striking an excellent balance between ease of use and powerful features. As we’ve seen through these examples, it not only simplifies the process of implementing logging but also elevates it by allowing for structured logging, log enrichment, and flexible output configurations.


Category: C# Tags:

Leave a Reply

Your email address will not be published. Required fields are marked *