.NET Core-将带有Request-Id的传入请求挂接到出站HTTP请求

Ank*_*jay 7 c# logging .net-core asp.net-core-2.1

我们正在寻找一种方法来跨多个API请求Request-Id(一个或Correlation-Id多个),如下图所示:

在此处输入图片说明

这个想法是有一个单一的ID来通过我们日志中的多个API跟踪特定的请求。我们使用ILogger的是.NET Core 2.1随附的标准。

到目前为止我们尝试过的

  • 我们尝试Request-Id在请求标头中使用,成功记录了日志,但是我们无法检索该值以将其添加到其他API的后续HTTP请求中。

  • 我们注意到,还有一个CorrelationId被记录下来。但是,我们不知道如何更新它。

  • 此外,我们注意到有TraceIdentity可在HttpContextAccessor这有可能解决我们的宗旨。但是,我们不知道如何利用它来解决我们的问题。

我们无法使用Application Insights,而是要依赖我们自己的日志记录基础结构框架。我们在文档中找不到太多内容。

是否有可用的现成解决方案可供我们使用,而无需提出自己的自定义解决方案?

Ank*_*jay 5

我在 Twitter 上向 @davidfowl 提出了同样的问题。他回复说:

不,没有任何现成的东西。有一个端到端的应用程序洞察,但它不是很充实。您可能会考虑跨团队使用相同的中间件。如果 3.0 中有一个工作项目可以解决这个问题https://github.com/aspnet/Hosting/issues/1350

因此,从目前来看,定制中间件是唯一的出路。这可能会随着未来的版本而改变。

更新

我们最终按照 @DavidMcEleney 的建议创建了一个自定义中间件。然而,除此之外,我们还添加了CorrelationId一个AsyncLocal属性。这有助于我们在需要时访问CorrelationId代码中的任何位置。这是代码获取/设置CorrelationId

using System;
using System.Threading;

public static class CorrelationContext
{
    private static readonly AsyncLocal<string> CorrelationId = new AsyncLocal<string>();

    public static void SetCorrelationId(string correlationId)
    {
        if (string.IsNullOrWhiteSpace(correlationId))
        {
            throw new ArgumentException(nameof(correlationId), "Correlation id cannot be null or empty");
        }

        if (!string.IsNullOrWhiteSpace(CorrelationId.Value))
        {
            throw new InvalidOperationException("Correlation id is already set");
        }

        CorrelationId.Value = correlationId;
    }

    public static string GetCorrelationId()
    {
        return CorrelationId.Value;
    }
}
Run Code Online (Sandbox Code Playgroud)

使用于CorrelationMiddleware.cs

public class CorrelationMiddleware
{
    private readonly RequestDelegate _next;

    public CorrelationMiddleware(RequestDelegate next)
    {
        _next = next;
    }

    public async Task Invoke(HttpContext context)
    {
        context.Request.Headers.TryGetValue("Correlation-Id-Header", out var correlationIds);

        var correlationId = correlationIds.FirstOrDefault() ?? Guid.NewGuid().ToString();

        CorrelationContext.SetCorrelationId(correlationId);

        using (LogContext.PushProperty("Correlation-Id", correlationId))
        {
            await _next.Invoke(context);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

如果我们稍后需要CorrelationId在代码中的任何位置访问 in,那么我们只需调用:CorrelationContext.GetCorrelationId();

  • 嗨@AnkitVijay,我知道这个问题已经有一年了,但我想知道:为什么你选择创建一个静态函数而不是为每个请求注册一个服务来保存该值?它将通过 DI 可供所有其他服务使用,在我看来,整个“AsyncLocal”的复杂性将被避免。 (2认同)