如何让 serilog enricher 在启动时使用依赖注入?
How do I get a serilog enricher to work with dependency injection while keeping it on startup?
这里有一个答案: 这说明你可以传入一个实例。
但是要做到这一点,我需要在我的依赖注入代码具有 运行(在 startup.cs
)
之后移动我的记录器设置
这意味着不会记录启动错误,因为记录器还没有准备好。
有没有办法在我的 Main()
方法中以某种方式将 serilog 配置为 运行,同时还使用 DI 项丰富数据? DI 项虽然是单例,但有进一步的依赖(主要是数据库连接)。
我用谷歌搜索了这个并阅读了一些关于向上下文添加内容的内容,但我一直无法找到一个我可以适应的完整工作示例。
我发现的大多数示例都涉及将代码放入控制器以附加信息,但我希望它对每个日志条目都全局可用。
我的主要以 :
开头
Log.Logger = new LoggerConfiguration()
.Enrich.FromLogContext()
.WriteTo.Elasticsearch(new ElasticsearchSinkOptions(new Uri(elasticUri))
{
AutoRegisterTemplate = true,
})
.CreateLogger();
进入 .NET Core MVC 代码之前
CreateWebHostBuilder(args).Build().Run();
我的 DI 对象基本上是一个 "UserData" class,其中包含用户名、公司 ID 等,这些是在访问时访问数据库以获取基于某些当前身份的值的属性(没有'尚未实施)。它被我的 DI 注册为单例。
我建议使用插入到 ASP .NET Core 管道中的简单中间件,使用所需的依赖项来丰富 Serilog 的 LogContext,让ASP .NET Core 依赖注入为您解决依赖...
例如假设 IUserDataService
是一个服务,你可以用它来获取你需要的数据,丰富日志,中间件看起来像这样:
public class UserDataLoggingMiddleware
{
private readonly RequestDelegate _next;
public UserDataLoggingMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task Invoke(HttpContext context, IUserDataService userDataService)
{
var userData = await userDataService.GetAsync();
// Add user data to logging context
using (LogContext.PushProperty("UserData", userData))
{
await _next.Invoke(context);
}
}
}
上面的LogContext.PushProperty
是在做充实,在当前执行的日志上下文中添加了一个叫做UserData
的属性。
ASP .NET Core 负责解析 IUserDataService
只要您在 Startup.ConfigureServices
.
中注册它
当然,要实现这一点,您必须:
1。通过调用 Enrich.FromLogContext()
告诉 Serilog 从日志上下文丰富日志。例如
Log.Logger = new LoggerConfiguration()
.ReadFrom.Configuration(Configuration)
.Enrich.FromLogContext() // <<======================
.WriteTo.Console(
outputTemplate: "[{Timestamp:HH:mm:ss} {Level:u3}] {Message:lj} " +
"{Properties:j}{NewLine}{Exception}")
.CreateLogger();
2。在 Startup.Configure
中将中间件添加到管道中。例如
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
// ...
app.UseMiddleware<UserDataLoggingMiddleware>();
// ...
app.UseMvc();
}
对已接受的答案稍作改进是使用 ILogger.BeginScope
而不是静态 Serilog LogContext.PushProperty
。它与字典一起变得有点丑陋,但仍然是一个改进,并且与记录器无关。
public async Task Invoke(HttpContext context, IUserDataService userDataService, ILogger<UserDataLoggingMiddleware> logger)
{
var userData = await userDataService.GetAsync();
// Add user data to logging context
using (logger.BeginScope(new Dictionary<string, object> { ["UserData"] = userData }))
{
await _next.Invoke(context);
}
}
UseSerilog
有几个覆盖,其中有一个带有 lambda 的覆盖,它接受 3 个参数,包括 IServiceProvider
.
它可用于动态注入一个对象,这将在 ctor 中使用 IServiceProvider
并使用 GetService
来查找每个 Log()
操作所需的上下文。
这里有一个答案:
但是要做到这一点,我需要在我的依赖注入代码具有 运行(在 startup.cs
)
这意味着不会记录启动错误,因为记录器还没有准备好。
有没有办法在我的 Main()
方法中以某种方式将 serilog 配置为 运行,同时还使用 DI 项丰富数据? DI 项虽然是单例,但有进一步的依赖(主要是数据库连接)。
我用谷歌搜索了这个并阅读了一些关于向上下文添加内容的内容,但我一直无法找到一个我可以适应的完整工作示例。
我发现的大多数示例都涉及将代码放入控制器以附加信息,但我希望它对每个日志条目都全局可用。
我的主要以 :
开头Log.Logger = new LoggerConfiguration()
.Enrich.FromLogContext()
.WriteTo.Elasticsearch(new ElasticsearchSinkOptions(new Uri(elasticUri))
{
AutoRegisterTemplate = true,
})
.CreateLogger();
进入 .NET Core MVC 代码之前
CreateWebHostBuilder(args).Build().Run();
我的 DI 对象基本上是一个 "UserData" class,其中包含用户名、公司 ID 等,这些是在访问时访问数据库以获取基于某些当前身份的值的属性(没有'尚未实施)。它被我的 DI 注册为单例。
我建议使用插入到 ASP .NET Core 管道中的简单中间件,使用所需的依赖项来丰富 Serilog 的 LogContext,让ASP .NET Core 依赖注入为您解决依赖...
例如假设 IUserDataService
是一个服务,你可以用它来获取你需要的数据,丰富日志,中间件看起来像这样:
public class UserDataLoggingMiddleware
{
private readonly RequestDelegate _next;
public UserDataLoggingMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task Invoke(HttpContext context, IUserDataService userDataService)
{
var userData = await userDataService.GetAsync();
// Add user data to logging context
using (LogContext.PushProperty("UserData", userData))
{
await _next.Invoke(context);
}
}
}
上面的LogContext.PushProperty
是在做充实,在当前执行的日志上下文中添加了一个叫做UserData
的属性。
ASP .NET Core 负责解析 IUserDataService
只要您在 Startup.ConfigureServices
.
当然,要实现这一点,您必须:
1。通过调用 Enrich.FromLogContext()
告诉 Serilog 从日志上下文丰富日志。例如
Log.Logger = new LoggerConfiguration()
.ReadFrom.Configuration(Configuration)
.Enrich.FromLogContext() // <<======================
.WriteTo.Console(
outputTemplate: "[{Timestamp:HH:mm:ss} {Level:u3}] {Message:lj} " +
"{Properties:j}{NewLine}{Exception}")
.CreateLogger();
2。在 Startup.Configure
中将中间件添加到管道中。例如
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
// ...
app.UseMiddleware<UserDataLoggingMiddleware>();
// ...
app.UseMvc();
}
对已接受的答案稍作改进是使用 ILogger.BeginScope
而不是静态 Serilog LogContext.PushProperty
。它与字典一起变得有点丑陋,但仍然是一个改进,并且与记录器无关。
public async Task Invoke(HttpContext context, IUserDataService userDataService, ILogger<UserDataLoggingMiddleware> logger)
{
var userData = await userDataService.GetAsync();
// Add user data to logging context
using (logger.BeginScope(new Dictionary<string, object> { ["UserData"] = userData }))
{
await _next.Invoke(context);
}
}
UseSerilog
有几个覆盖,其中有一个带有 lambda 的覆盖,它接受 3 个参数,包括 IServiceProvider
.
它可用于动态注入一个对象,这将在 ctor 中使用 IServiceProvider
并使用 GetService
来查找每个 Log()
操作所需的上下文。