停止由 CancellationToken 生成的异常,使其不再被 ApplicationInsights 报告
Stop Exception generated by CancellationToken from getting Reported by ApplicationInsights
我 认为 在我的控制器中使用 CancellationToken
是个好主意,如下所示:
[HttpGet("things", Name = "GetSomething")]
public async Task<ActionResult> GetSomethingAsync(CancellationToken ct) {
var result = await someSvc.LoadSomethingAsync(ct);
return Ok(result);
}
问题是现在 Azure Application Insights 显示了一堆 System.Threading.Tasks.TaskCancelledException: A Task was canceled.
类型的异常以及偶尔的 Npgsql.PostgresException: 57014: canceling statement due to user request
。这是我不需要的噪音。
Application Insights 已使用标准方法注册为服务 - services.AddApplicationInsightsTelemetry(Configuration);
。
尝试的解决方案
我想我可以插入应用程序管道并捕获上述异常,将它们转换为正常响应。我把下面的代码放在不同的地方。它捕获任何异常,如果 IsCancellationRequested,它 returns 一个虚拟响应。否则它会重新抛出捕获的异常。
app.Use(async (ctx, next) =>
{
try { await next(); }
catch (Exception ex)
{
if (ctx.RequestAborted.IsCancellationRequested)
{
ctx.Response.StatusCode = StatusCodes.Status418ImATeapot;
}
else { throw; }
}
});
这段代码的作用在于它改变了响应。但是,异常仍会发送到 Application Insights。
要求
- 我想要一个使用
RequestAborted.IsCancellationRequested
来尝试捕获特定异常的解决方案。原因是,如果我已经发现一个抛出异常的实现不是从 OperationCanceledException
派生的,则存在其他实现相同的可能性。
- 依赖失败是否仍然被记录并不重要,只是因请求被取消而引发的异常不会被记录。
- 我不想在每个控制器方法中都有一个 try/catch。它需要放在一个地方。
结论
我希望我了解报告异常的 Application Insights 机制。在试验之后,我觉得尝试在应用程序管道中捕获错误并不是正确的方法。只是不知道是什么。
您尝试过创建 ExceptionFilter 吗?
public class MyExceptionFilter : IExceptionFilter
{
public void OnException(ExceptionContext context)
{
if (context?.Exception.Message == "Did it catch this?")
{
context.Result = new BadRequestObjectResult("You have no access.");
}
}
}
ConfigureServices 方法内部:
services.AddMvc(config =>
{
config.Filters.Add(typeof(MyExceptionFilter));
})
过滤器中的逻辑只是给您一个示例,说明您希望如何过滤某些内容并传播结果。在您的情况下,我猜您需要以某种方式吞下与上下文相关的异常,以便之后不会发现异常。
也许简单地将它赋值给 null 就可以了?
我用 TelemetryProcessor 解决了这个问题。
为了在处理器中访问 RequestAborted.IsCancellationRequested,需要通过调用使 HttpContext 服务可用services.AddHttpContextAccessor()
在 Startup.ConfigureServices.
在处理器中,如果 IsCancellationRequested 为真,我会阻止处理任何异常遥测。下面是我最终解决方案的一个简化示例,因为最终我意识到我需要对超出我原始请求范围的依赖项和请求做一些更细微的工作。
internal class AbortedRequestTelemetryProcessor : ITelemetryProcessor
{
private readonly IHttpContextAccessor httpContextAccessor;
private readonly ITelemetryProcessor next;
public AbortedRequestTelemetryProcessor(
ITelemetryProcessor next, IHttpContextAccessor httpContextAccessor)
{
this.httpContextAccessor = httpContextAccessor;
this.next = next;
}
public void Process(ITelemetry item)
{
if (httpContextAccessor.HttpContext?.RequestAborted.IsCancellationRequested == true
&& item is ExceptionTelemetry)
{
// skip exception telemetry if cancellation was requested
return;
}
// Send everything else:
next.Process(item);
}
}
我 认为 在我的控制器中使用 CancellationToken
是个好主意,如下所示:
[HttpGet("things", Name = "GetSomething")]
public async Task<ActionResult> GetSomethingAsync(CancellationToken ct) {
var result = await someSvc.LoadSomethingAsync(ct);
return Ok(result);
}
问题是现在 Azure Application Insights 显示了一堆 System.Threading.Tasks.TaskCancelledException: A Task was canceled.
类型的异常以及偶尔的 Npgsql.PostgresException: 57014: canceling statement due to user request
。这是我不需要的噪音。
Application Insights 已使用标准方法注册为服务 - services.AddApplicationInsightsTelemetry(Configuration);
。
尝试的解决方案
我想我可以插入应用程序管道并捕获上述异常,将它们转换为正常响应。我把下面的代码放在不同的地方。它捕获任何异常,如果 IsCancellationRequested,它 returns 一个虚拟响应。否则它会重新抛出捕获的异常。
app.Use(async (ctx, next) =>
{
try { await next(); }
catch (Exception ex)
{
if (ctx.RequestAborted.IsCancellationRequested)
{
ctx.Response.StatusCode = StatusCodes.Status418ImATeapot;
}
else { throw; }
}
});
这段代码的作用在于它改变了响应。但是,异常仍会发送到 Application Insights。
要求
- 我想要一个使用
RequestAborted.IsCancellationRequested
来尝试捕获特定异常的解决方案。原因是,如果我已经发现一个抛出异常的实现不是从OperationCanceledException
派生的,则存在其他实现相同的可能性。 - 依赖失败是否仍然被记录并不重要,只是因请求被取消而引发的异常不会被记录。
- 我不想在每个控制器方法中都有一个 try/catch。它需要放在一个地方。
结论
我希望我了解报告异常的 Application Insights 机制。在试验之后,我觉得尝试在应用程序管道中捕获错误并不是正确的方法。只是不知道是什么。
您尝试过创建 ExceptionFilter 吗?
public class MyExceptionFilter : IExceptionFilter
{
public void OnException(ExceptionContext context)
{
if (context?.Exception.Message == "Did it catch this?")
{
context.Result = new BadRequestObjectResult("You have no access.");
}
}
}
ConfigureServices 方法内部:
services.AddMvc(config =>
{
config.Filters.Add(typeof(MyExceptionFilter));
})
过滤器中的逻辑只是给您一个示例,说明您希望如何过滤某些内容并传播结果。在您的情况下,我猜您需要以某种方式吞下与上下文相关的异常,以便之后不会发现异常。
也许简单地将它赋值给 null 就可以了?
我用 TelemetryProcessor 解决了这个问题。
为了在处理器中访问 RequestAborted.IsCancellationRequested,需要通过调用使 HttpContext 服务可用services.AddHttpContextAccessor()
在 Startup.ConfigureServices.
在处理器中,如果 IsCancellationRequested 为真,我会阻止处理任何异常遥测。下面是我最终解决方案的一个简化示例,因为最终我意识到我需要对超出我原始请求范围的依赖项和请求做一些更细微的工作。
internal class AbortedRequestTelemetryProcessor : ITelemetryProcessor
{
private readonly IHttpContextAccessor httpContextAccessor;
private readonly ITelemetryProcessor next;
public AbortedRequestTelemetryProcessor(
ITelemetryProcessor next, IHttpContextAccessor httpContextAccessor)
{
this.httpContextAccessor = httpContextAccessor;
this.next = next;
}
public void Process(ITelemetry item)
{
if (httpContextAccessor.HttpContext?.RequestAborted.IsCancellationRequested == true
&& item is ExceptionTelemetry)
{
// skip exception telemetry if cancellation was requested
return;
}
// Send everything else:
next.Process(item);
}
}