我正在创建自己的SeriLog接收器,使用构建简单接收器示例实现ILogEventSink
,旨在记录来自用户声明的一些信息。要在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 框架创建 sink?
我有一个运行 Asp.Net Core 2 框架、使用 .Net 4.6.2 运行时和 Serilog.AspNetCore v2.1.0 的 MVC 站点。
更新 - 解决方法
在 @tsimbalar 的提示下,我创建了类似以下代码的中间件。在我的 StartUp.Configure 方法中,我使用 app.UseMiddleware(); 在应用程序身份验证步骤之后添加它(否则将不会加载任何声明)。
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;
}
}
contextAccessor
传递给MyEnricher
对象的实例。这不是使用依赖注入,那么如果我在程序主方法中配置日志记录,而在启动(以及ConfigureServices
)调用之前,我将如何获取上下文呢? - Gavin Sutherland