You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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()
);

验证步骤

  1. 卸载现有WiX安装的服务,清理事件源对应的注册表项
  2. 重新部署服务,确保资源DLL与注册表项配置正确
  3. 测试日志写入,检查事件日志的Event ID是否正常显示,无冗余错误提示

内容的提问来源于stack exchange,提问作者Dogulas

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 08:48:13