gpt4 book ai didi

c# - 将所有 NLog 日志绑定(bind)回 WebAPI 中的原始请求的方法?

转载 作者:行者123 更新时间:2023-11-30 14:28:00 30 4
gpt4 key购买 nike

我正在使用 WebAPI 构建 API,并且一直在使用 NLog 在整个堆栈中进行日志记录。我的 API 解决方案有两个主要项目,包括:

  • 实现 Controller 和 webapi 东西的网站层本身
  • 以类似 CQRS 的方式实现“异步”命令和处理程序的服务层

我想要实现的是自动生成一个唯一的 ID,我可以将其附加到日志语句,以便在为单个请求提供服务时写入的任何日志,无论它们来自哪一层,都可以链接回原始的要求。我还希望它可以在不传递唯一 ID 的情况下工作,或者让日志语句本身关心将它包含在它们的调用中。

考虑到这个目标,我开始考虑编写一个自定义委托(delegate)处理程序来拦截每个请求(遵循 this post 的指导)并在 NLog 中添加一个唯一 ID 作为属性。我最终得到以下结果:

/// <summary>
/// This class is a WebAPI message handler that helps establish the data and operations needed
/// to associate log statements through the entire stack back to the originating request.
///
/// Help from here: http://weblogs.asp.net/fredriknormen/log-message-request-and-response-in-asp-net-webapi
/// </summary>
public class InitializeLoggingMessageHandler : DelegatingHandler
{
private ILogger _logger;

// The logger is injected with Autofac
//
public InitializeLoggingMessageHandler(ILogger logger)
{
_logger = logger;
}

protected async override System.Threading.Tasks.Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, System.Threading.CancellationToken cancellationToken)
{
// Get a unique ID for this request
//
var uniqueId = Guid.NewGuid().ToString();

// Now that we have a unique ID for this request, we add it to NLog's MDC as a property
// we can use in the log layouts. We do NOT use the global diagnostic context because
// WebAPI is multi-threaded, and we want the ID to be scoped to just the thread servicing
// this request.
//
NLog.MappedDiagnosticsContext.Set("UniqueId", uniqueId);

// Capture some details about the request for logging
//
var requestInfo = string.Format("{0} {1}", request.Method, request.RequestUri);
var requestMessage = await request.Content.ReadAsByteArrayAsync();

_logger.Info("Request: {0} - {1}", requestInfo, Encoding.UTF8.GetString(requestMessage));

var response = await base.SendAsync(request, cancellationToken);

return response;
}
}

通过这段代码,我可以在日志布局中使用唯一 ID,如下所示:

<target xsi:type="Debugger" name="DebugLogger" 
layout="${longdate} ${logger} ${mdc:item=UniqueId} ${message}" />

这种方法的问题是我正在使用 NLog 的 MappedDiagnosticsContext 来尝试将唯一 ID 保存为可以在布局中使用的属性(因此我执行日志记录的代码不需要知道)。这是一种用于存储值的线程本地机制,因此当您使用异步代码时它会崩溃,因为启动请求的线程可能不是执行所有请求的线程。

所以发生的情况是第一条日志消息包含唯一 ID,但后来的日志消息可能会丢失它,因为它们在不同的线程上并且无法访问该值。我也不能在 NLog 中使用 GlobalDiagnosticsContext,因为它是真正的全局性的,因此 WebAPI 中的多个请求很容易覆盖唯一 ID,并且数据将毫无用处。

那么,为了将所有日志消息关联回 WebAPI 中发起的请求,我是否应该考虑另一种机制?

最佳答案

看看LogicalCallContext .从 .NET 4.5 开始,它 supports async场景。

先生。 Jeffrey Richter :

The .NET Framework has a little-known facility that allows you to associate data with a “logical” thread-of-execution. This facility is called logical call context and it allows data to flow to other threads, AppDomains, and even to threads in other processes.

关于c# - 将所有 NLog 日志绑定(bind)回 WebAPI 中的原始请求的方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30593801/

30 4 0