在.Net Core 2.2 API中,我尝试使用Serilog记录到SQL Server,以利用其结构化记录功能。除了标准字段(ID,时间戳,级别,消息,MessageTemplate,LogEvent)外,我还需要在每个日志条目中捕获用户名和IP地址。我见过this post,但我想在一个地方做,所以开发人员不必在每个日志语句中手动添加它。我的Startup.cs
ctor中有以下代码段:
public Startup(IConfiguration configuration)
{
_configuration = configuration;
Log.Logger = new LoggerConfiguration()
.ReadFrom.Configuration(configuration)
.Enrich.FromLogContext()
.Enrich.With<SerilogContextEnricher>()
.CreateLogger();
}
.Enrich.FromLogContext()
调用使我可以使用静态LogContext在自定义中间件中添加自定义属性(用户名和IP地址),如下所示:
public class SerilogMiddleware
{
private static readonly ILogger Log = Serilog.Log.ForContext<SerilogMiddleware>();
private readonly RequestDelegate _next;
public SerilogMiddleware(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 user info
var user = httpContext.User.FindFirst(ClaimTypes.Name)?.Value ?? "anonymous";
// Get client info
var client = httpContext.Connection.RemoteIpAddress.ToString() ?? "unknown";
// enrich LogContext with user info
using (LogContext.PushProperty("User", user))
using (LogContext.PushProperty("Client", client))
{
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;
}
}
但是,.Enrich.FromLogContext()
调用还将ActionId,ActionName,RequestId,RequestPath和CorrelationId属性添加到LogEvent字段。我不想使用这5个属性来夸大我的日志表。我当前的解决方案是使用下面的自定义功能丰富功能来丰富我的记录器,该功能将从EventLog中删除这些属性。
public class SerilogContextEnricher : ILogEventEnricher
{
public void Enrich(LogEvent logEvent, ILogEventPropertyFactory propertyFactory)
{
logEvent.RemovePropertyIfPresent("ActionId");
logEvent.RemovePropertyIfPresent("ActionName");
logEvent.RemovePropertyIfPresent("RequestId");
logEvent.RemovePropertyIfPresent("RequestPath");
logEvent.RemovePropertyIfPresent("CorrelationId");
}
}
这一切都很好,但是最初将这些属性添加到记录器,然后再将其删除似乎很愚蠢。有谁知道一种无需添加或删除不需要的属性就可以将自定义属性普遍推入所有日志条目的方法吗?