Application Insights-从.net核心中间件添加属性

时间:2018-10-20 09:25:18

标签: .net .net-core asp.net-core-mvc azure-application-insights

我正在尝试从我们的.net核心MVC应用程序中获取一些有关应用程序见解的附加信息。我发现了以下帖子: Adding custom properties for each request in Application Insights metrics

答案中,他们使用了自定义遥测初始化程序,并且在您需要一些请求数据或其他内容时可以使用。

现在,我们的应用程序中有一组中间件。他们将某些标头转换为可读的内容。

当然,我们可以记录标题并搜索那些标题可以具有的所有不同值。但是我们希望将中间件的结果用于应用程序见解的属性。

任何人都想将中间件的某些结果用于Application Insights请求遥测的属性中?

2 个答案:

答案 0 :(得分:2)

从@svoychik得到正确的想法。中间件将输出值添加到HttpContext.Items。参见示例:

using Microsoft.AspNetCore.Http;
using System.Text;
using System.Threading.Tasks;

namespace Test.API.Middleware
{
    public class ValueMiddleware
    {
        private readonly RequestDelegate next;

        public ApiKeyMiddleware(RequestDelegate next)
        {
            this.next = next;
        }

        public async Task Invoke(HttpContext httpContext)
        {
            if (!context.Items.ContainsKey("ApplicationData"))
            {
                httpContext.Items["ApplicationData"] = "Important Data";
            }
        }
    }
}

然后,当您需要将所有这些项目纳入应用程序见解时,只需使用以下初始化程序即可:

using Microsoft.ApplicationInsights.Channel;
using Microsoft.ApplicationInsights.Extensibility;
using Microsoft.AspNetCore.Http;

namespace Test.API.TelemetryInitializers : ITelemetryInitializer
{
    public class HttpContextItemsTelemetryInitializer
    {
        private readonly IHttpContextAccessor httpContextAccessor;
        public HttpContextItemsTelemetryInitializer(IHttpContextAccessor httpContextAccessor)
        {
            this.httpContextAccessor = httpContextAccessor;
        }

        public void Initialize(ITelemetry telemetry)
        {
            var context = httpContextAccessor.HttpContext;
            if (context == null)
            {
                return;
            }

            foreach (var item in context.Items)
            {
                var itemKey = item.Key.ToString();

                // Remove some pollution that Microsoft and the systems adds to the HttpContext Items.
                if (itemKey.Contains("Microsoft") || itemKey.Contains("System"))
                {
                    continue;
                }

                if (!telemetry.Context.GlobalProperties.ContainsKey(itemKey))
                {
                    telemetry.Context.GlobalProperties.Add(itemKey, item.Value.ToString());
                }
            }
        }
    }
}

在Startup.cs中设置初始化程序和应用程序见解,如以下示例所示:

using Test.API.TelemetryInitializers;
using Microsoft.ApplicationInsights.Extensibility;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.DependencyInjection;

namespace Test.API
{
    public class Startup
    {
        // This method gets called by the runtime. Use this method to add services to the container.
        // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);

            services.AddSingleton<ITelemetryInitializer, HttpContextItemsTelemetryInitializer>();
            services.AddApplicationInsightsTelemetry();
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }

            app.UseMiddleware<ValueMiddleware>();
            app.UseMvc();
        }
    }
}

然后,将HttpContext.Items的所有值添加到您的应用程序见解中。

答案 1 :(得分:0)

无需将中间件中的数据放入 HttpContext 并运行 TelemetryInitializer,您可以直接将所需数据添加到中间件中的遥测对象中:

public class TelemetryMiddleware
{
    private const string _BodyKey = "Body";
    private readonly RequestDelegate _next;

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

    public async Task Invoke(HttpContext httpContext)
    {
        httpContext.Request.EnableBuffering();

        if (httpContext.Request.Body.CanRead
            && (httpContext.Request.Method == HttpMethods.Put
                || httpContext.Request.Method == HttpMethods.Post
                || httpContext.Request.Method == HttpMethods.Patch))
        {
            // The needed method to access telemetry object within middleware
            var telemetry = httpContext.Features.Get<RequestTelemetry>();

            if (telemetry != null
                && !telemetry.Properties.ContainsKey(_BodyKey))
            {
                var oldPosition = httpContext.Request.Body.Position;
                httpContext.Request.Body.Position = 0;

                using (var reader = new StreamReader(httpContext.Request.Body, Encoding.UTF8, false, 4096, true))
                {
                    var body = await reader.ReadToEndAsync();

                    if (!string.IsNullOrEmpty(body))
                        telemetry.Properties.Add(_BodyKey, body);
                }

                httpContext.Request.Body.Position = oldPosition;
            }
        }

        await _next(httpContext);
    }
}

管道的构建与每个中间件的构建相同:

app.UseMiddleware<TelemetryMiddleware>();