10

I want to get certain key bits of information (service-name, service-version, host-name, etc) logged on every log message in an ASP.Net Core service.

I have the following code:

public class Program
{
    public static void Main(string[] args)
    {
        var host = CreateHostBuilder(args).Build();

        using (host.Services.GetRequiredService<ILogger<Program>>().BeginScope("ServiceName: {0}", "bob-service"))
        {
            host.Run();
        }
    }

    public static IHostBuilder CreateHostBuilder(string[] args) =>
        Host.CreateDefaultBuilder(args)
            .ConfigureLogging(builder =>
            {
                builder.AddConsole(o => o.IncludeScopes = true);
            })
            .ConfigureWebHostDefaults(webBuilder =>
            {
                webBuilder.UseStartup<Startup>();
            });
}

From this I get the following logging:

info: Microsoft.Hosting.Lifetime[0]
      => ServiceName: bob-service
      Now listening on: http://localhost:5002

info: Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.PageActionInvoker[102]
      => ConnectionId:0HLSO8706NGBN => RequestPath:/ RequestId:0HLSO8706NGBN:00000001, SpanId:|aa5794ba-408ad22a63064421., TraceId:aa5794ba-408ad22a63064421, ParentId: => Middleware_Scope => /Index
      Executed handler method OnGet, returned result .

Note how the ServiceName only appears on the host-level logging. The request-level logging does not include it.

Is there a mechanism for setting scope on every log-message that comes out of ASP.Net Core.

I've tried adding a piece of middleware to do this, and it mostly works, but the logging doesn't appear on the "Microsoft.AspNetCore.Hosting.Diagnostics" log messages (although it appears on everything else as far as I can tell).

app
    .Use(async (context, next) =>
    {
        // Middleware to add scoped values to log messages.
        var logger = context.RequestServices.GetRequiredService<ILogger<Startup>>();
        using (logger.BeginScope("ServiceName: {0}", "bob-service")))
        {
            await next();
        }
    });

EDIT

Even when using the middleware described above, log messages from the Microsoft.AspNetCore.Hosting.Diagnostics logger do not contain the scoped fields. For example, note how in the second log message, the Middleware_Scope scoped message does not appear.

info: Microsoft.AspNetCore.StaticFiles.StaticFileMiddleware[6]
      => ConnectionId:0HLSOTDVELPJA => RequestPath:/css/site.css RequestId:0HLSOTDVELPJA:00000001, SpanId:|2fbd556d-44cc7c919266ccaf., TraceId:2fbd556d-44cc7c919266ccaf, ParentId: => Middleware_Scope
      The file /css/site.css was not modified

info: Microsoft.AspNetCore.Hosting.Diagnostics[2]
      => ConnectionId:0HLSOTDVELPJD => RequestPath:/js/site.js RequestId:0HLSOTDVELPJD:00000001, SpanId:|2fbd5570-44cc7c919266ccaf., TraceId:2fbd5570-44cc7c919266ccaf, ParentId:
      Request finished in 29.8413ms 304 application/javascript
RB.
  • 36,301
  • 12
  • 91
  • 131
  • "but the logging doesn't appear on the "Microsoft.AspNetCore.Hosting.Diagnostics" log messages" -- Isn't that covered from the first bit of code? – Chris Pratt Jan 13 '20 at 16:35
  • @chrispratt not in my testing sadly. – RB. Jan 13 '20 at 16:45
  • `logging doesn't appear on the "Microsoft.AspNetCore.Hosting.Diagnostics" log messages` Do you mean when the log is produced by `Microsoft.AspNetCore.Hosting.Diagnostics`, the message defined in BeginScope did not shows up? Can you paste the logs contain the good case and bad case? – Rena Jan 14 '20 at 09:58
  • @Rena Please see my edit, containing the log message where it is missing. – RB. Jan 14 '20 at 12:18
  • Could you share what is the version of asp.net core? – Rena Jan 15 '20 at 05:26
  • @Rena ASP.Net Core 3.0. – RB. Jan 15 '20 at 10:55
  • `Microservice.GetBaseLoggingFields(Constants.Application.ServiceName)` What's the `Microservice.GetBaseLoggingFields` method here? Is it customer own method? and what's `Constants.Application.ServiceName`? is it also custom defined? – Rena Jan 16 '20 at 05:08
  • @Rena Those are just a copy-paste from the real application. I've removed them now, as the above is intended to be an MVCE. – RB. Jan 16 '20 at 09:24
  • @RB. did you figure out a way of doing global scope, I am also looking for options of doing something similar – MariangeMarcano Oct 13 '20 at 11:52
  • Did you try changing logging to Trace? You can also get those values manually from your context request object in .NET and manually log the values you need that way. I would roll your own log class to capture those on every request and log them as information log levels. – Stokely Nov 12 '20 at 00:58
  • If someone uses serilog, consider to use LogContext as described in https://stackoverflow.com/questions/57460579/how-do-i-get-a-serilog-enricher-to-work-with-dependency-injection-while-keeping/57488163#comment115865101_57488163 – Michael Freidgeim Apr 25 '21 at 02:12

0 Answers0