如何在Azure上的Application Insights中将exception链接到请求?
我们在Azure上使用Owin来提供REST服务,并且必须直接向Application Insights报告。 我们想记录exception和请求。 现在我们有这个:
using AppFunc = Func<IDictionary, Task>; public class InsightsReportMiddleware { readonly AppFunc next; readonly TelemetryClient telemetryClient; public InsightsReportMiddleware(AppFunc next, TelemetryClient telemetryClient) { if (next == null) { throw new ArgumentNullException("next"); } this.telemetryClient = telemetryClient; this.next = next; } public async Task Invoke(IDictionary environment) { var sw = new Stopwatch(); sw.Start(); await next(environment); sw.Stop(); var ctx = new OwinContext(environment); var rt = new RequestTelemetry( name: ctx.Request.Path.ToString(), timestamp: DateTimeOffset.Now, duration: sw.Elapsed, responseCode: ctx.Response.StatusCode.ToString(), success: 200 == ctx.Response.StatusCode ); rt.Url = ctx.Request.Uri; rt.HttpMethod = ctx.Request.Method; telemetryClient.TrackRequest(rt); } } public class InsightsExceptionLogger : ExceptionLogger { readonly TelemetryClient telemetryClient; public InsightsExceptionLogger(TelemetryClient telemetryClient) { this.telemetryClient = telemetryClient; } public override Task LogAsync(ExceptionLoggerContext context, System.Threading.CancellationToken cancellationToken) { telemetryClient.TrackException(context.Exception); return Task.FromResult(null); } public override void Log(ExceptionLoggerContext context) { telemetryClient.TrackException(context.Exception); } }
它们在我们的应用程序中注册如下:
static void ConfigureInsights(IAppBuilder app, HttpConfiguration config) { var rtClient = new TelemetryClient(); app.Use(rtClient); config.Services.Add(typeof (IExceptionLogger), new InsightsExceptionLogger(rtClient)); }
这是有效的,除了exception和请求没有连接。 两者都被记录,但是当点击失败的请求时,它会显示“未找到相关的例外”。 相反,在打开exception属性时,我们可以读取“受此exception影响的请求:0”。 这样做的正确方法是什么?
Application Insights通过比较ExceptionTelemetry.Context.Operation.Id
和RequestTelemetry.Id
链接exception和请求。
我没有OWIN的代码示例,但Application Insights SDK的ASP.NET 5包具有类似的中间件组件,用于跟踪exception和请求。 我希望您可以使用此信息为OWIN构建解决方案。
我们创建一个RequestTelemetry
实例,并在调用执行实际请求处理的下一个中间件组件之前将其存储在请求处理环境中。 在ASP.NET 5中,我们将RequestTelemetry注册为请求范围的服务。 有了OWIN,我想你的中间件组件会创建它并将其存储在environment
字典中。
我们还有一个名为OperationIdTelemetryInitializer的ITelemetryInitializer
, ITelemetry.Context.Operation.Id
使用从环境中提取的RequestTelemetry.Id
设置ITelemetry.Context.Operation.Id
。 需要将此初始化程序添加到用于在应用程序中创建TelemetryClient
实例的TelemetryClient
中。 默认情况下使用TelemetryConfiguration.Active
。
我最终做了什么:
using AppFunc = Func, Task>; public class InsightsReportMiddleware { readonly AppFunc next; readonly TelemetryClient telemetryClient; public InsightsReportMiddleware(AppFunc next, TelemetryClient telemetryClient) { if (next == null) { throw new ArgumentNullException("next"); } this.telemetryClient = telemetryClient; this.next = next; } public async Task Invoke(IDictionary environment) { var ctx = new OwinContext(environment); var rt = new RequestTelemetry() { Url = ctx.Request.Uri, HttpMethod = ctx.Request.Method, Name = ctx.Request.Path.ToString(), Timestamp = DateTimeOffset.Now }; environment.Add("requestTelemetry", rt); var sw = new Stopwatch(); sw.Start(); await next(environment); sw.Stop(); rt.ResponseCode = ctx.Response.StatusCode.ToString(); rt.Success = ctx.Response.StatusCode < 400; rt.Duration = sw.Elapsed; telemetryClient.TrackRequest(rt); } } public class InsightsExceptionLogger : ExceptionLogger { readonly TelemetryClient telemetryClient; public InsightsExceptionLogger(TelemetryClient telemetryClient) { this.telemetryClient = telemetryClient; } public override Task LogAsync(ExceptionLoggerContext context, System.Threading.CancellationToken cancellationToken) { var owinContext = context.Request.GetOwinEnvironment(); ExceptionTelemetry exceptionTelemetry = null; if (owinContext != null) { object obj; if (owinContext.TryGetValue("requestTelemetry", out obj)) { var requestTelemetry = obj as RequestTelemetry; exceptionTelemetry = new ExceptionTelemetry(context.Exception) { Timestamp = DateTimeOffset.Now }; exceptionTelemetry.Context.Operation.Id = requestTelemetry.Id; } } if (exceptionTelemetry != null) { telemetryClient.TrackException(exceptionTelemetry); } else { telemetryClient.TrackException(context.Exception); } return Task.FromResult
对于我现在的客户,我们还没有OWIN-ed。
我在WebAPI上注册了DelegatingHandler
,它通过CallContext.LogicalSetData
将当前请求粘贴到线程的SynchronizationContext
,并在请求完成后将其删除。
在我现有的日志记录系统中,它必须使用Application Insights的东西进行改编,然后我通过CallContext.LogicalSetData
从线程中获取请求,并设置关于获取由框架放入请求属性的HttpContext
,然后从在HttpContext.Items
,我得到了RequestTelemetry
实例。
最终,这一切都是必需的,因为我无法访问IoC容器中的请求或操作或任何新的服务。
最终,我们可能会重写其中的一些内容,以便改进ActionContext或InstrumentationContext
样式对象的创建和流动,从而摆脱处理程序和CallContext
有趣的业务。