How can I get the current HttpContext in a SeriLog shell?

I create my own SeriLog receiver that implements ILogEventSink using the Example of creating a simple shell to record some information from users claim. To access the HttpContext in Core, I would usually inject IHttpContextAccessor into the instance, but the example shows IHttpContextAccessor to create the receiver instance in the extension method, for example.

 public class MySink : ILogEventSink { private readonly IFormatProvider _formatProvider; public MySink(IFormatProvider formatProvider) { _formatProvider = formatProvider; } public void Emit(LogEvent logEvent) { // How to get HttpContext here? } } public static class MySinkExtensions { public static LoggerConfiguration MySink( this LoggerSinkConfiguration loggerConfiguration, IFormatProvider formatProvider = null) { return loggerConfiguration.Sink(new MySink(formatProvider)); } } 

... then use the sink ...

 var log = new LoggerConfiguration() .MinimumLevel.Information() .WriteTo.MySink() .CreateLogger(); 

How to access the current HttpContext in the receiver's Emit method? Or maybe there is a sink created by the DI framework, for example ?!

I have an MVC site working with an Asp.Net Core 2 base against the .NET 4.2.2 environment using Serilog.AspNetCore v2.1.0.

Update - Workaround

After the pointer from @tsimbalar, I created a middleware similar to the code below. In my StartUp.Configure method StartUp.Configure I add it using app.UseMiddleware<ClaimsMiddleware>(); after the authentication step of the application has been completed (otherwise, no applications will be downloaded).

 public class ClaimsMiddleware { private static readonly ILogger Log = Serilog.Log.ForContext<ClaimsMiddleware>(); private readonly RequestDelegate next; public ClaimsMiddleware(RequestDelegate next) { this.next = next ?? throw new ArgumentNullException(nameof(next)); } public async Task Invoke(HttpContext httpContext) { if (httpContext == null) throw new ArgumentNullException(nameof(httpContext)); // Get values from claims here var myVal = httpContext .User .Claims .Where(x => x.Type == "MyVal") .Select(x => x.Value) .DefaultIfEmpty(string.Empty) .SingleOrDefault(); using (LogContext.PushProperty("MyVal", myVal)) { try { await next(httpContext); } // Never caught, because `LogException()` returns false. catch (Exception ex) when (LogException(httpContext, ex)) { } } } private static bool LogException(HttpContext httpContext, Exception ex) { var logForContext = Log.ForContext("StackTrace", ex.StackTrace); logForContext.Error(ex, ex.Message); return false; } } 
+5
source share
1 answer

UPDATE I think you can look at this article: http://mylifeforthecode.com/enriching-serilog-output-with-httpcontext-information-in-asp-net-core/

The idea is to register a custom middleware that will add all contextual information to the current LogContext at the time of the request.

To work, you must configure your log using

 Log.Logger = new LoggerConfiguration() // snip ....MinimumLevel.Debug() .Enrich.FromLogContext() // snip ... .CreateLogger(); 

This article by Nicholas Bloomhardt can also help: https://blog.getseq.net/smart-logging-middleware-for-asp-net-core/


A WARNING. The solution below does not work in this case

The solution below cannot work if the registrar is registered earlier (in Program.Main ())

First of all, if you want to add additional information related to a registered event, I believe that you want Enricher .

Could you:

  • Register IHttpContextAccessor in your ServiceCollection (for example, using AddHttpContextAccessor() ): services.AddHttpContextAccessor();
  • Create an ILogEventEnricher implementation that accepts IHttpContextAccessor in its constructor
  • When setting up your registrar, enter IHttpContextAccessor (by adding an argument of type IHttpContextAccessor to Startup.Configure()
  • Add this enrichment to your registrar

enricher might look something like https://github.com/serilog-web/classic/blob/master/src/SerilogWeb.Classic/Classic/Enrichers/ClaimValueEnricher.cs .

And you would configure your registrar as follows:

 var logger = new LoggerConfiguration() .EnrichWith(new MyEnricher(contextAccessor)) .WriteTo.Whatever() .CreateLogger(); 
+2
source

Source: https://habr.com/ru/post/1273075/


All Articles