Application Insights and Serilog in .NET 8 Worker Services with HostApplicationBuilder
Since .NET 8, the template of Worker Services has changed from using IHostBuilder
to HostApplicationBuilder
.
.NET 7
IHost host = Host.CreateDefaultBuilder(args)
.ConfigureServices(services =>
{
services.AddHostedService<Worker>();
})
.Build();
host.Run();
.NET 8
var builder = Host.CreateApplicationBuilder(args);
builder.Services.AddHostedService<Worker>();
var host = builder.Build();
host.Run();
As a result, the way to implement Application Insights and Serilog in Worker Service has changed a bit and I am going to go through it.
NuGet packages
These are the packages you need. You may want to add extra packages based on your need, such as different sinks (likely Serilog.Sinks.Console
) or enrichers (eg. Serilog.Enrichers.Environment
).
- Microsoft.ApplicationInsights.WorkerService
- Serilog
- Serilog.Extensions.Hosting
- Serilog.Settings.Configuration
- Serilog.Sinks.ApplicationInsights
appsettings.json
This is the appsettings.json you need. Substitute you Application Insights connection string and application name. Play around with the minimum log level if you want to. Note that Serilog does not read configuration from Logging
so you can remove it.
{
"ApplicationInsights": {
"ConnectionString": "<YOUR_CONNECTION_STRING>"
},
"Serilog": {
"MinimumLevel": {
"Default": "Information",
"Override": {
"Microsoft": "Warning"
}
},
"Properties": {
"ApplicationName": "My Worker Service App"
}
}
}
Program.cs
In Program.cs
, you need to add builder.Services.AddApplicationInsightsTelemetryWorkerService();
to register Application Insights telemetry. This read ConnectionString
from appsettings.json
to connect to Application Insights so make sure that is correct. This inject TelemetryConfiguration
, which will be used by Serilog to send log to Application Insights. It also inject TelemetryClient
, which you can use to send telemetry, but we are not using it in this example.
The next thing you need to add is builder.Services.AddSerilog()
. The line configuration.ReadFrom.Configuration(builder.Configuration);
loads your Serilog configuration from appsetting.json. The sample I am showing configure the sink to Application Insights in code but you can also set that up in appsetting.json, which you can easily find tutorial online on how to do it so I am not showing it here. The reason I am doing it in code is because the actual code I wrote has a logic to only send log to Application Insights in release mode and sink to console if in debug mode.
using Microsoft.ApplicationInsights.Extensibility;
using Serilog;
using MyWorkerService;
var builder = Host.CreateApplicationBuilder(args);
builder.Services.AddHostedService<Worker>();
builder.Services.AddApplicationInsightsTelemetryWorkerService();
builder.Services.AddSerilog((serviceProvider, configuration) =>
{
configuration.ReadFrom.Configuration(builder.Configuration);
configuration.WriteTo.ApplicationInsights(
serviceProvider.GetRequiredService<TelemetryConfiguration>(),
TelemetryConverter.Traces);
});
var host = builder.Build();
host.Run();
Worker.cs or any classes
This is the easy part. You just need to dependency inject ILogger<Worker>
or ILogger<T>
in any class you want to log and log away! I actually did not modify one bit from the Worker Services template so there you go.
namespace MyWorkerService
{
public class Worker : BackgroundService
{
private readonly ILogger<Worker> _logger;
public Worker(ILogger<Worker> logger)
{
_logger = logger;
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
while (!stoppingToken.IsCancellationRequested)
{
if (_logger.IsEnabled(LogLevel.Information))
{
_logger.LogInformation("Worker running at: {time}", DateTimeOffset.Now);
}
await Task.Delay(1000, stoppingToken);
}
}
}
}