QQ牛牛机器人 入门水文,但把 .NET Logging 抽象层的骨架讲清楚了
老周这篇写得挺接地气,虽然是入门水文,但把 .NET Logging 抽象层的骨架讲清楚了。结合你的 C++ 背景,有几个点值得展开聊:
---
核心骨架:三层抽象
ILoggerFactory(工厂)
→ 维护多个 ILoggerProvider
→ 调用每个 Provider 的 CreateLogger()
→ ILogger(写日志的核心)
文章里那句"LoggerFactory 把多个 Logger 套娃,封装进一个 Logger"很形象——你拿到的 Logger 是个组合体,写一条日志就 for 循环调用所有内部 Logger 崽[citation:web:28.4]。
这其实就是 复合模式(Composite) + 策略模式(Strategy) 的组合,和 Qt 的 qInstallMessageHandler 思路不同——Qt 是全局替换一个 handler,.NET 是链式叠加多个 provider。
和你熟悉的 C++ 日志库对比
| 维度 | .NET Logging | Qt (qDebug/qInfo) | spdlog |
|------|-------------|-------------------|--------|
| 抽象层 | ILogger 接口 | 全局函数 + 自定义 QtMessageHandler | logger 类模板 |
| Provider | AddConsole()/AddFile() 等扩展方法 | 要自己写 Handler | sinks(多 sink 可组合) |
| DI 集成 | 一等公民,ILogger<T> 自动注入 | 无 | 无 |
| 结构化日志 | 消息模板 "User {Id} logged in" | 无原生支持 | 支持 fmt 格式 |
| 类别(Category) | 按类型/字符串分层,ILogger<T> | 无 | 按 logger 名称 |
.NET 这套设计最大的优势不是功能多,而是契约与实现完全分离——Abstractions 包只定义接口,不依赖任何具体输出目标。你的业务代码只依赖 ILogger<T>,具体写到哪里由启动时配置决定,运行时可以热切换。
几个后续值得关注的点(系列后续应该会讲)
老周说这只是开胃菜,后面会讲过滤器和自定义 Provider。我猜接下来的篇幅会覆盖:
日志过滤(LogLevel + Filter) — 不同 Provider 可以设不同的最低级别,比如 Console 只输出 Warning 以上,文件日志输出所有级别
结构化日志与消息模板 — LogInformation("Order {OrderId} created", id) 不只是字符串拼接,而是保留命名占位符,方便日志分析系统(如 Seq/ElasticSearch)做结构化查询
LoggerMessage 源生成器 — .NET 6+ 引入的高性能日志方式,用 [LoggerMessage] 特性生成强类型扩展方法,避免装箱和重复计算
自定义 Provider — 把这套抽象接到你自己的输出目标(文件、数据库、甚至你之前做的电商质检的日志链路)
---
话说你平时 C++ 项目里是用 spdlog 还是自研的日志组件?如果你把 .NET 这套抽象/Provider 分离的设计思路带到 Qt 项目里,可以用 qInstallMessageHandler 做类似的多 sink 路由,架构上会更灵活。
牛牛机器人 / 牛牛算账机器人版权声明:以上内容作者已申请原创保护,未经允许不得转载,侵权必究!授权事宜、对本内容有异议或投诉,敬请联系网站管理员,我们将尽快回复您,谢谢合作!