serilog / serilog-extensions-logging

Serilog provider for Microsoft.Extensions.Logging
Apache License 2.0
313 stars 100 forks source link

Doesn't work in Azure Functions v2 #139

Closed gthvidsten closed 5 years ago

gthvidsten commented 5 years ago

When creating an Azure Function you can provide a startup class that inherits from IWebJobsStartup. This has an IServiceCollection you can inject into, and the Azure Functions will get these custom objects injected. This can be done in the following fashion according to the documentation:

[assembly: WebJobsStartup(typeof(Startup))]
namespace MyAzureFunc {
    internal class Startup : IWebJobsStartup {
        public void ConfigureServices(IServiceCollection services) {
            Log.Logger = new LoggerConfiguration()
                .Enrich.FromLogContext()
                .WriteTo.Console()
                .WriteTo.File()
                .CreateLogger();
            services.AddLogging(loggingBuilder => loggingBuilder.AddSerilog(dispose: true));
        }
    }
}

Which doesn't work.

According to this comment on #127 you can also do this:

[assembly: WebJobsStartup(typeof(Startup))]
namespace MyAzureFunc {
    internal class Startup : IWebJobsStartup {
        public void Configure(IWebJobsBuilder builder) {
            builder.Services.AddLogging(
                lb => lb.ClearProviders()
                    .AddSerilog(
                        new LoggerConfiguration()
                            .WriteTo.Console()
                            .WriteTo.File(...)
                            .CreateLogger(),
                        dispose: true));
        }
    }
}

However, this doesn't work either. There are no errors when compiling or running, but the log messages do not appear in the file, and not in the console (well, they do appear in the console, but not in the Serilog-format but seems to be using the default logger).

Seeing as the final example clears providers, I'm surprised it still uses the default ILogger and not the injected Serilog instance.

So the question is basically then how to get Serilog to work in an Azure Function with a startup class to handle DI.

gthvidsten commented 5 years ago

My bad. I was using the wrong version of Microsoft.NET.Sdk.Functions (WebJobsStartup requires version 1.0.26+). I'm now able to add Serilog.ILogger as a singleton.

However, using the builder.Services.AddLogging(), then trying to inject Microsoft.Extensions.Logging.ILogger to the Azure Functions class constructor gives an error that ILogger can't be found. Removing it from the constructor and instead trying to use it directly in the method yields the same result.

nblumhardt commented 5 years ago

Hi @gthvidsten - thanks for the notes/observations. Azure Functions is a bit of an unusual environment, I'm not using it personally so I can't offer any advice unfortunately, but hopefully someone else tuned in here has hit the same issue in the past.

If not, Stack Overflow can get a lot more eyes on these kinds of issues, so posting there under the serilog tag may be worthwhile.

gthvidsten commented 5 years ago

I managed to get an Extensions.Logging.ILogger into my Azure Function methods, but I still haven't gotten it injected into my constructor. I'll see if anyone on SO have any ideas about it. If they have I'll try to remember to post the conclusion here.

gthvidsten commented 5 years ago

It seems that Extensions.Logging.ILogger is something you must create yourself in the constructor. You can inject an Extensions.Logging.ILoggerFactory and use that to create an Extensions.Logging.ILogger using ILogger log = loggerFactory.CreateLogger<MyClass>();

You can then save the resulting ILogger into the class member variables and keep using it in all the Azure Funtions in that class without having to inject an ILogger into each method.

alastairtree commented 4 years ago

You do't have to use ILoggerFactory, ILogger does work, but you may need to tweak your host.json file to ensure function logs get published into serilog:

{
  "version": "2.0",
  "logging": {
    "fileLoggingMode": "debugOnly",
    "logLevel": {
      // For all functions
      "Function": "Trace",
      // Default settings, e.g. for host
      "default": "Trace"
    }
  }
}