简体   繁体   English

如何在 SeriLog Sink 中获取当前的 HttpContext?

[英]How can I get the current HttpContext in a SeriLog Sink?

I'm creating my own SeriLog sink implementing ILogEventSink using the Building a Simple Sink example with the intent of logging some information from the users claims.我正在创建我自己的 SeriLog 接收器,使用构建一个简单的接收器示例实现ILogEventSink ,目的是从用户声明中记录一些信息。 To get access to HttpContext in Core, I'd normally inject in an instance of IHttpContextAccessor but the example shows creating an instance of the sink in an extension method eg要访问 Core 中的 HttpContext,我通常会注入IHttpContextAccessor的实例,但该示例显示在扩展方法中创建接收器的实例,例如

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 to use the sink ... ......然后使用水槽......

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

How can I get access to the current HttpContext in the Emit method of the sink?如何在接收器的 Emit 方法中访问当前的 HttpContext? Or is it possible to have the sink created by the DI framework for example?!或者是否有可能让 DI 框架创建接收器?!

I have an MVC site running Asp.Net Core 2 framework against .Net 4.6.2 runtime using Serilog.AspNetCore v2.1.0.我有一个 MVC 站点,它使用 Serilog.AspNetCore v2.1.0 针对 .Net 4.6.2 运行时运行 Asp.Net Core 2 框架。

Update - Workaround更新 - 解决方法

After the pointer from @tsimbalar I created middleware similar to the code below.在@tsimbalar 的指针之后,我创建了类似于以下代码的中间件。 In my StartUp.Configure method I add it using app.UseMiddleware<ClaimsMiddleware>();在我的StartUp.Configure方法中,我使用app.UseMiddleware<ClaimsMiddleware>();添加它app.UseMiddleware<ClaimsMiddleware>(); after the app authentication step has happened (otherwise there will be no claims loaded).应用程序身份验证步骤发生后(否则将不会加载任何声明)。

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

UPDATE I think you may want to look at this article : http://mylifeforthecode.github.io/enriching-serilog-output-with-httpcontext-information-in-asp-net-core/更新我想你可能想看看这篇文章: http : //mylifeforthecode.github.io/enriching-serilog-output-with-httpcontext-information-in-asp-net-core/

The idea is to register a custom middleware that will add all the contextual information to the current LogContext during the request.这个想法是注册一个自定义中间件,它将在请求期间将所有上下文信息添加到当前LogContext

For it to work you must configure your logger with为了让它工作,你必须配置你的记录器

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

This article by Nicholas Blumhardt may also help : https://blog.getseq.net/smart-logging-middleware-for-asp-net-core/ Nicholas Blumhardt 的这篇文章也可能有所帮助: https : //blog.getseq.net/smart-logging-middleware-for-asp-net-core/


WARNING - Solution below does not work in this case警告 - 下面的解决方案在这种情况下不起作用

The solution below cannot work if the logger is registered early (in Program.Main() )如果记录器提前注册(在 Program.Main() 中),下面的解决方案将无法工作

First of all, if you want to add extra information attached to the logged event, I believe what you want is an Enricher .首先,如果你想添加附加到记录事件的额外信息,我相信你想要的是一个Enricher

You could then :然后你可以:

  • Register IHttpContextAccessor into your ServiceCollection (for instance, using AddHttpContextAccessor() ) : services.AddHttpContextAccessor();IHttpContextAccessor注册到您的 ServiceCollection(例如,使用AddHttpContextAccessor() ): services.AddHttpContextAccessor();
  • Create an implementation of ILogEventEnricher that accepts IHttpContextAccessor in its constructor创建在其构造函数中接受IHttpContextAccessorILogEventEnricher的实现
  • When configuring your logger, inject IHttpContextAccessor (by adding an argument of type IHttpContextAccessor to Startup.Configure()配置记录器时,注入IHttpContextAccessor (通过将IHttpContextAccessor类型的参数添加到Startup.Configure()
  • Add this enricher to your logger将此丰富器添加到您的记录器

The enricher could look something like https://github.com/serilog-web/classic/blob/master/src/SerilogWeb.Classic/Classic/Enrichers/ClaimValueEnricher.cs .浓缩器可能看起来像https://github.com/serilog-web/classic/blob/master/src/SerilogWeb.Classic/Classic/Enrichers/ClaimValueEnricher.cs

And you would configure your logger like this :你会像这样配置你的记录器:

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

I have been struggling trying to do the same and I finally found a proper solution.我一直在努力尝试做同样的事情,我终于找到了一个合适的解决方案。

Do not add the enricher when creating the Logger.创建 Logger 时不要添加丰富器。 You will have to add the enricher in the middleware where you can access the IServiceProvider .您必须在中间件中添加丰富器,您可以在其中访问IServiceProvider The key is that LogContext has a method, Push , that can add an enricher:关键是LogContext有一个方法Push ,可以添加一个丰富器:

public async Task Invoke(HttpContext httpContext)
{
    IServiceProvider serviceProvider = httpContext.RequestServices;
    using (LogContext.Push(new LogEnricher(serviceProvider))) {
        await _next(httpContext);
    }
}

In the ConfigureServices , I add a services.AddScoped<HttpContextToLog>() call.ConfigureServices ,我添加了services.AddScoped<HttpContextToLog>()调用。

Then, I populate the HttpContextToLog object in several places, accessing it like this:然后,我在几个地方填充HttpContextToLog对象,像这样访问它:

HttpContextToLog contextToLog = _serviceProvider.GetService<HttpContextToLog>();

in the Enrich method, in an IActionFilter , in an IPageFilter , etc.Enrich方法中,在IActionFilter ,在IPageFilter ,等等。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何将自定义列添加到我的 Serilog MS SQL Server 接收器? - How can I add a custom column to my Serilog MS SQL Server sink? 如何将完整的对象添加到 Serilog Azure Tablestorage 接收器,该对象未在消息中写出? - How can I add a complete object to Serilog Azure Tablestorage sink, which is not written out in the message? 我可以从HttpContext获取当前正在执行的控制器吗? - Can I get the current executing controller from HttpContext? 如何在不使用HttpContext的情况下获取Web应用程序的当前配置? - How can I get current config of the web application without using HttpContext? 如何获取超过1000个html控件值的HttpContext.Current.Request? - how can i get HttpContext.Current.Request of more than 1000 html controls value? 如何配置 Serilog 接收器以记录到 CloudWatch - How to configure a Serilog sink for logging to CloudWatch 如何使用Serilog RollingFile接收器启用多个文件? - How to enable multiple files with Serilog RollingFile sink? 使用 Microsoft 的 ILogger 时,如何将 scope 包含在 Serilog 的控制台接收器中? - How do I include scope with Serilog's console sink when using Microsoft's ILogger? serilog 中的 Amazon S3 接收器不工作。 如何将 s3 Sink 与 serilog 一起使用? - Amazon S3 sink in serilog is not working. How to use s3 Sink with serilog? 我如何在不使用httpcontext.current的情况下获取域URL - How do i get domain url without using httpcontext.current
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM