如何 link Azure 上的 Application Insights 中的请求例外?
How to link exceptions to requests in Application Insights on Azure?
我们在 Azure 上使用 Owin 进行 REST 服务,并且必须直接向 Application Insights 报告。我们想要记录异常和请求。现在我们有这个:
using AppFunc = Func<IDictionary<string, object>, 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<string, object> 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<object>(null);
}
public override void Log(ExceptionLoggerContext context)
{
telemetryClient.TrackException(context.Exception);
}
}
他们像这样注册到我们的应用程序中:
static void ConfigureInsights(IAppBuilder app, HttpConfiguration config)
{
var rtClient = new TelemetryClient();
app.Use<InsightsReportMiddleware>(rtClient);
config.Services.Add(typeof (IExceptionLogger), new InsightsExceptionLogger(rtClient));
}
这有效,除了异常和请求未连接。两者都会被记录下来,但是当点击一个失败的请求时,它会显示 "No related exceptions were found"。反之,当打开异常属性时,我们可以读到"Requests affected by this exception: 0"。
这样做的正确方法是什么?
Application Insights 通过比较 ExceptionTelemetry.Context.Operation.Id
和 RequestTelemetry.Id
来链接异常和请求。
我没有 OWIN 的代码示例,但是 Application Insights SDK 的 ASP.NET 5 package 具有类似的中间件组件,用于跟踪异常和请求。我希望您可以使用这些信息为 OWIN 构建解决方案。
我们创建一个 RequestTelemetry
实例并将其存储在请求处理环境中,然后调用下一个执行实际请求处理的中间件组件。在 ASP.NET 5 中,我们将 RequestTelemetry 注册为请求范围的服务。使用 OWIN,我想您的中间件组件会创建它并将其存储在 environment
字典中。
我们还有一个名为 OperationIdTelemetryInitializer 的 ITelemetryInitializer
,它将 ITelemetry.Context.Operation.Id
设置为从环境中提取的 RequestTelemetry.Id
。此初始化程序需要添加到 TelemetryConfiguration
中,用于在您的应用程序中创建 TelemetryClient
实例。默认使用 TelemetryConfiguration.Active
。
我最后做了什么:
using AppFunc = Func<IDictionary<string, object>, 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<string, object> 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<object>(null);
}
public override void Log(ExceptionLoggerContext context)
{
telemetryClient.TrackException(context.Exception);
}
}
对于我当前的客户,我们还没有 OWIN-ed。
我用 WebAPI 注册了一个 DelegatingHandler
,它通过 CallContext.LogicalSetData
将当前请求粘贴到线程的 SynchronizationContext
中,并在请求完成后将其删除。
在我现有的日志系统中,它必须用 Application Insights 的东西进行改造,然后我通过 CallContext.LogicalSetData
从线程中获取请求并开始获取 HttpContext
这是由框架放入请求属性中,然后从 HttpContext.Items
,我得到 RequestTelemetry
实例。
最终,这一切都是必需的,因为我无法从正在更新服务的 IoC 容器访问请求或操作或任何内容。
最终我们可能会重写其中的一些内容,以改进 OperationContext
或 InstrumentationContext
样式对象在堆栈中的创建和流动,并摆脱处理程序和 CallContext
有趣的业务.
存在接受属性字典的 TelemetryClient.TrackException
方法的重载。它专门用于对异常进行分类和搜索。这允许生成一个错误 ID,并且 link 错误到 AppInsights。
错误处理示例:
var errorId = GenerateErrorId();
var trackProperties = new Dictionary<string, string>();
trackProperties.Add("ErrorId", errorId);
var ai = new TelemetryClient();
ai.TrackException(exception, trackProperties);
JObject resp = new JObject();
resp["message"] = exception.Message + " - " + errorId;
await context.Response.WriteAsync(resp.ToString());
我们在 Azure 上使用 Owin 进行 REST 服务,并且必须直接向 Application Insights 报告。我们想要记录异常和请求。现在我们有这个:
using AppFunc = Func<IDictionary<string, object>, 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<string, object> 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<object>(null);
}
public override void Log(ExceptionLoggerContext context)
{
telemetryClient.TrackException(context.Exception);
}
}
他们像这样注册到我们的应用程序中:
static void ConfigureInsights(IAppBuilder app, HttpConfiguration config)
{
var rtClient = new TelemetryClient();
app.Use<InsightsReportMiddleware>(rtClient);
config.Services.Add(typeof (IExceptionLogger), new InsightsExceptionLogger(rtClient));
}
这有效,除了异常和请求未连接。两者都会被记录下来,但是当点击一个失败的请求时,它会显示 "No related exceptions were found"。反之,当打开异常属性时,我们可以读到"Requests affected by this exception: 0"。 这样做的正确方法是什么?
Application Insights 通过比较 ExceptionTelemetry.Context.Operation.Id
和 RequestTelemetry.Id
来链接异常和请求。
我没有 OWIN 的代码示例,但是 Application Insights SDK 的 ASP.NET 5 package 具有类似的中间件组件,用于跟踪异常和请求。我希望您可以使用这些信息为 OWIN 构建解决方案。
我们创建一个 RequestTelemetry
实例并将其存储在请求处理环境中,然后调用下一个执行实际请求处理的中间件组件。在 ASP.NET 5 中,我们将 RequestTelemetry 注册为请求范围的服务。使用 OWIN,我想您的中间件组件会创建它并将其存储在 environment
字典中。
我们还有一个名为 OperationIdTelemetryInitializer 的 ITelemetryInitializer
,它将 ITelemetry.Context.Operation.Id
设置为从环境中提取的 RequestTelemetry.Id
。此初始化程序需要添加到 TelemetryConfiguration
中,用于在您的应用程序中创建 TelemetryClient
实例。默认使用 TelemetryConfiguration.Active
。
我最后做了什么:
using AppFunc = Func<IDictionary<string, object>, 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<string, object> 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<object>(null);
}
public override void Log(ExceptionLoggerContext context)
{
telemetryClient.TrackException(context.Exception);
}
}
对于我当前的客户,我们还没有 OWIN-ed。
我用 WebAPI 注册了一个 DelegatingHandler
,它通过 CallContext.LogicalSetData
将当前请求粘贴到线程的 SynchronizationContext
中,并在请求完成后将其删除。
在我现有的日志系统中,它必须用 Application Insights 的东西进行改造,然后我通过 CallContext.LogicalSetData
从线程中获取请求并开始获取 HttpContext
这是由框架放入请求属性中,然后从 HttpContext.Items
,我得到 RequestTelemetry
实例。
最终,这一切都是必需的,因为我无法从正在更新服务的 IoC 容器访问请求或操作或任何内容。
最终我们可能会重写其中的一些内容,以改进 OperationContext
或 InstrumentationContext
样式对象在堆栈中的创建和流动,并摆脱处理程序和 CallContext
有趣的业务.
存在接受属性字典的 TelemetryClient.TrackException
方法的重载。它专门用于对异常进行分类和搜索。这允许生成一个错误 ID,并且 link 错误到 AppInsights。
错误处理示例:
var errorId = GenerateErrorId();
var trackProperties = new Dictionary<string, string>();
trackProperties.Add("ErrorId", errorId);
var ai = new TelemetryClient();
ai.TrackException(exception, trackProperties);
JObject resp = new JObject();
resp["message"] = exception.Message + " - " + errorId;
await context.Response.WriteAsync(resp.ToString());