使用Application Insight时的操作ID

时间:2019-02-06 12:03:56

标签: azure azure-application-insights

我正在为我的端点提供一个关联ID:

enter image description here

然后我从HttpContext.Request.Headers中读取该ID,并将其用作我的遥测.Context.Operation.Id。

这有效,但是当我查看日志时,会有一个额外的条目,该条目由框架自动生成。该条目具有其自己的ID。如何确保框架使用相同的ID?

enter image description here

这是我配置服务的方式

using System;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using AutoMapper;
using Microsoft.ApplicationInsights;
using Microsoft.ApplicationInsights.Extensibility;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc.ApiExplorer;
using Microsoft.AspNetCore.Mvc.Versioning;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Logging;
using Users.Api.Services;
using Users.Api.Utility;
using Users.Services.Implementations;
using Users.Services.Interfaces;
using Users.Sql;
using Users.Utility;
using Packages.Api.Filters;
using Packages.Audit;
using Swashbuckle.AspNetCore.Swagger;

namespace Users.Api
{
    public class Startup
    {
        public Startup(IHostingEnvironment env)
        {
            var builder = new ConfigurationBuilder()
                .SetBasePath(env.ContentRootPath)
                .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
                .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)
                .AddEnvironmentVariables();
            Configuration = builder.Build();
        }

        public IConfigurationRoot Configuration { get; }

        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            // Dependency injection
            services.AddAutoMapper();

            services.AddDbContext<UsersContext>(
               builder => builder.UseSqlServer(Environment.GetEnvironmentVariable("Connectionstring")));

            services.AddScoped<IUserService, UserService>();
            services.AddScoped<IIdentityService, IdentityService>();
            services.AddScoped<IServiceBusCommunicator, ServiceBusCommunicator>();
            services.AddScoped<IGraphClient, GraphClient>();
            services.AddScoped<IClaimsHarvester, ClaimsHarvester>();
            services.AddScoped<IUserRepository, UserRepository>();

            services.AddSingleton<HttpClient>();
            services.AddSingleton<EndpointConfiguration>();
            services.AddSingleton<GraphConfiguration>();
            services.TryAddSingleton<IHttpContextAccessor, HttpContextAccessor>();
            services.AddScoped<IAuditLogClient, AuditLogClient>();

            var clientId = Environment.GetEnvironmentVariable("Authentication:AzureAd:ClientId");
            var tenant = Environment.GetEnvironmentVariable("Authentication:AzureAd:Tenant");
            var signInPolicyId = Environment.GetEnvironmentVariable("Authentication:AzureAd:SignInPolicyId");
            var authority = $"https://login.microsoftonline.com/tfp/{tenant}/{signInPolicyId}/v2.0/";

            services.AddAuthentication(options =>
                {
                    options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
                    options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
                    options.DefaultSignInScheme = JwtBearerDefaults.AuthenticationScheme;

                }).AddJwtBearer(bearerOptions =>
                {
                    bearerOptions.Authority = authority;
                    bearerOptions.Audience = clientId;
                    bearerOptions.Events = new JwtBearerEvents
                    {
                        OnAuthenticationFailed = AuthenticationFailed
                    };
                });

            services.AddMvc();

            services.AddSwaggerGen(
                options =>
                {
                    options.SwaggerDoc("v1", new Info { Title = "Users API", Version = "v1" });
                });

            services.ConfigureSwaggerGen(options =>
            {
                options.OperationFilter<AuthorizationHeaderParameterOperationFilter>();
                options.OperationFilter<CorrelationHeaderParameterOperationFilter>();
                options.OperationFilter<XTotalCountHeaderParameterOperationFilter>();
            });
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app,
            IHostingEnvironment env,
            ILoggerFactory loggerFactory,
            ContextInitializer contextInitializer)
        {
            if (env.IsDevelopment())
            {
               // loggerFactory.AddConsole(Configuration.GetSection("Logging"));
               // loggerFactory.AddDebug();
                app.UseDeveloperExceptionPage();
            }

            app.UseAuthentication();
            app.UseMvc();

            app.UseSwagger();
            app.UseSwaggerUI(
                c =>
                {
                    c.SwaggerEndpoint($"{Environment.GetEnvironmentVariable("ServiceFabric:UniqueUrlPath")}/swagger/v1/swagger.json", "Contacts API V1");
                });

            // Seed default values
            contextInitializer.Seed();
        }

        private Task AuthenticationFailed(AuthenticationFailedContext arg)
        {
            // For debugging purposes only!
            var s = $"AuthenticationFailed: {arg.Exception.Message}";
            arg.Response.ContentLength = s.Length;
            arg.Response.Body.Write(Encoding.UTF8.GetBytes(s), 0, s.Length);
            return Task.FromResult(0);
        }
    }
}

1 个答案:

答案 0 :(得分:1)

ApplicationInsights通常不支持此功能。

您仍然可以实现它,但是必须编写一个自定义请求集合。

您需要从DI容器中删除RequestTelemetryTrackingModule,然后添加用于跟踪请求的自定义中间件。

这种方法行不通(下面的代码):

    在此服务和上游服务上使用不同工具密钥时的
  • 方案。您可以查看如何在AppInsights SDK(设置requestTelemetry.Sourceresponse header)中对其进行处理

  • 与AspNetCore发出的信息跟踪的相关性。

  • 通常,请求遥测名称包含路径而不是路径,您可能需要弄清楚

    public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }

        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddApplicationInsightsTelemetry("ikey");
            var requestModule =
                services.FirstOrDefault(sd => sd.ImplementationType == typeof(RequestTrackingTelemetryModule));
            if (requestModule != null)
            {
                services.Remove(requestModule);
            }

            services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IHostingEnvironment env, TelemetryClient client)
        {
            app.UseMiddleware<RequestMiddleware>(client);
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            else
            {
                // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
                app.UseHsts();
            }

            app.UseHttpsRedirection();
            app.UseMvc();
        }
    }

    public class RequestMiddleware
    {
        private readonly RequestDelegate next;
        private readonly TelemetryClient telemetryClient;

        public RequestMiddleware(
            RequestDelegate next,
            TelemetryClient telemetryClient)
        {
            this.telemetryClient = telemetryClient;
            this.next = next;
        }

        public async Task InvokeAsync(HttpContext context)
        {
            var activity = new Activity("request");
            if (context.Request.Headers.TryGetValue("x-my-correlation-id", out var val))
            {
                activity.SetParentId(val);
            }

            using (var request = telemetryClient.StartOperation<RequestTelemetry>(activity))
            {
                request.Telemetry.Url = context.Request.GetUri();
                request.Telemetry.Context.Operation.Name = $"{context.Request.Method} {context.Request.Path.Value}";
                request.Telemetry.Name = $"{context.Request.Method} {context.Request.Path.Value}";

                try
                {
                    await next.Invoke(context).ConfigureAwait(false);
                }
                catch (Exception e)
                {
                    telemetryClient.TrackException(e);
                    request.Telemetry.Success = false;
                    throw;
                }
                finally
                {
                    if (context.Response != null)
                    {
                        request.Telemetry.ResponseCode = context.Response.StatusCode.ToString();
                        request.Telemetry.Success = context.Response.StatusCode < 400;
                    }
                    else
                    {
                        request.Telemetry.Success = false;
                    }
                }
            }
        }
    }