将请求 headers 添加到 Nancy 应用程序的 Application Insights 遥测

Adding request headers to Application Insights telemetry for Nancy application

我想在 Application Insights 的请求事件中包含 headers,并发现以下 post 具有针对带有 HttpContext 的应用程序的解决方案。我正在使用 Nancy 应用程序,其中请求 headers 存储在 NancyContext 中。问题是 Nancy 没有提供像 HttpContext.Current 这样的静态访问器,所以我想知道如何解决它。

我试了两次都没有成功。第一个是构建一个 ITelemetryInitializer,如下面 link 中所述,但后来我无法访问 NancyContext。

https://blogs.msdn.microsoft.com/stuartleeks/2016/11/03/including-headers-for-request-events-with-application-insights/

我的第二次尝试是将 NancyModule 传递给一个静态函数,该函数将请求 headers 添加到 ITelemetryContext 但后来我无法获取当前的 ITelemetryContext。

有没有其他人遇到并解决了这个问题?

您的第二种方法应该可行,并且您可以使用现有的扩展方法来获取当前请求遥测数据(如果有的话)。

方法是方法:HttpContextExtension.GetRequestTelemetry(https://github.com/Microsoft/ApplicationInsights-dotnet-server/blob/2a681f5399a6aaee554fa2d93a1d6447a8402fe1/Src/Web/Web.Shared.Net/HttpContextExtension.cs#L16)

这将为您返回给定 HttpContext 的当前请求遥测数据,因此您应该能够做到:

 var requestTelemetry = HttpContext.Current?.GetRequestTelemetry();
 // add whatever you need to the request telemetry?

从你的 Nancy 模块里面?

我找到了一个解决方案,可能不是最漂亮的,但至少看起来可行。

我创建了一个静态可访问的 AsyncLocal 实例来保存每个线程的 RequestTelemetry object。

public class RequestVariables
{
    public static AsyncLocal<RequestTelemetry> RequestTelemetry = new AsyncLocal<RequestTelemetry>();
}

我在 ITelemetryInitializer

中设置 RequestVariables.RequestTelemetry 的值
public class RequestTelemetryInitializer : ITelemetryInitializer
{
    public void Initialize(ITelemetry telemetry)
    {
        if (telemetry is RequestTelemetry requestTelemetry)
            RequestVariables.RequestTelemetry.Value = requestTelemetry;
    }
}

然后我在 Startup.Configure(...) 方法中注册了一个小的中间件,它获取由 ITelemetryInitializer 设置的 RequestTelemetry 实例并将请求 headers 添加到它。

app.Use((context, next) =>
{
    var requestTelemetry = RequestVariables.RequestTelemetry.Value;
    if (requestTelemetry?.Context == null) return next();

    foreach (var header in context.Request.Headers)
    {
        if (!requestTelemetry.Context.Properties.ContainsKey(header.Key))
            requestTelemetry.Context.Properties.Add(header.Key, header.Value.First());
    }

    return next();
});

实际上,.NET Framework 有一个示例:https://blogs.msdn.microsoft.com/stuartleeks/2016/11/03/including-headers-for-request-events-with-application-insights/

在 .NET Core 中,您只需使用 IHttpContextAccessor 访问 HttpContext 而不是 HttpContext.Current:

public class TelemetryHeadersInitializer : ITelemetryInitializer
{
    private readonly IHttpContextAccessor _httpContextAccessor;

    public List<string> RequestHeaders { get; set; }
    public List<string> ResponseHeaders { get; set; }

    public TelemetryHeadersInitializer(IHttpContextAccessor httpContextAccessor)
    {
        RequestHeaders = new List<string> { "Referer" }; //whatever you need
        ResponseHeaders = new List<string> { ... };
        _httpContextAccessor = httpContextAccessor;
    }

    public void Initialize(ITelemetry telemetry)
    {
        var requestTelemetry = telemetry as RequestTelemetry;
        // Is this a TrackRequest() ?
        if (requestTelemetry == null) return;

        var context = _httpContextAccessor.HttpContext;
        if (context == null) return;

        foreach (var headerName in RequestHeaders)
        {
            var headers = context.Request.Headers[headerName];
            if (headers.Any())
            {
                telemetry.Context.Properties.Add($"Request-{headerName}", string.Join(Environment.NewLine, headers));
            }             
        }
        foreach (var headerName in ResponseHeaders)
        {
            var headers = context.Response.Headers[headerName];
            if (headers.Any())
            {
                telemetry.Context.Properties.Add($"Response-{headerName}", string.Join(Environment.NewLine, headers));
            }
        }
    }
}

//Services.cs:
services.AddSingleton<ITelemetryInitializer, TelemetryHeadersInitializer>();

同时检查: https://github.com/Microsoft/ApplicationInsights-aspnetcore/wiki/Custom-Configuration