Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to setup Serilog with Azure Functions v4 correctly?

I want to use Serilog in an Azure Function v4 (.net 6) (the logs should be sent to Datadog). For this I have installed the following nuget packages:

<PackageReference Include="Serilog" Version="2.10.0" />
<PackageReference Include="Serilog.Extensions.Logging" Version="3.1.0" />
<PackageReference Include="Serilog.Formatting.Compact" Version="1.1.0" />
<PackageReference Include="Serilog.Sinks.Console" Version="4.0.1" />
<PackageReference Include="Serilog.Sinks.Datadog.Logs" Version="0.3.5" />

Below is the configuration in the Startup.cs class:

public override void Configure(IFunctionsHostBuilder builder)
{
  builder.Services.AddHttpClient();
  
  //... adding services etc.

  Log.Logger = new LoggerConfiguration()
    .MinimumLevel.Override("Microsoft", LogEventLevel.Warning)
    .MinimumLevel.Override("Worker", LogEventLevel.Warning)
    .MinimumLevel.Override("Host", LogEventLevel.Warning)
    .MinimumLevel.Override("System", LogEventLevel.Error)
    .MinimumLevel.Override("Function", LogEventLevel.Error)
    .MinimumLevel.Override("Azure.Storage.Blobs", LogEventLevel.Error)
    .MinimumLevel.Override("Azure.Core", LogEventLevel.Error)
    .Enrich.WithProperty("Application", "Comatic.KrediScan.AzureFunctions")
    .Enrich.FromLogContext()
    .WriteTo.DatadogLogs("XXXXXXXXXXX", configuration: new DatadogConfiguration() { Url = "https://http-intake.logs.datadoghq.eu" }, logLevel:   LogEventLevel.Debug)
    .WriteTo.Console()
    .CreateLogger();

  builder.Services.AddSingleton<ILoggerProvider>(sp => new SerilogLoggerProvider(Log.Logger, true));

  builder.Services.AddLogging(lb =>
  {
    //lb.ClearProviders(); //--> if used nothing works...
    lb.AddSerilog(Log.Logger, true);
  });

Basically logging works, but all log statements are written twice (with a few milliseconds difference, Datadog and Console).

enter image description here

Obviously I am doing something fundamentally wrong with the configuration. I don't use appsettings.json, the configuration of Serilog takes place exclusively in the code. I have scoured the entire internet and read just about every article on Serilog and Azure Functions. On Stackoverflow I also read virtually every question about it and tried all the answers. Unfortunately, so far without success.

SO-Questions for example: Use Serilog with Azure Log Stream
How do I use Serilog with Azure WebJobs?
Serilog enricher Dependency Injection with Azure Functions
https://github.com/hgmauri/sample-azure-functions/blob/main/src/Sample.AzureFunctions.DotNet31/Startup.cs

Is there any example for setting up Serilog with Azure Functions v4 / .net 6?

Thanks a lot for the help!
Michael Hachen

like image 286
mikehachen Avatar asked Nov 23 '25 10:11

mikehachen


2 Answers

Got it! After replacing all ILogger with ILogger<T> and removing the line builder.Services.AddSingleton<ILoggerProvider>(sp => new SerilogLoggerProvider(Log.Logger, true)); everything worked as expected.

Startup.cs

Log.Logger = new LoggerConfiguration()
          .MinimumLevel.Override("Microsoft", LogEventLevel.Warning)
          .MinimumLevel.Override("Worker", LogEventLevel.Warning)
          .MinimumLevel.Override("Host", LogEventLevel.Warning)
          .MinimumLevel.Override("System", LogEventLevel.Error)
          .MinimumLevel.Override("Function", LogEventLevel.Error)
          .MinimumLevel.Override("Azure.Storage.Blobs", LogEventLevel.Error)
          .MinimumLevel.Override("Azure.Core", LogEventLevel.Error)
          .Enrich.WithProperty("Application", $"xxxxx.AzureFunctions.{builder.GetContext().EnvironmentName}")
          .Enrich.FromLogContext()
          .Enrich.WithExceptionDetails(new DestructuringOptionsBuilder()
            .WithDefaultDestructurers()
            .WithDestructurers(new[] { new SqlExceptionDestructurer() }))
          .WriteTo.Seq(builder.GetContext().EnvironmentName.Equals("Development", StringComparison.OrdinalIgnoreCase) ? "http://localhost:5341/" : "https://xxxxxx.xx:5341/", LogEventLevel.Verbose)
          .WriteTo.Console(theme: SystemConsoleTheme.Literate)
          .CreateLogger();
      
      builder.Services.AddLogging(lb =>
      {
        lb.AddSerilog(Log.Logger, true);
      });
like image 117
mikehachen Avatar answered Nov 25 '25 04:11

mikehachen


For those that got here because they can't properly config their logging in an azure function with the app insights sink this is what works for me:

private static void ConfigureLogging(IServiceCollection services)
{
   Log.Logger = new LoggerConfiguration()
        .MinimumLevel.Information()
        .MinimumLevel.Override("Microsoft", LogEventLevel.Warning)
        .MinimumLevel.Override("System", LogEventLevel.Warning)
        .MinimumLevel.Override("Worker", LogEventLevel.Warning)
        .MinimumLevel.Override("Host", LogEventLevel.Warning)
        .MinimumLevel.Override("Function", LogEventLevel.Warning)
        .MinimumLevel.Override("Azure", LogEventLevel.Warning)
        .MinimumLevel.Override("DurableTask", LogEventLevel.Warning)
        .Enrich.FromLogContext()
        .Enrich.WithExceptionDetails()
        .WriteTo.ApplicationInsights(
            TelemetryConfiguration.CreateDefault(),
            TelemetryConverter.Events,
            LogEventLevel.Information)
        .CreateLogger();
        services.AddLogging(configure => configure.AddSerilog(Log.Logger));
}

The example here at the time of writing doesn't seem to work. The logging scope doesn't get captured in the output.

Serilog Version: 2.11.0

Serilog.Sinks.ApplicationInsights Version: 4.0.0

Linked example for the future:

[assembly: FunctionsStartup(typeof(MyFunctions.Startup))]
namespace MyFunctions
{
    public class Startup : FunctionsStartup
    {
        public override void Configure(IFunctionsHostBuilder builder)
        {
            builder.Services.AddSingleton<ILoggerProvider>((sp) => 
            {
                Log.Logger = new LoggerConfiguration()
                    .Enrich.FromLogContext()
                    .WriteTo.ApplicationInsights(sp.GetRequiredService<TelemetryClient>(), TelemetryConverter.Traces)
                    .CreateLogger();
                return new SerilogLoggerProvider(Log.Logger, true);
            });
        }
    }
}
like image 41
Plevi Avatar answered Nov 25 '25 04:11

Plevi



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!