Search code examples
c#asp.net-coreloggingazure-functionsserilog

Azure Functions V3: Unable to get ILogger working with DI


We have an Azure Function v3 and would like to inject an ILogger<MyFunction> logger into our function classes via constructor. We are struggling to get it to work with Serilog as the default logger.

I have tried different ways as shown below with different errors.

Startup.cs:

public class Startup : FunctionsStartup
{
    public override void Configure(IFunctionsHostBuilder builder)
    {
        builder.Services.AddSingleton<ILoggerFactory, LoggerFactory>();
        builder.Services.AddSingleton<ILoggerProvider>(sp =>
        {
            var logger = new LoggerConfiguration().WriteTo.Elasticsearch(
                new ElasticsearchSinkOptions(...)
                .CreateLogger();
            return new SerilogLoggerProvider(logger, dispose: true);
        });
    }
}

However, I get following error:

Method Microsoft.Extensions.DependencyInjection.ServiceCollectionServiceExtensions.AddSingleton: type argument 'Microsoft.Extensions.Logging.LoggerFactory' violates the constraint of type parameter 'TImplementation'. Value cannot be null. (Parameter 'provider')

If I try to add the factory like following: builder.Services.AddSingleton<ILoggerFactory>(sp => new LoggerFactory());

The error is:

Microsoft.Azure.WebJobs.Script.WebHost: Registered factory delegate returns service Microsoft.Extensions.Logging.LoggerFactory is not assignable to container. Value cannot be null. (Parameter 'provider')

Trying to add the logger into a provider into a factory in one go when adding the IFactoryLogger results in following error:

Method not found: 'Void Microsoft.Extensions.Logging.LoggerFactory..ctor(System.Collections.Generic.IEnumerable`1<Microsoft.Extensions.Logging.ILoggerProvider>)'. Value cannot be null. (Parameter 'provider')

I've also tried to add the default logging without declaring a factory:

builder.Services.Add(ServiceDescriptor.Describe(typeof(ILogger<>), typeof(Logger<>), ServiceLifetime.Scoped));

The error is:

Microsoft.Extensions.Logging.Abstractions: Value cannot be null. (Parameter 'factory').

Am I missing something crucial here?


Solution

  • Below is the way to add Serilog in Azure Functions V3:

    • Create an instance the Serilog logger, with all the configuration for console and file sinks.
    • Register this logger in the builder.Services.AddLogging method.

    Related Code:

    // Startup.cs - Registering a third party logging provider
    var logger = new LoggerConfiguration()
                    .WriteTo.Console()
                    .WriteTo.File("log.txt", rollingInterval: RollingInterval.Day)
                    .CreateLogger();
    builder.Services.AddLogging(lb => lb.AddSerilog(logger));
    

    Complete Startup.cs:

    // Startup.cs
    using AzureFunctionDependencyInjection.Configurations;
    using AzureFunctionDependencyInjection.Services;
    using Microsoft.Azure.Functions.Extensions.DependencyInjection;
    using Microsoft.Extensions.Configuration;
    using Microsoft.Extensions.DependencyInjection;
    using Serilog;
    [assembly: FunctionsStartup(typeof(AzureFunctionDependencyInjection.Startup))]
    namespace AzureFunctionDependencyInjection
    {
        public class Startup : FunctionsStartup
        {
            public override void Configure(IFunctionsHostBuilder builder)
            {
                // Registering Configurations (IOptions pattern)
                builder
                    .Services
                    .AddOptions<MessageResponderConfiguration>()
                    .Configure<IConfiguration>((messageResponderSettings, configuration) =>
                    {
                        configuration
                        .GetSection("MessageResponder")
                        .Bind(messageResponderSettings);
                    });
    // Registering Serilog provider
                var logger = new LoggerConfiguration()
                    .WriteTo.Console()
                    .WriteTo.File("log.txt", rollingInterval: RollingInterval.Day)
                    .CreateLogger();
                builder.Services.AddLogging(lb => lb.AddSerilog(logger));
    // Registering services
                builder
                    .Services
                    .AddSingleton<IMessageResponderService, MessageResponderService>();
            }
        }
    }
    

    Check out this detailed and great article: Dependency Injection in Azure Functions V3 on this.