Skip to main content
Version: v3.0.0

Using Arcus & Serilog in ASP.NET Core

The Arcus Application Insights Serilog sink is a great way to simplify telemetry tracking and application logging. Unlike Microsoft's TelemetryClient for telemetry tracking, Arcus uses the common ILogger infrastructure to track and link telemetry in Application Insights.

This user guide will walk through the steps to configure the Arcus Application Insights Serilog sink in ASP.NET Core applications.


The example in this user guide uses following packages.

PM > Install-Package -Name Serilog.AspNetCore
PM > Install-Package -Name Arcus.Observability.Telemetry.Serilog.Sinks.ApplicationInsights
PM > Install-Package -Name Arcus.Security.Providers.AzureKeyVault
PM > Install-Package -Name Arcus.WebApi.Logging


Since Arcus uses Serilog, we expect you to setup Serilog as your logging infrastructure. This is also Microsoft's recommended logging system (more info).


The Arcus Application Insights Serilog sink builds on top of Serilog and acts as a bridge between the common ILogger infrastructure and the Application Insights telemetry.


It is recommended to configure the Arcus Application Insights Serilog sink with the Application Insights connection string. This connection string should be safely stored. This example uses the Arcus secret store with Azure Key Vault integration (more info).


As this user guide shows how a fully working API application is set up for Application Insights tracking, we will also use Arcus.WebApi.Logging. The Arcus WebApi library builds on top of Arcus Observability, specific for API applications. This will make sure that the application correlation is stored in the HTTP context during send/receive operations (more info).

Setting up Serilog with Arcus

The following shows a complete code sample of how Arcus and Serilog are configured together. Each critical point is explained afterwards. In short, what's happening is that Serilog is first configured as a basic debug logger so that startup failures are logged to the console (1). After the application is build, the 'real' Serilog setup is configured that uses the Arcus Application Insights Serilog sink (6) with the connection string that is stored in the Arcus secret store (3).

using Microsoft.AspNetCore.Builder;
using Microsoft.DependencyInjection.Extensions;
using Serilog;
using Serilog.Configuration;

public class Program
public static async Task<int> Main(string[] args)
// 1. Configure startup Serilog logger.
Log.Logger = new LoggerConfiguration()

WebApplicationBuilder builder = WebApplication.CreateBuilder(args);
// 2. Register the HTTP correlation services to access the current correlation information during the HTTP request processing.

// 3. Configure Arcus secret store with Application Insights connection string (more info on secret store:
builder.Host.ConfigureSecretStore((context, stores) => stores.AddAzureKeyVaultWithManagedServiceIdentity(...));

// 4. Use Serilog's static Logger as application logger.

WebApplication app = builder.Build();
// 5. Use the Arcus HTTP correlation middleware to set the correlation information on received HTTP requests.
app.UseEndpoints(endpoints => endpoints.MapControllers());

await ConfigureSerilogAsync(app);
await app.RunAsync("http://localhost:5000");

return 0;
catch (Exception exception)
Log.Fatal(exception, "Host terminated unexpectedly");
return 1;

// 6. Retrieve Application Insights connection string to configure the 'real' application logger.
private static async Task ConfigureSerilogAsync(WebApplication app)
var secretProvider = app.Services.GetRequiredService<ISecretProvider>();
string connectionString = await secretProvider.GetRawSecretAsync("APPLICATIONINSIGHTS_CONNECTION_STRING");

var reloadLogger = (ReloadableLogger) Log.Logger;
reloadLogger.Reload(config =>
.MinimumLevel.Override("Microsoft", LogEventLevel.Warning)

return config;
  1. Before the application is build, we should set up a basic Serilog logger to log any startup failures. That's what the try/catch/finally block is all about. This is a safe and reliable way to setup Serilog (more info). Note that the .CreateBootstrapLogger() means that the Serilog logger can be 'reloaded' afterwards.
  2. The connection string to contact the Application Insights resource should be stored safely. The .ConfigureSecretStore will register a composite ISecretProvider interface to interact with all the registered secret providers (more info).
  3. To make sure that any written telemetry to Application Insights is correlated, the Serilog sink should be able to access the current HTTP correlation of the received request. The .AddHttpCorrelation() makes sure that the HTTP correlation services are available.
  4. Make sure that Serilog uses the static configured logger as application logger that gets injected as ILogger in your application (more info).
  5. To set the current HTTP correlation information of the received HTTP request, the Arcus HTTP correlation middleware has to be registered with .UseHttpCorrelation(). This will make sure that the HTTP correlation information will be set, using the previously registered HTTP correlation services (3).
  6. When the application is build, the 'real' Serilog configuration can be set up. This will extract the Application Insights connection string from the Arcus secret store and use it to configure the Arcus Serilog sink, using AzureApplicationInsightsWithConnectionString. This example also adds WithHttpCorrelationInfo from the Arcus.WebApi.Logging library to include the HTTP correlation (more info).

💡 Note: this setup is by default available in the Arcus web API project template.

Writing telemetry with ILogger

Once Serilog is set up, you can write telemetry data with the general ILogger instance injected in your application. This example uses the Arcus logger extension to track custom events in Application Insights, but there is a lot more that can be tracked. See our list of telemetry types to find out all the available types that can be written with Arcus.

using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;

public class OrderController : ControllerBase
private readonly ILogger _logger;

public OrderController(ILogger<OrderController> logger)
_logger = logger;

public IActionResult Post([FromBody] Order order)
// Use logger for general logging: results in 'trace' in Application Insights.
_logger.LogInformation("Order {Id} processed!", order.Id);

var contextualInformation = new Dictionary<string, object>
{"Order ID", order.Id},
{"Customer", order.Customer.Name}

// Use logger for telemetry tracking: results in 'custom event' in Application Insights.
_logger.LogCustomEvent("Order processed", contextualInformation);

return Accepted();