EventLog 类可读取系统日志(如"System"),无需管理员权限但需确保读取权限;写入自定义日志须预先注册事件源(需管理员权限),且仅限 Windows 平台,.NET Core/5+ 需手动引用 System.Diagnostics.EventLog 包并禁用裁剪。

怎么用 EventLog 类读取系统日志
直接读系统日志(比如 System 或 Application)不需要管理员权限,但必须确保程序有对应日志的读取权限——默认多数用户能读,但某些自定义日志源可能被禁用。
常见错误是传错日志名:"System" 和 "system" 不一样,大小写敏感;另外 "Security" 日志默认拒绝普通用户读取,会抛出 UnauthorizedAccessException。
- 用
EventLog.GetEventLogs()列出所有可用日志,确认名字拼写和访问状态 - 读取前先检查
EventLog.Exists(logName)和EventLog.SourceExists(sourceName),避免运行时报ArgumentException - 批量读取时别直接遍历
Entries集合(它会一次性加载全部日志,内存暴涨),改用EventLog.EntryWritten事件监听新增条目,或分页查EventLog.ReadEntry()+ 索引定位
var log = new EventLog("System", "."); // "." 表示本地机器
log.EnableRaisingEvents = true;
log.EntryWritten += (s, e) => Console.WriteLine(e.Entry.Message);
怎么安全地写入自定义事件日志
写日志不是调个 WriteEntry 就完事。Windows 要求:写入前必须注册事件源(Source),且该源必须绑定到某个日志(Log),否则抛 InvalidOperationException:“源不存在”。
注册源需要管理员权限,但写入不需要——所以部署时得提前用管理员身份跑一次注册逻辑,或者用安装程序完成。
- 不要在每次写日志前都调
EventLog.CreateEventSource(),它会失败(已存在时抛异常),应只在首次启动或安装时执行 - 注册时指定日志名,如
"MyAppLog",后续写入就自动落到这个日志里;不指定则默认进"Application" -
WriteEntry的eventID必须是 1–65535 范围内整数,超出会静默截断或报错;EventType只能是Information、Warning、Error、SuccessAudit、FailureAudit
if (!EventLog.SourceExists("MyApp"))
EventLog.CreateEventSource("MyApp", "MyAppLog");
var log = new EventLog("MyAppLog", ".", "MyApp");
log.WriteEntry("服务启动完成", EventLogEntryType.Information, 1001);
为什么 EventLog 在 .NET Core/.NET 5+ 中受限
原生 EventLog 类在 System.Diagnostics.EventLog 命名空间下,但仅限 Windows 平台,且 .NET Core 3.1+ 默认不包含——需手动加 NuGet 包 System.Diagnostics.EventLog,否则编译就报错“类型未找到”。
更关键的是:.NET 6+ 默认启用“单文件发布”和“裁剪”,可能把事件日志相关反射逻辑裁掉,导致运行时报 PlatformNotSupportedException。
- 项目文件中显式添加
- 发布时加
--no-self-contained或在.csproj里设false - 跨平台需求强烈的话,别硬扛
EventLog,改用ILogger+ 文件/Syslog 输出,再由外部工具(如 NXLog)转发到 Windows 事件日志
权限和部署时最容易漏的三件事
开发机上跑通 ≠ 上线能用。很多问题卡在环境差异,而不是代码本身。
- 安装服务或后台程序时,如果用 LocalSystem 账户,它默认有写
Application日志权限,但没权写自定义日志(除非你注册源时指定了该账户上下文) - GPO(组策略)可能禁用事件日志写入,尤其在域环境中,检查
Computer Configuration → Administrative Templates → Windows Components → Event Log Service - 日志文件达到上限(默认 20MB)后,默认行为是“按需覆盖旧事件”,但若设成
OverwriteAsNeeded = false且磁盘满,后续写入直接失败,无提示
最常被忽略的是:注册事件源时没指定机器名,导致在远程服务器上用 "." 指向本地,而实际要写的是另一台机器——这时得传目标主机名,并确保防火墙放开 RPC 端口(且对方开启了 Remote Registry 服务)。











