Serilog 中环境 LogContext 的线程安全

ptf*_*ptf 3 c# serilog

根据这篇文章,您可以将请求 ID 附加到 Serilog 中的环境上下文(the LogContext),如下所示:

using (LogContext.PushProperty("RequestId", Request.Id))
{
    // Process request; all logged events will carry `RequestId`
    Log.Information("Adding {Item} to cart {CartId}", item, cart.Id);
}
Run Code Online (Sandbox Code Playgroud)

这很好,而且似乎正在发挥作用。我有两种需要这个的场景:

  • 将相关 ID 添加到 API 的每个请求的日志中。
  • 为队列的每个消息读取添加相关 ID。

让我感到困惑的是,如果多个请求同时访问 API,或者我们同时处理多个消息,会发生什么情况。由于LogContext是静态类,我是否会意外地使用来自最初设置该属性的线程之外的另一个线程的值覆盖该属性RequestIdLogContext

假设线程 1 将RequestId设为1。在完成之前,线程 2 将 设为 ,RequestId因为2我们收到了另一个请求。现在,线程 1 会用作记录时2的值吗?RequestId我猜它不会,但有人可以解释为什么吗?根据 this this,将与现有属性同名的属性推入堆栈会覆盖它:

将属性推送到上下文将覆盖任何现有的同名属性,直到从 PushProperty() 返回的对象被释放为止,如示例中的属性 A 所示。

Serilog 是否对从该LogContext.PushProperty(...)方法返回的每个句柄有一个堆栈,或者其他什么?有什么办法可以覆盖RequestId,也许不需要LogContext.PushProperty("RequestId", Request.Id)再次打电话?

Cai*_*ete 8

LogContext 通过 AsyncLocal/ThreadStatic 实现线程安全。每个线程都有自己的 LogContext,尽管它是通过静态类访问的。请求不共享相同的 LogContext。