【问题标题】:.NET Core - Hook incoming request with a Request-Id to outbound HTTP requests.NET Core - 将带有 Request-Id 的传入请求与出站 HTTP 请求挂钩
【发布时间】:2018-09-13 04:56:26
【问题描述】:

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

我们的想法是通过我们的日志中的多个 API 使用一个 id 来跟踪特定请求。我们使用 .NET Core 2.1 开箱即用的标准 ILogger

到目前为止我们所做的尝试

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

  • 我们注意到还有一个CorrelationId 被记录。但是,我们无法弄清楚如何更新它。

  • 另外,我们注意到HttpContextAccessor 上有可用的TraceIdentity,这可能会解决我们的目的。但是,我们不知道如何利用它来解决我们的问题。

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

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

【问题讨论】:

  • 为什么不能检索 Request-Id 标头的值?如果传入请求设置了标头 Request-Id,asp.net 核心将其值用作日志消息中的 CorrelationId。这是自动完成的。
  • 记录的 requestId 是 TraceIdentifier
  • 您好@Jehof 如前所述,我们无法找到在后续请求中检索request-id 的方法。您能否指导我们使用示例代码来实现这一目标?

标签: c# logging .net-core asp.net-core-2.1


【解决方案1】:

我在 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;
    }
}

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);
        }
    }
}

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

【讨论】:

  • 是的,我已经看到了。再次感谢。
  • 请检查另一个免费库:github.com/albumprinter/CorrelationTracking/wiki
  • 嗨@AnkitVijay我知道这个问题已经有一年了,但我想知道:为什么你选择创建一个静态函数而不是为每个请求注册一个服务,持有价值?它可以通过 DI 提供给所有其他服务,在我看来,整个AsyncLocal 的复杂性都可以避免。
【解决方案2】:

我一直在使用 Serilog 登录 dotnet core 并一直在使用中间件推送 LogContext 属性 -

CorrelationMiddleware.cs

    public class CorrelationMiddleware
    {
    readonly RequestDelegate _next;

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

    public async Task Invoke(HttpContext context)
    {
        context.Request.Headers.TryGetValue(Headers.Correlation, out StringValues correlationId);

        using (LogContext.PushProperty("Correlation-Id", correlationId.FirstOrDefault()))
        {
            await _next.Invoke(context);
        }
    }
}

在您的 Startup.cs 配置方法中注册:

app.UseMiddleware<CorrelationLogger>();

然后,在进行出站 http 调用时 - 您可以通过添加

向 HttpRequestMessage 添加标头
request.Headers.Add(Headers.Correlation, GetHeader("Correlation-Id"));

在搜索日志时,我们可以通过相关 id 进行搜索并查看所有 API 之间的完整端到端...

【讨论】:

  • 嗨@David,我们当然可以使用这种方法,这是备用选项。但我们想避免这种情况,因为 API 服务可能有不同的团队所有者。我们没有创建我们自己的“自定义”中间件,而是寻找可以在不同团队之间保持一致的开箱即用的东西,以及更多来自 官方 ASP.NET Core SDK 的“标准”。希望我说得通。
【解决方案3】:

不确定,这是否直接相关,但我们在 Service Fabric 项目中跨 api 和服务关联请求时面临同样的问题。我们最终从 CallContext(在 System.Runtime.Remoting.Messaging 内部)设置和获取了相关性 ID。 巧合的是刚刚写了一些关于它的东西here。请看看这是否有帮助。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-01-20
    • 2010-10-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-11-27
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多