2017-11-02 18 views
5

사용자 클레임의 일부 정보를 기록하려는 목적으로 Building a Simple Sink 예제를 사용하여 ILogEventSink을 구현하는 자체 SeriLog 싱크를 만듭니다. 코어에서 HttpContext에 액세스하려면 일반적으로 IHttpContextAccessor의 인스턴스를 삽입하지만 예제에서는 확장 메서드에서 싱크의 인스턴스를 만드는 예를 보여줍니다. SeriLog 싱크에서 현재 HttpContext를 가져 오는 방법은 무엇입니까?

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

... 다음 싱크를 사용하는 ...
var log = new LoggerConfiguration() 
    .MinimumLevel.Information() 
    .WriteTo.MySink() 
    .CreateLogger(); 

어떻게 싱크대의 방출 방법에서 현재 HttpContext에 대한 액세스를 얻을 수 있습니까? 또는 예를 들어 DI 프레임 워크에서 싱크대를 만들 수 있습니까?

Serilog.AspNetCore v2.1.0을 사용하는 .Net 4.6.2 런타임에 대해 Asp.Net Core 2 프레임 워크를 실행하는 MVC 사이트가 있습니다.

업데이트 - 나는 아래의 코드와 유사 미들웨어 만들어 @tsimbalar에서 포인터 후 해결

. 내 StartUp.Configure 메서드에서 app.UseMiddleware<ClaimsMiddleware>();을 사용하여 추가합니다. 이후 앱 인증 단계가 발생했습니다 (그렇지 않으면 클레임이로드되지 않습니다).

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

답변

2

UPDATE 나는 당신이이 글을보고 할 수 있습니다 생각 : http://mylifeforthecode.com/enriching-serilog-output-with-httpcontext-information-in-asp-net-core/

아이디어가시 현재 LogContext에 모든 상황 정보를 추가하는 사용자 정의 미들웨어를 등록하는 것입니다 의뢰. 당신이

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

으로 로거를 구성해야 작동하려면

니콜라스 Blumhardt에 의해이 문서는 또한 도움이 될 수 https://blog.getseq.net/smart-logging-middleware-for-asp-net-core/


경고 - 솔루션 아래이 경우에서 작동하지 않습니다

로거가 등록 된 경우 아래 해결책은 작동하지 않습니다. (Program.Main())

우선, 기록 된 이벤트에 첨부 된 추가 정보를 추가하려면 원하는 파일이 Enricher이라고 생각합니다.

그런 다음 수 (사용 예를 들어, AddHttpContextAccessor()) 당신의 ServiceCollection에

  • 등록 IHttpContextAccessor : services.AddHttpContextAccessor();
  • 은 생성자에서 IHttpContextAccessor을 받아 ILogEventEnricher의 구현을 작성
  • 로거를 구성, IHttpContextAccessor을 삽입하십시오 (IHttpContextAccessor의 인수를 Startup.Configure()에 입력하여
  • 추가하십시오. 로거에 풍부한

enricherhttps://github.com/serilog-web/classic/blob/master/src/SerilogWeb.Classic/Classic/Enrichers/ClaimValueEnricher.cs 같은 것을 볼 수 있었다.

그리고 것 구성이 같은 로거 :

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

감사 @tsimbalar. ** configure ** 단계에서 당신은'contextAccessor'를'MyEnricher' 객체의 인스턴스로 넘깁니다. 이것은 의존성 주입을 사용하지 않기 때문에, Startup (그리고 그 이후에'ConfigureServices')이 호출되기 전에 Program Main 메서드에서 로깅을 설정한다면 어떻게 컨텍스트를 얻게 될까요? –

+0

오, 예, 당신이 프로그램 메인에 있다면, 그건 작동하지 않을 수 있습니다 .... mmmm 어떻게 작동 할 수 있을지 모르겠다 – tsimbalar

+0

@ gavin 난 내 대답을 – tsimbalar