.NET 6 WebAPI:Application Insights未记录未处理异常求助
问题背景
我正在开发一个.NET 6 Web API,已安装以下NuGet包:
<PackageReference Include="Microsoft.ApplicationInsights.AspNetCore" Version="2.21.0" />
相关配置(简化版):
{ "Logging": { "LogLevel": { "Default": "Information" }, "ApplicationInsights": { "LogLevel": { "Default": "Information", "Microsoft": "Error" }, "ConnectionString": "InstrumentationKey" } } }
遥测扩展代码:
using System.Reflection; using Microsoft.ApplicationInsights.Channel; using Microsoft.ApplicationInsights.Extensibility; using Microsoft.ApplicationInsights.WindowsServer.TelemetryChannel; namespace MyApplication; public static class ApplicationServicesLoggingExtensions { /// <summary> /// Adds production loggers /// </summary> /// <param name="services"></param> /// <param name="configuration"></param> /// <returns></returns> public static IServiceCollection AddLogging(this IServiceCollection services, IConfiguration configuration) { return services.AddLogging(logging => { logging.ClearProviders(); logging.AddConsole(); logging.AddEventLog(config => { config.SourceName = Assembly.GetExecutingAssembly().FullName; }); logging.AddConfiguration(configuration.GetSection("Logging")); logging.AddApplicationInsights( config => { config.ConnectionString = configuration.GetSection("Logging:ApplicationInsights:ConnectionString").Value; }, options => { options.FlushOnDispose = true; }); logging.AddDebug(); }) .SetupStorageFolderForTelemetryChannel(configuration); } /// <summary> /// Setup up telemetry with a storage folder using <see cref="ServerTelemetryChannel" /> /// and installs a custom initializer that helps identify the application generating telemetry /// </summary> /// <param name="services"></param> /// <param name="configuration"></param> /// <returns></returns> private static IServiceCollection SetupStorageFolderForTelemetryChannel(this IServiceCollection services, IConfiguration configuration) { services.AddSingleton<ITelemetryInitializer, CustomTelemetryInitializer>(); var configuredStorageFolder = configuration.GetValue<string>("ApplicationInsights:StorageFolder"); if (string.IsNullOrEmpty(configuredStorageFolder)) return services .AddApplicationInsightsTelemetry(); var baseFolder = AppContext.BaseDirectory; var storageFolder = Path.Combine(baseFolder, configuredStorageFolder); var f = new DirectoryInfo(storageFolder); if (!f.Exists) f.Create(); // This sets up ServerTelemetryChannel with StorageFolder set to a custom location. return services.AddSingleton(typeof(ITelemetryChannel), new ServerTelemetryChannel { StorageFolder = storageFolder }) .AddApplicationInsightsTelemetry(); } }
自定义遥测初始化器代码:
using Microsoft.ApplicationInsights.Channel; using Microsoft.ApplicationInsights.Extensibility; namespace MyApplication; public class CustomTelemetryInitializer : ITelemetryInitializer { private readonly IConfiguration _configuration; private readonly IHttpContextAccessor _httpContextAccessor; public CustomTelemetryInitializer(IConfiguration configuration, IHttpContextAccessor httpContextAccessor) { _configuration = configuration; _httpContextAccessor = httpContextAccessor; } public void Initialize(ITelemetry telemetry) { SetApplicationNameToRoleName(telemetry); SetEnvironmentNameToRoleInstanceAddingDate(telemetry); SetAMachine(telemetry); } private void SetApplicationNameToRoleName(ITelemetry telemetry) { telemetry.Context.GlobalProperties["MachineName"] = Environment.MachineName; } private void SetAMachine(ITelemetry telemetry) { var appName = _configuration.GetValue<string>("AppSettings:ApplicationName"); if (string.IsNullOrEmpty(appName)) return; telemetry.Context.Cloud.RoleName = appName; } private void SetEnvironmentNameToRoleInstanceAddingDate(ITelemetry telemetry) { var environmentName = _configuration.GetValue<string>("AppSettings:Environment"); var dc = _configuration.GetValue<string>("AppSettings:WarehouseNumber"); if (string.IsNullOrEmpty(environmentName) || string.IsNullOrEmpty(dc)) return; telemetry.Context.Cloud.RoleInstance = $"{environmentName}-{dc}"; } }
Program.cs注册代码:
builder.Services.AddLogging(builder.Configuration);
问题:期望所有未处理异常都能被记录至Application Insights,但编排API调用其他API超时抛出的异常未被记录。调整AddControllers注册顺序后,能看到异常发生前的日志,但异常本身仍未被捕获记录。
解决方案
1. 确保全局异常中间件正确记录异常
如果项目使用了自定义全局异常处理中间件,必须在捕获异常后明确记录日志,避免吞掉异常导致Application Insights无法捕获:
public class ExceptionHandlingMiddleware { private readonly RequestDelegate _next; private readonly ILogger<ExceptionHandlingMiddleware> _logger; public ExceptionHandlingMiddleware(RequestDelegate next, ILogger<ExceptionHandlingMiddleware> logger) { _next = next; _logger = logger; } public async Task InvokeAsync(HttpContext context) { try { await _next(context); } catch (Exception ex) { // 强制记录异常日志,Application Insights会捕获这条日志 _logger.LogError(ex, "未处理异常"); // 后续响应处理逻辑... } } }
2. 修正Application Insights注册逻辑
当前代码中存在重复调用AddApplicationInsightsTelemetry()的问题,会导致配置冲突。修改扩展方法,合并注册逻辑并明确开启异常跟踪:
public static IServiceCollection AddLogging(this IServiceCollection services, IConfiguration configuration) { // 确保HttpContextAccessor已注册,自定义初始化器依赖它 services.AddHttpContextAccessor(); return services.AddLogging(logging => { logging.ClearProviders(); logging.AddConsole(); logging.AddEventLog(config => { config.SourceName = Assembly.GetExecutingAssembly().FullName; }); logging.AddConfiguration(configuration.GetSection("Logging")); logging.AddApplicationInsights( config => { config.ConnectionString = configuration.GetSection("Logging:ApplicationInsights:ConnectionString").Value; config.EnableAdaptiveSampling = true; }, options => { options.FlushOnDispose = true; options.TrackExceptions = true; // 明确开启异常跟踪 }); logging.AddDebug(); }) .SetupStorageFolderForTelemetryChannel(configuration); } private static IServiceCollection SetupStorageFolderForTelemetryChannel(this IServiceCollection services, IConfiguration configuration) { services.AddSingleton<ITelemetryInitializer, CustomTelemetryInitializer>(); var configuredStorageFolder = configuration.GetValue<string>("ApplicationInsights:StorageFolder"); if (string.IsNullOrEmpty(configuredStorageFolder)) return services; // 不再重复调用AddApplicationInsightsTelemetry var baseFolder = AppContext.BaseDirectory; var storageFolder = Path.Combine(baseFolder, configuredStorageFolder); var f = new DirectoryInfo(storageFolder); if (!f.Exists) f.Create(); return services.AddSingleton(typeof(ITelemetryChannel), new ServerTelemetryChannel { StorageFolder = storageFolder }); }
3. 调整日志级别配置
确保Application Insights能捕获Error级别的日志(异常默认以Error级别记录),修改配置文件:
{ "Logging": { "LogLevel": { "Default": "Information" }, "ApplicationInsights": { "LogLevel": { "Default": "Information", "Microsoft": "Error", "MyApplication": "Error" // 添加项目命名空间的Error级别日志捕获 }, "ConnectionString": "InstrumentationKey" } } }
4. 验证异步代码的异常处理
超时异常通常以TaskCanceledException形式抛出,确保异步方法没有使用async void(这类方法的异常无法被全局捕获),且异常没有被静默处理:
// 正确示例:返回Task的异步方法 public async Task CallExternalApi() { try { await _httpClient.GetAsync("https://external-api.example.com"); } catch (TaskCanceledException ex) { _logger.LogError(ex, "调用外部API超时"); throw; // 重新抛出异常,让全局捕获机制处理 } }
5. 明确启用异常跟踪
在Program.cs中补充配置,确保Application Insights的异常跟踪功能开启:
builder.Services.AddApplicationInsightsTelemetry(options => { options.EnableExceptionTracking = true; });
内容的提问来源于stack exchange,提问作者Harish Ninge Gowda
相关产品推荐
相关产品推荐

