根据上下文源将 Serilog 日志过滤到不同的接收器?
Filter Serilog logs to different sinks depending on context source?
我有一个 .NET Core 2.0 应用程序,我在其中成功使用 Serilog 进行日志记录。现在,我想将一些数据库性能统计信息记录到一个单独的接收器(它们不是用于调试,这基本上是应用程序中所有其他日志记录的目的,所以我想将它们分开)并认为这可以完成通过使用 Log.ForContext<MyClass>()
.
创建数据库统计记录器
我不知道我应该如何配置 Serilog 使用我的 appsettings.json 将我的 "debug logs" 记录到一个接收器并将我的数据库统计信息记录到其他?我希望可以做类似的事情:
"Serilog": {
"WriteTo": [
{
"Name": "RollingFile",
"pathFormat": "logs/Log-{Date}.log",
"Filter": {
"ByExcluding": "FromSource(MyClass)"
}
},
{
"Name": "RollingFile",
"pathFormat": "logs/DBStat-{Date}.log",
"Filter": {
"ByIncludingOnly": "FromSource(MyClass)"
}
}
]
}
配置的 "Filter"
部分纯属我的猜测。这可能使用我的配置文件管理器还是我需要在我的 Startup.cs
文件中的代码中执行此操作?
编辑:我已经使用 C# API 让它工作,但仍然想使用 JSON 配置来解决它:
Log.Logger = new LoggerConfiguration()
.WriteTo.Logger(lc => lc
.Filter.ByExcluding(Matching.FromSource<MyClass>())
.WriteTo.LiterateConsole())
.WriteTo.Logger(lc => lc
.Filter.ByExcluding(Matching.FromSource<MyClass>())
.WriteTo.RollingFile("logs/DebugLog-{Date}.log"))
.WriteTo.Logger(lc => lc
.Filter.ByIncludingOnly(Matching.FromSource<MyClass>())
.WriteTo.RollingFile("logs/DBStats-{Date}.log", outputTemplate: "{Message}{NewLine}"))
.CreateLogger();
我今天完成了这项工作,我认为我会提供一个正确的答案,因为我花了很多帖子、问题和其他页面来解决这个问题。
拥有所有日志很有用,但我也只想单独记录我的 API 代码,而忽略 Microsoft.
命名空间日志。 JSON 配置看起来像这样:
"Serilog": {
"Using": [ "Serilog.Sinks.File" ],
"MinimumLevel": "Debug",
"WriteTo": [
{
"Name": "File",
"Args": {
"path": "/var/logs/system.log",
... //other unrelated file config
}
},
{
"Name": "Logger",
"Args": {
"configureLogger": {
"WriteTo": [
{
"Name": "File",
"Args": {
"path": "/var/logs/api.log",
... //other unrelated file config
}
}
],
"Filter": [
{
"Name": "ByExcluding",
"Args": {
"expression": "StartsWith(SourceContext, 'Microsoft.')"
}
}
]
}
}
}
],
"Enrich": [ "FromLogContext", "WithMachineName", "WithThreadId" ]
... //Destructure and other config
}
顶级 WriteTo
是第一个简单的全局接收器。所有日志事件都写入此。如果您在与此相同的级别上添加 Filter
部分,它将影响所有已配置的 WriteTo
元素。
然后我将另一个 WriteTo
配置为 Logger
(不是 File
),但是 Args
看起来不同并且有一个 configureLogger
元素与顶层的Serilog
作用相同,即子logger的顶层。这意味着您可以轻松地将此配置拆分到一个单独的文件中,并将其另外添加到配置构建器中(见底部)。
从这里开始,这个子记录器的工作方式是一样的:你可以配置多个WriteTo
s,这个级别的Filter
元素只会影响这个子记录器。
只需将更多 "Name": "Logger"
元素添加到顶层 WriteTo
部分并分别为每个元素设置过滤器。
备注
同样重要的是要注意,即使您是在配置中执行所有这些操作并且没有在代码中引用任何 Serilog.Filters.Expressions
包,您仍然必须添加对该包的 NuGet 引用。 没有包引用就无法工作。
关于拆分配置:
如果我必须添加更多记录器,为了清楚起见,我肯定会将不同的记录器拆分到单独的文件中,例如
appsettings.json:
"Serilog": {
"Using": [ "Serilog.Sinks.File" ],
"MinimumLevel": "Error",
"WriteTo": [
{
"Name": "File",
"Args": {
"path": "/var/logs/system.log",
...
}
},
{
"Name": "Logger",
"Args": {
"configureLogger": {} // leave this empty
}
}
],
"Enrich": [ "FromLogContext", "WithMachineName", "WithThreadId" ],
...
apilogger.json:
{
"Serilog:WriteTo:1:Args:configureLogger": { //notice this key
"WriteTo": [
{
"Name": "File",
"Args": {
"path": "/var/logs/api_separateFile.log",
...
}
}
],
"Filter": [
{
"Name": "ByExcluding",
"Args": {
"expression": "StartsWith(SourceContext, 'Microsoft.')"
}
}
]
}
}
然后调整我的 IWebHost
构建器以包含额外的配置:
WebHost.CreateDefaultBuilder(args)
.ConfigureAppConfiguration((hostingContext, config) =>
{
config.AddJsonFile("apilogger.json", optional: false, reloadOnChange: false);
})
.UseStartup<Startup>();
这样更容易理解、阅读和维护。
仅将 entityframework 日志写入文件如下,但我们需要安装 Serilog.Filters.Expressions nuget 包
"Serilog": {
"MinimumLevel": {
"Default": "Debug",
"Override": {
"Microsoft": "Warning",
"System": "Warning",
"Microsoft.EntityFrameworkCore": "Information"
}
},
"WriteTo": [
{
"Name": "Logger",
"Args": {
"configureLogger": {
"Filter": [
{
"Name": "ByIncludingOnly",
"Args": {
"expression": "StartsWith(SourceContext, 'Microsoft.EntityFrameworkCore')"
}
}
],
"WriteTo": [
{
"Name": "File",
"Args": {
"path": "C:\LOGS\TestService_EF_.json",
"outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level:u3}] {Message:lj}{NewLine}{Exception}",
"rollingInterval": "Day",
"retainedFileCountLimit": 7
}
}
]
}
}
}
]
}
我不得不做类似的事情,但在代码中,而不是 JSON。使用记录器作为接收器,如 https://github.com/serilog/serilog/wiki/Configuration-Basics 底部所述,成功了。
在我的例子中,我想将所有内容记录到文件和控制台,除了来自特定来源的消息应该只发送到文件:
private static bool SourceContextEquals(LogEvent logEvent, Type sourceContext)
=> logEvent.Properties.GetValueOrDefault("SourceContext") is ScalarValue sv && sv.Value?.ToString() == sourceContext.FullName;
private static ILogger CreateLogger() =>
new LoggerConfiguration()
.WriteTo.File("mylog.log")
.WriteTo.Logger(lc =>
lc.Filter.ByExcluding(le => SourceContextEquals(le, typeof(TypeThatShouldLogOnlyToFile)))
.WriteTo.Console()
)
.CreateLogger();
我有一个 .NET Core 2.0 应用程序,我在其中成功使用 Serilog 进行日志记录。现在,我想将一些数据库性能统计信息记录到一个单独的接收器(它们不是用于调试,这基本上是应用程序中所有其他日志记录的目的,所以我想将它们分开)并认为这可以完成通过使用 Log.ForContext<MyClass>()
.
我不知道我应该如何配置 Serilog 使用我的 appsettings.json 将我的 "debug logs" 记录到一个接收器并将我的数据库统计信息记录到其他?我希望可以做类似的事情:
"Serilog": {
"WriteTo": [
{
"Name": "RollingFile",
"pathFormat": "logs/Log-{Date}.log",
"Filter": {
"ByExcluding": "FromSource(MyClass)"
}
},
{
"Name": "RollingFile",
"pathFormat": "logs/DBStat-{Date}.log",
"Filter": {
"ByIncludingOnly": "FromSource(MyClass)"
}
}
]
}
配置的 "Filter"
部分纯属我的猜测。这可能使用我的配置文件管理器还是我需要在我的 Startup.cs
文件中的代码中执行此操作?
编辑:我已经使用 C# API 让它工作,但仍然想使用 JSON 配置来解决它:
Log.Logger = new LoggerConfiguration()
.WriteTo.Logger(lc => lc
.Filter.ByExcluding(Matching.FromSource<MyClass>())
.WriteTo.LiterateConsole())
.WriteTo.Logger(lc => lc
.Filter.ByExcluding(Matching.FromSource<MyClass>())
.WriteTo.RollingFile("logs/DebugLog-{Date}.log"))
.WriteTo.Logger(lc => lc
.Filter.ByIncludingOnly(Matching.FromSource<MyClass>())
.WriteTo.RollingFile("logs/DBStats-{Date}.log", outputTemplate: "{Message}{NewLine}"))
.CreateLogger();
我今天完成了这项工作,我认为我会提供一个正确的答案,因为我花了很多帖子、问题和其他页面来解决这个问题。
拥有所有日志很有用,但我也只想单独记录我的 API 代码,而忽略 Microsoft.
命名空间日志。 JSON 配置看起来像这样:
"Serilog": {
"Using": [ "Serilog.Sinks.File" ],
"MinimumLevel": "Debug",
"WriteTo": [
{
"Name": "File",
"Args": {
"path": "/var/logs/system.log",
... //other unrelated file config
}
},
{
"Name": "Logger",
"Args": {
"configureLogger": {
"WriteTo": [
{
"Name": "File",
"Args": {
"path": "/var/logs/api.log",
... //other unrelated file config
}
}
],
"Filter": [
{
"Name": "ByExcluding",
"Args": {
"expression": "StartsWith(SourceContext, 'Microsoft.')"
}
}
]
}
}
}
],
"Enrich": [ "FromLogContext", "WithMachineName", "WithThreadId" ]
... //Destructure and other config
}
顶级 WriteTo
是第一个简单的全局接收器。所有日志事件都写入此。如果您在与此相同的级别上添加 Filter
部分,它将影响所有已配置的 WriteTo
元素。
然后我将另一个 WriteTo
配置为 Logger
(不是 File
),但是 Args
看起来不同并且有一个 configureLogger
元素与顶层的Serilog
作用相同,即子logger的顶层。这意味着您可以轻松地将此配置拆分到一个单独的文件中,并将其另外添加到配置构建器中(见底部)。
从这里开始,这个子记录器的工作方式是一样的:你可以配置多个WriteTo
s,这个级别的Filter
元素只会影响这个子记录器。
只需将更多 "Name": "Logger"
元素添加到顶层 WriteTo
部分并分别为每个元素设置过滤器。
备注
同样重要的是要注意,即使您是在配置中执行所有这些操作并且没有在代码中引用任何 Serilog.Filters.Expressions
包,您仍然必须添加对该包的 NuGet 引用。 没有包引用就无法工作。
关于拆分配置:
如果我必须添加更多记录器,为了清楚起见,我肯定会将不同的记录器拆分到单独的文件中,例如
appsettings.json:
"Serilog": {
"Using": [ "Serilog.Sinks.File" ],
"MinimumLevel": "Error",
"WriteTo": [
{
"Name": "File",
"Args": {
"path": "/var/logs/system.log",
...
}
},
{
"Name": "Logger",
"Args": {
"configureLogger": {} // leave this empty
}
}
],
"Enrich": [ "FromLogContext", "WithMachineName", "WithThreadId" ],
...
apilogger.json:
{
"Serilog:WriteTo:1:Args:configureLogger": { //notice this key
"WriteTo": [
{
"Name": "File",
"Args": {
"path": "/var/logs/api_separateFile.log",
...
}
}
],
"Filter": [
{
"Name": "ByExcluding",
"Args": {
"expression": "StartsWith(SourceContext, 'Microsoft.')"
}
}
]
}
}
然后调整我的 IWebHost
构建器以包含额外的配置:
WebHost.CreateDefaultBuilder(args)
.ConfigureAppConfiguration((hostingContext, config) =>
{
config.AddJsonFile("apilogger.json", optional: false, reloadOnChange: false);
})
.UseStartup<Startup>();
这样更容易理解、阅读和维护。
仅将 entityframework 日志写入文件如下,但我们需要安装 Serilog.Filters.Expressions nuget 包
"Serilog": {
"MinimumLevel": {
"Default": "Debug",
"Override": {
"Microsoft": "Warning",
"System": "Warning",
"Microsoft.EntityFrameworkCore": "Information"
}
},
"WriteTo": [
{
"Name": "Logger",
"Args": {
"configureLogger": {
"Filter": [
{
"Name": "ByIncludingOnly",
"Args": {
"expression": "StartsWith(SourceContext, 'Microsoft.EntityFrameworkCore')"
}
}
],
"WriteTo": [
{
"Name": "File",
"Args": {
"path": "C:\LOGS\TestService_EF_.json",
"outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level:u3}] {Message:lj}{NewLine}{Exception}",
"rollingInterval": "Day",
"retainedFileCountLimit": 7
}
}
]
}
}
}
]
}
我不得不做类似的事情,但在代码中,而不是 JSON。使用记录器作为接收器,如 https://github.com/serilog/serilog/wiki/Configuration-Basics 底部所述,成功了。
在我的例子中,我想将所有内容记录到文件和控制台,除了来自特定来源的消息应该只发送到文件:
private static bool SourceContextEquals(LogEvent logEvent, Type sourceContext)
=> logEvent.Properties.GetValueOrDefault("SourceContext") is ScalarValue sv && sv.Value?.ToString() == sourceContext.FullName;
private static ILogger CreateLogger() =>
new LoggerConfiguration()
.WriteTo.File("mylog.log")
.WriteTo.Logger(lc =>
lc.Filter.ByExcluding(le => SourceContextEquals(le, typeof(TypeThatShouldLogOnlyToFile)))
.WriteTo.Console()
)
.CreateLogger();