Sai
Sai

Reputation: 675

Azure FunctionApps (Isolated worker) with Serilog unable to resolve

I'm using Azure Functionapp (version 4) isolated worker process. I have configured Serilog in the program.cs file as below. But in my actual function when I inject Serilog.ILogger, it fails with error during runtime, unable to resolve Serilog.ILogger.

using Microsoft.ApplicationInsights.Extensibility;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Serilog;
using Microsoft.Azure.Functions.Worker;

var host = new HostBuilder()
    .ConfigureFunctionsWorkerDefaults()
     .ConfigureServices(s =>
     {
         s.AddApplicationInsightsTelemetryWorkerService();
         s.ConfigureFunctionsApplicationInsights();


         Log.Logger = new LoggerConfiguration()
             .Enrich.FromLogContext()
             .Enrich.WithProperty("Application", "Application")
             .Enrich.WithProperty("Environment", "Dev")
             .MinimumLevel.Warning()
              .WriteTo.ApplicationInsights(TelemetryConfiguration.CreateDefault(), TelemetryConverter.Traces)
              .CreateLogger();


         //configure seriLog
         s.AddLogging(lb =>
         {
             lb.AddSerilog(Log.Logger, true);
         });

         s.Configure<LoggerFilterOptions>(options =>
         {
             // The Application Insights SDK adds a default logging filter that instructs ILogger to capture only Warning and more severe logs. Application Insights requires an explicit override.
             // Log levels can also be configured using appsettings.json. For more information, see https://learn.microsoft.com/en-us/azure/azure-monitor/app/worker-service#ilogger-logs
             LoggerFilterRule toRemove = options.Rules.FirstOrDefault(rule => rule.ProviderName
                 == "Microsoft.Extensions.Logging.ApplicationInsights.ApplicationInsightsLoggerProvider");

             if (toRemove is not null)
             {
                 options.Rules.Remove(toRemove);
             }
         });
     })
    .Build();

host.Run();

I Also tried using the below method to register Serilog but its still fails -

 s.AddSingleton<ILoggerProvider>((sp) =>
     {
         Log.Logger = new LoggerConfiguration()
             .Enrich.FromLogContext()
             .WriteTo.ApplicationInsights(sp.GetRequiredService<TelemetryClient>(), TelemetryConverter.Traces)
             .CreateLogger();
         return new SerilogLoggerProvider(Log.Logger, true);
     });

Upvotes: 0

Views: 774

Answers (1)

Hank
Hank

Reputation: 2466

The main reason that Serilog.ILogger is not resolvable is that AddSerilog doesn't add Serilog.ILogger as a resolvable service as you shouldn't be requesting a Serilog.ILogger.

The AddSerilog that you are using is an extension method to Microsoft.Extensions.Logging.ILoggingBuilder and it adds Serilog as an ILoggerProvider (see source code). That way, when you request an Microsoft.Extensions.Logging.ILogger, it will build an logger that logs to all the registered ILoggerProviders as Serilog may not be the only provider.

Instead, you should be requesting that an Microsoft.Extension.Logging.ILogger<T> be injection into your function.

If you really want an Serilog.ILogger injected, then you need to use extension AddSerilog on the IServiceCollection and provide Log.Logger. The source code for that function is here.

A summary:

You should be using any of the following:

var host = new HostBuilder()
    .UseSerilog()
    .Build()

// OR

var host = new HostBuilder()
    .ConfigureServices(s =>
    {
        s.AddSerilog();
    })
    .Build();

// OR

var host = new HostBuilder()
    .ConfigureServices(s =>
    {
        s.ConfigureLogging(lb => lb.AddSerilog());
    })
    .Build();

and then injecting ILogger<T> is the recommended practice since your functions shouldn't know anything about Serilog. You also never need to specify Serilog's static Log.Logger as it will be used by default if ILogger is not specified.

And here's what you should do if you want to inject a Serilog.ILogger.

var host = new HostBuilder()
    .ConfigureServices(s =>
    {
        s.AddSerilog(Log.Logger);
    })
    .Build();

I didn't specify whether you need to use dispose or not, that's up to your implementation.

Upvotes: 2

Related Questions