如何在SeriLog接收器中获取当前的HttpContext?

加文·萨瑟兰

我正在ILogEventSink使用“构建一个简单的接收器”示例创建自己的SeriLog接收器,以记录用户声明中的某些信息。为了访问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));
    }
}

...然后使用水槽...

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

如何在接收器的Emit方法中访问当前的HttpContext?还是可以通过DI框架创建接收器?

我有一个MVC站点,使用Serilog.AspNetCore v2.1.0针对.Net 4.6.2运行时运行Asp.Net Core 2框架。

更新-解决方法

在@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;
    }
}
滕巴拉尔

更新我认为您可能想看一下这篇文章:http : //mylifeforthecode.github.io/enriching-serilog-output-with-httpcontext-information-in-asp-net-core/

这个想法是注册一个自定义的中间件,该中间件会将所有上下文信息添加LogContext请求期间的当前信息中

为了使其正常工作,您必须使用以下命令配置记录器

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

Nicholas Blumhardt的这篇文章可能也有帮助:https : //blog.getseq.net/smart-logging-middleware-for-asp-net-core/


警告-以下解决方案在这种情况下不起作用

如果记录器过早注册(在Program.Main()中),则以下解决方案将不起作用

首先,如果您想添加附加信息到记录的事件中,我相信您想要的是一个Enricher

然后,您可以:

  • IHttpContextAccessor注册到您的ServiceCollection中(例如,使用AddHttpContextAccessor()):services.AddHttpContextAccessor();
  • 创建在其构造函数ILogEventEnricher中接受的实现IHttpContextAccessor
  • 配置记录器时,注入IHttpContextAccessor(通过将type参数添加IHttpContextAccessorStartup.Configure()
  • 将此浓缩器添加到记录器中

富集可能看起来像https://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();

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

如何在Oreo中为媒体按钮注册广播接收器?

如何在Go中通过指针接收器方法修改简单类型的值?

我如何在广播接收器中检测运动传感器?

Serilog电子邮件接收器

如何在下载接收器中访问本地文件名?

如何在Apache Flink中并行写入接收器

如何从Zeppelin中的控制台流接收器获取输出?

如何在广播接收器内设置警报

如何向我的Serilog MS SQL Server接收器添加自定义列?

如何使用Serilog RollingFile接收器启用多个文件?

如何向Serilog Azure Tablestorage接收器添加一个完整的对象,该对象未在消息中写出?

如何在freeRTOS中向多接收器发送队列消息?

如何在Kotlin中使用接收器创建Lambda

如何在flutter插件中使用接收器(BroadcastReceiver)?

如何在Android中注销广播接收器

如何在Windows Phone中实现Android广播接收器的编程方式

如何在广播接收器的帮助下获取相机单击事件?

Android:当闹钟响起时,如何在闹钟接收器中获取requestCode

如何在服务中使用广播接收器

如何在广播接收器中启动服务?

如何为Serilog.Sinks.MongDB接收器指定集合

如何在接收器中使用<intent-filter>

如何在服务和广播接收器中检测关键事件

如何在 Flume 1.7 中编写自定义 ES 接收器

广播接收器如何在活动之间工作?

如何在作为输入接收器的 onCreate() 中解决“非静态 vs 静态”问题

如何在广播接收器中访问 MyViewModel(AndroidViewModel)

如何在 Azure 数据工厂接收器中添加“文本限定符”

Serilog EventLog 接收器不记录