[英]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 :然后你可以:
AddHttpContextAccessor()
) : services.AddHttpContextAccessor();
将IHttpContextAccessor注册到您的 ServiceCollection(例如,使用AddHttpContextAccessor()
): services.AddHttpContextAccessor();
ILogEventEnricher
that accepts IHttpContextAccessor
in its constructor创建在其构造函数中接受IHttpContextAccessor
的ILogEventEnricher
的实现IHttpContextAccessor
(by adding an argument of type IHttpContextAccessor
to Startup.Configure()
配置记录器时,注入IHttpContextAccessor
(通过将IHttpContextAccessor
类型的参数添加到Startup.Configure()
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.