For my ASP.NET 5 Web Project I want to log to Application Insights via Serilog. Now I finally got everything working, but I cannot belive this is they way to go. I hope you can help me to improve it.
The main problem I see, is that the Instrumentation Key of Application Insights is both configured in the Serilog and ApplicationInsights section of appsettings.json. I would expect Serilog to use the default/active Client (and configuration), but instead it seems to create a second Client based on its own configuration.
Documentation at https://github.com/serilog/serilog-sinks-applicationinsights says:
As mentioned above you can also pass an instrumentation key but it's actively discouraged
If I remove the instrumentationKey setting from the Serilog section in appsettings.json, it doesn't log any Serilog statements to Application Insights anymore. To solve this issue, I saw you can use .WriteTo.ApplicationInsights(TelemetryConfiguration.Active, TelemetryConverter.Traces)
, but I don't want hard-coded configuration and prefer to do it via appsettings.json. Also, I am affraid having two Clients/configurations, does not give the best performance.
Now, is there any way to do the configuration via appsettings.json and not have to duplicate the instrumentation key?
Program.cs
public static void Main(string[] args)
{
LoggingExtensions.SetupLoggerConfiguration(AppName, AppVersion);
try
{
Log.Information("Starting web host for {0}", AppName);
CreateHostBuilder(args).Build().Run();
}
catch (Exception ex)
{
Log.Fatal(ex, "Host terminated unexpectedly");
}
finally
{
Log.CloseAndFlush();
}
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.UseSerilog((hostBuilderContext, loggerConfiguration) =>
{
loggerConfiguration.ConfigureBaseLogging(
hostBuilderContext.Configuration, AppName, AppVersion);
})
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
public static string AppName => typeof(Program).Assembly.GetName().Name;
public static Version AppVersion => typeof(Program).Assembly.GetName().Version;
Startup.cs
public void ConfigureServices(IServiceCollection services)
{
...
services.AddApplicationInsightsTelemetry(Configuration["APPINSIGHTS_CONNECTIONSTRING"]);
...
}
LoggingExtensions.cs
internal static void SetupLoggerConfiguration(string appName, Version appVersion)
{
var configuration = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json")
.AddJsonFile($"appsettings.{Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") ?? "Production"}.json", true)
.Build();
Log.Logger = new LoggerConfiguration()
.ConfigureBaseLogging(configuration, appName, appVersion)
.CreateLogger();
}
internal static LoggerConfiguration ConfigureBaseLogging(
this LoggerConfiguration loggerConfiguration,
IConfiguration configuration,
string appName,
Version appVersion
)
{
loggerConfiguration
.ReadFrom.Configuration(configuration)
.Enrich.WithProperty("ApplicationVersion", appVersion.ToString())
.Enrich.WithProperty("ApplicationName", appName);
return loggerConfiguration;
}
HomeController.cs
private readonly ILogger<HomeController> _logger;
public HomeController(ILogger<HomeController> logger)
{
_logger = logger;
}
public ActionResult Index()
{
_logger.LogInformation("Home page visit");
return View();
}
appsettings.json
{
"Serilog": {
"Using": [
"Serilog.Sinks.Console",
"Serilog.Sinks.ApplicationInsights"
],
"MinimumLevel": {
"Default": "Information"
},
"WriteTo": [
{
"Name": "Console",
"Args": {
"theme": "Serilog.Sinks.SystemConsole.Themes.AnsiConsoleTheme::Code, Serilog.Sinks.Console"
}
},
{
"Name": "ApplicationInsights",
"Args": {
"restrictedToMinimumLevel": "Information",
"instrumentationKey": "xxx",
"telemetryConverter": "Serilog.Sinks.ApplicationInsights.Sinks.ApplicationInsights.TelemetryConverters.TraceTelemetryConverter, Serilog.Sinks.ApplicationInsights"
}
}
],
"Enrich": [
"FromLogContext",
"WithMachineName",
"WithThreadId"
]
},
"ApplicationInsights": {
"ConnectionString": "InstrumentationKey=xxx;IngestionEndpoint=https://xxx.in.applicationinsights.azure.com/"
}
}
Update 1
Seems that the ApplicationInsights sink relies on TelemetryConfiguration.Active
which is deprecated and probably not set in .NET 5.
https://github.com/serilog/serilog-sinks-applicationinsights/issues/141
For now, I used the solution at https://github.com/serilog/serilog-sinks-applicationinsights/issues/121#issuecomment-798849183, but please if someone has a better solution... tell me!
Update 2
Found a better solution for now at https://github.com/serilog/serilog-sinks-applicationinsights/issues/156
The deprecated TelemetryConfiguration.Active
can be used by setting this option in startup.cs:
services.AddApplicationInsightsTelemetry(opt => opt.EnableActiveTelemetryConfigurationSetup = true);
// No need to set InstrumentationKey here as you can do this by setting
// { "ApplicationInsights": { "InstrumentationKey": "xxx" } }
// in appsettings.json
Also add the following on top of the Program.cs as described on https://nblumhardt.com/2020/10/bootstrap-logger/
Log.Logger = new LoggerConfiguration()
.WriteTo.Console()
.CreateBootstrapLogger();