Serilog in Net6 Console App

MyHumbleCoder
4 min readJun 28, 2023

--

I really enjoy building new stupid projects and this one is quite fun, and I am basing this article off this article: https://dev.to/moe23/net-5-console-app-with-dependency-injection-serilog-logging-and-appsettings-3d4n

My daily coding vitamin is writing a simple program that does one thing, and for this one thing today I am intrigued with the idea of creating a console application utilizing Serilog. I found an article on a Net5 console application implementing Serilog, so I just smashed that into Net6.

Attention: I am not original in anything technology wise, I am a learner.

Let’s begin by make a space and project:

mkdir SerilogInAConsoleApp
cd SerilogInAConsoleApp
dotnet new console --name SerilogInAConsoleApp

Run the base application, and if all is well… great job! You are a software developer ;)

As you’ll find, a console application does not come out of the box with any Inversion Of Control (IOC) capabilities for Dependency Injection (DI). So, that’s terrible and you should quit now. Just delete everything you built thus far and return to university to become an accountant.

Still there? Alright, cool, we can incorporate anything we need for making our application and IOC capable, just don’t tell the folks that left.

To make our application IOC capable we will need to install a few Nuget Packages:

dotnet add package Microsost.Extensions.Hosting
dotnet add package Serilog.AspNetCore

Serilog has the concept of using sinks, which enables easily integrating with various platforms; e.g., GCP, AWS, SEQ. For our code base we will only be using console sink and file sink, which happen to be included within the Serilog.AspNetCore package.

Awesome sauce! Let’s bootstrap a little hosting in our application and get things rolling. We will rely on the builder pattern, which means we will take a ConfigurationBuilder object, and slap everything we need inside of it for creating a beautiful IOC for implementing DI. Inside of our Program class we will add the following method, AppStartup.

static IHost AppStartup() {
var builder = new ConfigurationBuilder();
// incorporate our appsettings.json
builder.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
.AddEnvironmentVariables();

var host = Host.CreateDefaultBuilder()
.ConfigureServices((context, services) => {
// here we can build our services...
})
.Build();

return host;
}

Now, our Program class should call our new static method.

static IHost AppStartup() {
var builder = new ConfigurationBuilder();

builder.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
.AddEnvironmentVariables();

// now we can setup serilog, reads from appsettings, and creates logger
Log.Logger = new LoggerConfiguration()
.ReadFrom.Configuration(builder.Build())
.WriteTo.Console()
.CreateLogger();

Log.Logger.Information("starting serilog in a console app...");

var host = Host.CreateDefaultBuilder()
.ConfigureServices((context, services) => {
// here we can build our services...
})
.UseSerilog()
.Build();

return host;
}

var host = AppStartup();

We have our IOC capable console application, and its ready for instantiating Serilog and injecting Serilog as its logging provider, but before we do that, lets make a service to use the logger. Create an interface and its implementation called, MyConfigReader.

public interface IMyConfigReader
{
void ReadConfig();
}
public class MyConfigReader: IMyConfigReader
{
private readonly IConfiguration _configuration;
private readonly ILogger<MyConfigReader> _logger;

public MyConfigReader(IConfiguration configuration, ILogger<MyConfigReader> logger)
{
_configuration = configuration ?? throw new ArgumentNullException(nameof(configuration));
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
}
public void ReadConfig()
{
var configValue = _configuration["MyConfigValue:ValueToBeRead"];
_logger.LogInformation($"value from appsettings: {configValue}");
}
}

We are making good time here. Since we created our interface and implementation we need to add it into our IOC services. Let’s add it as a singleton.


static IHost AppStartup() {
var builder = new ConfigurationBuilder();

builder.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
.AddEnvironmentVariables();



var host = Host.CreateDefaultBuilder()
.ConfigureServices((context, services) => {
// here we can build our services...
services.AddSingleton<IMyConfigReader, MyConfigReader>();
})
.Build();

return host;
}


var host = AppStartup();

var service = ActivatorUtilities.CreateInstance<MyConfigReader>(host.Services);

service.Connect();

Great job. As of now we are using Microsoft’s logging provider, and all we need to do is tell our Program’s host to use Serilog instead, so we will use a new Serilog logger to read from the configuration file, and inject it within the host, but first lets change the appsettings.json file.

{
"Serilog": {
"MinimalLevel": {
"Default": "Information",
"Override": {
"Microsoft": "Information",
"System": "Warning"
}
}
},
"MyConfigValue": {
"ValueToBeRead": "This is my VALUE yall"
}
}

In this configuration you’ll notice the log level is set to information within Serilog, it will incorporate Microsoft at the information level, and System logs will be set to warning level.

With Serilog setup in our configuration file we can import our packages for use within our Program class host. Again, we will instantiate a new logger which reads from the configuration, and tell the host to use Serilog. Our final Program class will be as such.

// See https://aka.ms/new-console-template for more information
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Serilog;
using SerilogInAConsoleApp;


static IHost AppStartup() {
var builder = new ConfigurationBuilder();

builder.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
.AddEnvironmentVariables();


Log.Logger = new LoggerConfiguration()
.ReadFrom.Configuration(builder.Build())
.WriteTo.Console()
.CreateLogger();

Log.Logger.Information("starting serilog in a console app...");

var host = Host.CreateDefaultBuilder()
.ConfigureServices((context, services) => {
// here we can build our services...
services.AddSingleton<IDataService, DataService>();
})
.UseSerilog()
.Build();

return host;
}

// now I made a small service that pulls from config, and uses serilog as the logger implemented using DI, now setup services and call appstartup.

var host = AppStartup();

var service = ActivatorUtilities.CreateInstance<DataService>(host.Services);

service.Connect();

Run it, and see your achievement!

output window after running program

--

--

MyHumbleCoder
MyHumbleCoder

Written by MyHumbleCoder

Developer, passionate about web developement and coding standards. Creative, Reliable and Capable.

Responses (1)