Serilog 中环境 LogContext 的线程安全

Thread safety of the ambient LogContext in Serilog

根据 this 文章,您可以像这样在 Serilog 中将请求 ID 附加到环境上下文(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);
}

这很好,而且似乎有效。我有两种情况需要这个:

让我感到困惑的是,如果多个请求同时到达 API,或者我们同时处理多条消息,会发生什么情况。由于 LogContext 是静态 class,我是否可以不小心用另一个线程的值覆盖 LogContext 中的 RequestId 属性,而不是最初设置 属性?

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

Pushing property onto the context will override any existing properties with the same name, until the object returned from PushProperty() is disposed, as the property A in the example demonstrates.

Serilog 从 LogContext.PushProperty(...) 方法返回的每个句柄是否有一个堆栈?有什么方法可以覆盖 RequestId,或许不需要再次调用 LogContext.PushProperty("RequestId", Request.Id)

LogContext is thread-safe via AsyncLocal/ThreadStatic。每个线程都有自己的 LogContext,尽管它是通过静态 class 访问的。请求不共享相同的 LogContext。