控制台应用如何实现三类日志输出,是否需要使用SeriLog组件?
问题解答
核心结论
- 完全不需要依赖Serilog这类第三方组件即可实现你的需求,但使用成熟日志组件可大幅减少重复开发成本,避免踩入各类日志处理的底层坑。
自行实现ILogger的方案
如果你坚持要自己开发实现,步骤如下:
- 自定义实现
ILogger接口,内部维护线程安全的内存队列(比如ConcurrentQueue<string>)存储本次运行的所有日志内容 - 在
Log方法中同步完成三个操作:日志输出到控制台、日志写入本地文件、日志内容追加到内存队列 - 配套实现
ILoggerProvider,将自定义Logger注入到依赖注入容器中,满足类库要求的ILogger传入需求 - 应用运行结束时,直接读取内存队列中存储的全部日志即可用于发送邮件,完全不需要读取本地历史日志文件
注意:自行实现需要额外处理多线程并发写入安全、日志级别过滤、日志文件按大小/时间自动滚动、IO异常兜底、异步写入避免阻塞业务线程等问题,这类边缘场景的代码量会远大于核心功能代码。
基于Serilog的极简实现方案
如果使用Serilog,只需要几行配置即可完美匹配所有需求,无需处理底层细节:
- 安装对应NuGet包:
Serilog.AspNetCore、Serilog.Sinks.Console、Serilog.Sinks.File、Serilog.Sinks.InMemory - 初始化日志配置:
// 配置Serilog Log.Logger = new LoggerConfiguration() .MinimumLevel.Information() // 输出到控制台 .WriteTo.Console() // 写入本地文件,自动按天滚动 .WriteTo.File("logs/run.log", rollingInterval: RollingInterval.Day) // 写入内存存储本次运行日志 .WriteTo.InMemory(out var currentRunLogs) .CreateLogger(); // 适配ILogger接口注入到DI容器 var host = Host.CreateDefaultBuilder(args) .ConfigureLogging(logging => logging.ClearProviders().AddSerilog()) .Build();
- 应用退出前,直接读取
currentRunLogs内的所有日志条目格式化后即可发送邮件,不需要读取本地历史日志文件。
为什么普遍推荐用Serilog这类组件
- 已内置处理所有日志相关的边缘场景:并发写入、文件滚动、日志格式化、级别过滤、作用域支持等,不需要自行开发测试
- 性能经过大量生产环境验证,远高于大多数自行实现的日志方案
- 扩展成本极低,后续如果需要新增日志上报、结构化日志、日志过滤等需求,只需要加一行配置即可完成
内容的提问来源于stack exchange,提问作者Jonathan Wood
相关产品推荐
相关产品推荐

