c# - .NET Core - 使用 Request-Id 将传入请求挂接到出站 HTTP 请求

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

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

enter image description here

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

到目前为止我们尝试了什么

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

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

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

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

是否有任何开箱即用的解决方案可供我们使用,而无需提出我们自己的定制解决方案?

最佳答案

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

No there's nothing out of the box for this. There's an end to end that works with app insights but it isn't very fleshed out. You might consider just using the same middleware across teams. if There's a work item to address this in 3.0 https://github.com/aspnet/Hosting/issues/1350

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

更新

我们最终按照@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();

关于c# - .NET Core - 使用 Request-Id 将传入请求挂接到出站 HTTP 请求,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52306882/

相关文章:

c# - 如何获取 IMethodSymbol 的语句?

c# - 从 MySQL 中获取元组的值到字符串数组

python - 使用多个模块记录时的记录器层次结构和根记录器

node.js - Nodejs winston 错过日志

c# - 在多个 .NET Core 项目之间共享代码

javascript - System.Windows.Controls.WebBrowser(IFramed窗口)如何与其xaml(WPF)中的父 View 通信

c# - CacheManager 内存缓存配置

具有多个模块的 Python 日志记录

exe - 如何在开发人员机器上构建 Visual Studio 2017 .NET Core .exe 文件?

c# - Asp.net core Sakura.AspNetCore.PagedList 和部分 View