2017-11-02 25 views
5

Tôi đang tạo bồn rửa SeriLog của riêng mình triển khai ILogEventSink sử dụng ví dụ Building a Simple Sink với mục đích ghi nhật ký một số thông tin từ xác nhận quyền sở hữu của người dùng. Để truy cập vào HttpContext trong Core, tôi thường tiêm vào một thể hiện của IHttpContextAccessor nhưng ví dụ này cho thấy việc tạo một thể hiện của bồn rửa trong một phương thức mở rộng, ví dụ:Làm thế nào tôi có thể nhận được HttpContext hiện tại trong một SeriLog Sink?

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)); 
    } 
} 

... sau đó sử dụng bồn rửa chén ...

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

Làm thế nào tôi có thể nhận được quyền truy cập vào các HttpContext hiện trong phương pháp Emit của bồn rửa chén? Hoặc là nó có thể có bồn rửa được tạo ra bởi khuôn khổ DI ví dụ ?!

Tôi có trang web MVC chạy khuôn khổ Asp.Net Core 2 dựa trên thời gian chạy Net 4.6.2 bằng Serilog.AspNetCore v2.1.0.

Update - Cách giải quyết

Sau khi con trỏ từ @tsimbalar Tôi tạo ra middleware tương tự như mã dưới đây. Trong phương pháp StartUp.Configure tôi thêm nó bằng cách sử dụng app.UseMiddleware<ClaimsMiddleware>();sau bước xác thực ứng dụng đã xảy ra (nếu không sẽ không có xác nhận quyền sở hữu nào được tải).

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; 
    } 
} 

Trả lời

2

CẬP NHẬT Tôi nghĩ bạn có thể muốn nhìn vào bài viết này: http://mylifeforthecode.com/enriching-serilog-output-with-httpcontext-information-in-asp-net-core/

Ý tưởng là để đăng ký một middleware tùy chỉnh mà sẽ thêm tất cả các theo ngữ cảnh thông tin với dòng LogContext trong yêu cầu.

Đối với nó để làm việc bạn phải cấu hình logger của bạn với

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

Bài viết này bởi Nicholas Blumhardt cũng có thể giúp: https://blog.getseq.net/smart-logging-middleware-for-asp-net-core/


CẢNH BÁO - Giải pháp dưới đây không làm việc trong trường hợp này

Giải pháp dưới đây không thể hoạt động nếu trình ghi nhật ký được đăng ký sớm (trong Program.Main())

Trước hết, nếu bạn muốn thêm thông tin bổ sung kèm theo sự kiện đã đăng nhập, tôi tin những gì bạn muốn là Enricher.

Bạn có thể sau đó:

  • Đăng ký IHttpContextAccessor vào ServiceCollection của bạn (ví dụ, sử dụng AddHttpContextAccessor()): services.AddHttpContextAccessor();
  • Tạo một thực hiện ILogEventEnricher chấp nhận IHttpContextAccessor trong constructor của nó
  • Khi cấu hình logger của bạn, tiêm IHttpContextAccessor (bằng cách thêm đối số loại IHttpContextAccessor vào Startup.Configure()
  • Thêm vi phong phú hơn cho logger của bạn

enricher có thể trông giống như https://github.com/serilog-web/classic/blob/master/src/SerilogWeb.Classic/Classic/Enrichers/ClaimValueEnricher.cs.

Và bạn sẽ configure logger của bạn như thế này:

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

Cảm ơn @tsimbalar. Trong bước ** configure ** bạn đang chuyển 'contextAccessor' vào một cá thể của đối tượng' MyEnricher'. Đây không phải là sử dụng tiêm phụ thuộc vì vậy làm thế nào tôi sẽ nhận được bối cảnh nếu tôi đang cấu hình đăng nhập vào chương trình chính Phương pháp trước khi khởi động (và sau đó 'ConfigureServices') đã được gọi? –

+0

oh có, nếu bạn đang ở trong chương trình chính, mà không thể làm việc .... mmmm không chắc chắn làm thế nào mà sẽ làm việc – tsimbalar

+0

@ gavin Tôi đã cập nhật câu trả lời của tôi – tsimbalar

Các vấn đề liên quan