Serilog写入Windows事件日志时无法识别正确Event ID的求助
解决Serilog写入Windows事件日志的Event ID与消息异常问题
核心问题分析
Windows事件日志要求事件源必须关联已注册的消息资源DLL,Serilog默认的EventLog Sink是直接写入原始文本,未通过消息ID关联资源文件,导致系统提示“Event ID无法识别”,同时会附加Serilog模板格式的冗余内容。
可行解决方案
方案1:自定义Serilog EventLog Sink,调用原生EventLog API
放弃Serilog自带的EventLog Sink,实现自定义Sink直接调用EventLog.WriteEntry,手动控制Event ID与消息格式:
public class CustomEventLogSink : ILogEventSink { private readonly string _source; private readonly string _logName; private readonly Dictionary<LogEventLevel, EventLogEntryType> _levelMap = new() { { LogEventLevel.Verbose, EventLogEntryType.Information }, { LogEventLevel.Debug, EventLogEntryType.Information }, { LogEventLevel.Information, EventLogEntryType.Information }, { LogEventLevel.Warning, EventLogEntryType.Warning }, { LogEventLevel.Error, EventLogEntryType.Error }, { LogEventLevel.Fatal, EventLogEntryType.Error } }; public CustomEventLogSink(string source, string logName) { _source = source; _logName = logName; if (!EventLog.SourceExists(source)) { EventLog.CreateEventSource(source, logName); } } public void Emit(LogEvent logEvent) { var message = logEvent.RenderMessage(); var entryType = _levelMap[logEvent.Level]; // 自定义Event ID映射,可根据业务需求调整 int eventId = logEvent.Level switch { LogEventLevel.Information => 1000, LogEventLevel.Warning => 2000, LogEventLevel.Error => 3000, _ => 0 }; using var eventLog = new EventLog(_logName); eventLog.Source = _source; eventLog.WriteEntry(message, entryType, eventId); } }
替换原Serilog配置中的EventLog Sink:
// 替换原WriteTo.EventLog代码块 loggerConfig.WriteTo.Sink(new CustomEventLogSink( Settings.Default.EventLogSource, Settings.Default.EventLogName), lel);
方案2:修复消息资源DLL的注册与关联
若坚持使用Serilog自带的EventLog Sink,需确保以下配置正确:
- 消息资源DLL(EventMessages.dll)需与应用程序架构(32/64位)完全匹配
- 注册表项配置准确:
- 路径:
HKLM\SYSTEM\CurrentControlSet\Services\EventLog\[日志名]\[事件源] - 添加
EventMessageFile值,内容为[你的DLL完整路径];%SystemRoot%\System32\eventlog.dll - 设置
TypesSupported值为7(支持信息、警告、错误类型)
- 路径:
- 为Serilog指定自定义Event ID提供器:
loggerConfig.WriteTo.EventLog( source: Settings.Default.EventLogSource, logName: Settings.Default.EventLogName, restrictedToMinimumLevel: lel, eventIdProvider: new CustomEventIdProvider() ); public class CustomEventIdProvider : IEventIdProvider { public ushort ComputeEventId(LogEvent logEvent) { // 根据日志级别返回预定义Event ID return logEvent.Level switch { LogEventLevel.Information => 1000, LogEventLevel.Warning => 2000, LogEventLevel.Error => 3000, _ => 0 }; } }
方案3:消除DuplicateFilterSink的干扰
自定义DuplicateFilterSink生成的重复计数消息未分配有效Event ID,会加重异常问题。可修改该Sink为重复消息分配固定Event ID(如4000),或暂时移除该Sink验证核心日志功能:
// 在DuplicateFilterSink的Emit方法中,为重复计数消息添加固定Event ID LogEvent duplicateEvent = new LogEvent( logEvent.Timestamp, logEvent.Level, logEvent.Exception, duplicateTemplate, duplicateProperties.Concat(new[] { new LogEventProperty("EventId", new ScalarValue(4000)) }).ToArray() );
验证步骤
- 卸载现有WiX安装的服务,清理事件源对应的注册表项
- 重新部署服务,确保资源DLL与注册表项配置正确
- 测试日志写入,检查事件日志的Event ID是否正常显示,无冗余错误提示
内容的提问来源于stack exchange,提问作者Dogulas
相关产品推荐
相关产品推荐

