BeginScope 与 Serilog
BeginScope with Serilog
我想直接使用 Microsoft.Logger
在 Serilog 上的功能,即 BeginScope
功能。
我知道我可以使用 Microsoft ILogger
并将 Serilog 设置为底层记录器,但在应用程序的这一点上太麻烦了。
我想知道 Serilog 中是否有 BeginScope
等价物。
互联网上的信息并不直接,有提到 Serilog 支持,但没有提到直接支持或使用 Microsoft 类。
是的,Serilog 具有此功能的本机等效项,称为使用 LogContext.PushProperty()
。
要启用此功能,您首先必须将 Enrich.FromLogContext()
添加到您的 Serilog LoggerConfiguration
,例如:
Log.Logger = new LoggerConfiguration()
.Enrich.FromLogContext() // <- this line
.WriteTo.Console(outputTemplate: "[{Timestamp:HH:mm:ss} {Level:u3}] {Message:lj} " +
"{Properties:j}{NewLine}{Exception}"))
.CreateLogger();
然后,要将属性推送到上下文(相当于 ILogger.BeginScope()
),请使用:
using (LogContext.PushProperty("OrderId", 1234))
{
Log.Information("Processing a new order");
// ...etc
}
上面的配置包括 {Properties:j}
以确保所有事件属性(例如来自日志上下文的属性)都包含在输出中。您查看附加属性的方式取决于您使用的接收器。
@Nicholas 的回答是正确的。我只是想为任何其他来到此线程的人提供一个小的工作示例,以指出一些不太明显的事情;
这里有一些示例代码,展示了如何使用 Serilog 上下文;
void Main()
{
var log = Log.Logger = new LoggerConfiguration()
.Enrich.FromLogContext()
.MinimumLevel.Information()
.WriteTo.Console()
.CreateLogger();
Log.Logger = log;
log.Information("Starting app");
Task.WaitAll(
Task.Run (() => GetNums(10,15, 2, "evens")),
Task.Run (() => GetNums(11, 15, 2, "odds"))
);
log.Information("Finished.");
Console.ReadLine();
}
static Random R = new Random();
static void GetNums(int start, int cnt, int inc, string name)
{
using(var log = LogContext.PushProperty("name", name))
{
for (int i = start; i < start + cnt; i+=inc)
{
Log.Information("{number},{name}", i);
Thread.Sleep(R.Next(500));
}
}
}
产生这个输出
[17:11:31 INF] Starting app
[17:11:31 INF] 10,evens
[17:11:31 INF] 11,odds
[17:11:31 INF] 12,evens
[17:11:31 INF] 14,evens
[17:11:32 INF] 13,odds
[17:11:32 INF] 16,evens
[17:11:32 INF] 15,odds
[17:11:32 INF] 18,evens
[17:11:32 INF] 20,evens
[17:11:32 INF] 17,odds
[17:11:32 INF] 22,evens
[17:11:33 INF] 24,evens
[17:11:33 INF] 19,odds
[17:11:33 INF] 21,odds
[17:11:34 INF] 23,odds
[17:11:34 INF] 25,odds
[17:11:34 INF] Finished.
我想指出的是,如果命名值没有出现在您的模板中,记录到上下文的项目将不会出现在日志中(即不会被记录)。
例如,在上面的代码中,如果我们将 Log.Information("{number},{name}",i);
更改为 Log.Information("{number}",i);
那么这就是您将得到的结果,这与您不配置时可能得到的结果类似充实Enrich.FromLogContext()
。忘记更新模板并追尾试图找到错误是微妙而容易的。
不包含上下文中包含的命名属性的模板字符串
[17:22:11 INF] Starting app
[17:22:11 INF] 10
[17:22:11 INF] 11
[17:22:11 INF] 12
[17:22:11 INF] 13
[17:22:11 INF] 15
[17:22:11 INF] 17
[17:22:12 INF] 14
[17:22:12 INF] 16
[17:22:12 INF] 19
[17:22:12 INF] 18
[17:22:12 INF] 20
[17:22:12 INF] 21
[17:22:12 INF] 23
[17:22:12 INF] 22
[17:22:12 INF] 24
[17:22:13 INF] 25
[17:22:13 INF] Finished.
此外,丰富的属性 appended
到字符串的末尾,所以
Log.Information("{name},{number}", i);
会产生
[17:35:11 INF] Starting app
[17:35:11 INF] 11,{number}
[17:35:11 INF] 10,{number}
登录愉快!希望这对您有所帮助。
我想直接使用 Microsoft.Logger
在 Serilog 上的功能,即 BeginScope
功能。
我知道我可以使用 Microsoft ILogger
并将 Serilog 设置为底层记录器,但在应用程序的这一点上太麻烦了。
我想知道 Serilog 中是否有 BeginScope
等价物。
互联网上的信息并不直接,有提到 Serilog 支持,但没有提到直接支持或使用 Microsoft 类。
是的,Serilog 具有此功能的本机等效项,称为使用 LogContext.PushProperty()
。
要启用此功能,您首先必须将 Enrich.FromLogContext()
添加到您的 Serilog LoggerConfiguration
,例如:
Log.Logger = new LoggerConfiguration()
.Enrich.FromLogContext() // <- this line
.WriteTo.Console(outputTemplate: "[{Timestamp:HH:mm:ss} {Level:u3}] {Message:lj} " +
"{Properties:j}{NewLine}{Exception}"))
.CreateLogger();
然后,要将属性推送到上下文(相当于 ILogger.BeginScope()
),请使用:
using (LogContext.PushProperty("OrderId", 1234))
{
Log.Information("Processing a new order");
// ...etc
}
上面的配置包括 {Properties:j}
以确保所有事件属性(例如来自日志上下文的属性)都包含在输出中。您查看附加属性的方式取决于您使用的接收器。
@Nicholas 的回答是正确的。我只是想为任何其他来到此线程的人提供一个小的工作示例,以指出一些不太明显的事情;
这里有一些示例代码,展示了如何使用 Serilog 上下文;
void Main()
{
var log = Log.Logger = new LoggerConfiguration()
.Enrich.FromLogContext()
.MinimumLevel.Information()
.WriteTo.Console()
.CreateLogger();
Log.Logger = log;
log.Information("Starting app");
Task.WaitAll(
Task.Run (() => GetNums(10,15, 2, "evens")),
Task.Run (() => GetNums(11, 15, 2, "odds"))
);
log.Information("Finished.");
Console.ReadLine();
}
static Random R = new Random();
static void GetNums(int start, int cnt, int inc, string name)
{
using(var log = LogContext.PushProperty("name", name))
{
for (int i = start; i < start + cnt; i+=inc)
{
Log.Information("{number},{name}", i);
Thread.Sleep(R.Next(500));
}
}
}
产生这个输出
[17:11:31 INF] Starting app
[17:11:31 INF] 10,evens
[17:11:31 INF] 11,odds
[17:11:31 INF] 12,evens
[17:11:31 INF] 14,evens
[17:11:32 INF] 13,odds
[17:11:32 INF] 16,evens
[17:11:32 INF] 15,odds
[17:11:32 INF] 18,evens
[17:11:32 INF] 20,evens
[17:11:32 INF] 17,odds
[17:11:32 INF] 22,evens
[17:11:33 INF] 24,evens
[17:11:33 INF] 19,odds
[17:11:33 INF] 21,odds
[17:11:34 INF] 23,odds
[17:11:34 INF] 25,odds
[17:11:34 INF] Finished.
我想指出的是,如果命名值没有出现在您的模板中,记录到上下文的项目将不会出现在日志中(即不会被记录)。
例如,在上面的代码中,如果我们将 Log.Information("{number},{name}",i);
更改为 Log.Information("{number}",i);
那么这就是您将得到的结果,这与您不配置时可能得到的结果类似充实Enrich.FromLogContext()
。忘记更新模板并追尾试图找到错误是微妙而容易的。
不包含上下文中包含的命名属性的模板字符串
[17:22:11 INF] Starting app
[17:22:11 INF] 10
[17:22:11 INF] 11
[17:22:11 INF] 12
[17:22:11 INF] 13
[17:22:11 INF] 15
[17:22:11 INF] 17
[17:22:12 INF] 14
[17:22:12 INF] 16
[17:22:12 INF] 19
[17:22:12 INF] 18
[17:22:12 INF] 20
[17:22:12 INF] 21
[17:22:12 INF] 23
[17:22:12 INF] 22
[17:22:12 INF] 24
[17:22:13 INF] 25
[17:22:13 INF] Finished.
此外,丰富的属性 appended
到字符串的末尾,所以
Log.Information("{name},{number}", i);
会产生
[17:35:11 INF] Starting app
[17:35:11 INF] 11,{number}
[17:35:11 INF] 10,{number}
登录愉快!希望这对您有所帮助。