如何配置Serilog与Sentry忽略指定异常?从配置文件读取忽略列表
解决Serilog+Sentry忽略指定异常不生效的问题
问题根源
- 配置的异常类型不完整:你在appsettings.json里只写了
NotImplementedException,但代码中判断的是异常类型的完整命名空间+类型名(比如System.NotImplementedException),导致匹配失败。 - Sentry中间件与Serilog的冲突:
builder.WebHost.UseSentry()会独立捕获未处理异常,绕开Serilog的过滤逻辑。 - 过滤逻辑仅检查顶层异常:未考虑异常链中的内部异常,若异常被包装则无法被识别。
分步解决方案
1. 修正配置文件的异常类型
修改appsettings.json中Serilog:IgnoreList:ExceptionTypes,补充完整命名空间:
{ "Logfile": {"Name": "/logs/log-Service-.txt"}, "Sentry": {"Dsn": "https://sentry.dns"}, "Serilog": { "IgnoreList": { "ExceptionTypes": ["System.NotImplementedException"] } }, "ConnectionStrings": {"DefaultConnection": "myconnection"} }
2. 优化Serilog的Sentry过滤逻辑
更新SetBeforeSend逻辑,递归检查整个异常链:
public static class HostBuilderExtensions { public static IHostBuilder UseCustomSerilog(this IHostBuilder builder, IConfiguration configuration) { var ignoreList = configuration.GetSection("Serilog:IgnoreList:ExceptionTypes").Get<string[]>() ?? Array.Empty<string>(); return builder.UseSerilog((context, config) => { config.MinimumLevel.Verbose() .MinimumLevel.Override("Microsoft", LogEventLevel.Fatal) .WriteTo.Udp( remoteAddress: configuration.GetSection("Logstash")["Host"] ?? throw new InvalidOperationException(), remotePort: int.Parse(configuration.GetSection("Logstash")["Port"] ?? throw new InvalidOperationException()), family: AddressFamily.InterNetwork, formatter: new CompactJsonFormatter() ) .Enrich.WithProperty("type", configuration.GetSection("Logstash")["Type"] ?? throw new InvalidOperationException()) .WriteTo.File( new CompactJsonFormatter(), configuration.GetSection("Logfile")["Name"] ?? throw new InvalidOperationException(), rollingInterval: RollingInterval.Day ) .WriteTo.Console() .WriteTo.Sentry(o => { o.Dsn = configuration.GetSection("Sentry")["Dsn"]; o.MinimumEventLevel = LogEventLevel.Error; o.MinimumBreadcrumbLevel = LogEventLevel.Error; o.SetBeforeSend((sentryEvent, _) => { if (ShouldIgnoreException(sentryEvent.Exception, ignoreList)) { Console.WriteLine("Ignored"); return null; } return sentryEvent; }); }) .Enrich.FromLogContext(); }); } // 递归检查异常链的辅助方法 private static bool ShouldIgnoreException(Exception? ex, IEnumerable<string> ignoreTypes) { if (ex == null) return false; // 检查当前异常是否在忽略列表 if (ignoreTypes.Contains(ex.GetType().FullName)) { return true; } // 递归检查内部异常 return ShouldIgnoreException(ex.InnerException, ignoreTypes); } }
3. 处理Sentry中间件的冲突
以下两种方案任选其一:
方案A:禁用Sentry自身的异常捕获
让所有异常都通过Serilog处理,关闭Sentry中间件的自动捕获:
var builder = WebApplication.CreateBuilder(args); builder.Services.AddControllers(); builder.Services.AddEndpointsApiExplorer(); builder.Services.AddSwaggerGen(); // 修改Sentry配置,禁用自动捕获 builder.WebHost.UseSentry(options => { options.Dsn = builder.Configuration.GetSection("Sentry")["Dsn"]; options.EnableGlobalErrorCapture = false; // 关闭全局异常捕获 options.AutoSessionTracking = false; options.CaptureConsole = false; }); builder.Host.UseCustomSerilog(builder.Configuration); // 后续代码不变...
方案B:在Sentry中间件中添加过滤
若需要保留Sentry中间件的其他功能,同步添加配置文件中的忽略规则:
var builder = WebApplication.CreateBuilder(args); builder.Services.AddControllers(); builder.Services.AddEndpointsApiExplorer(); builder.Services.AddSwaggerGen(); var ignoreList = builder.Configuration.GetSection("Serilog:IgnoreList:ExceptionTypes").Get<string[]>() ?? Array.Empty<string>(); builder.WebHost.UseSentry(options => { options.Dsn = builder.Configuration.GetSection("Sentry")["Dsn"]; // 从配置文件添加异常过滤 foreach (var typeName in ignoreList) { var exceptionType = Type.GetType(typeName); if (exceptionType != null) { // 通过反射调用泛型方法添加过滤 var filterMethod = typeof(SentryAspNetCoreOptionsExtensions) .GetMethod(nameof(SentryAspNetCoreOptionsExtensions.AddExceptionFilterForType)) ?.MakeGenericMethod(exceptionType); filterMethod?.Invoke(null, new[] { options }); } } }); builder.Host.UseCustomSerilog(builder.Configuration); // 后续代码不变...
内容的提问来源于stack exchange,提问作者Ahmed Elshorbagy
相关产品推荐
相关产品推荐

