用 ILogger
+ Microsoft.Extensions.Logging
是当前标准做法
ASP.NET Core 项目默认内置,.NET 6+ 桌面应用也推荐直接用它,而不是手写文件写入或老式
Trace。核心是依赖注入 + 预置提供程序(如控制台、Debug、文件),不耦合具体输出方式。
关键点:
ILogger<t></t>是泛型接口,
T一般填当前类类型,用于日志分类和过滤 必须通过 DI 容器获取实例(
Program.cs中
builder.Services.AddLogging()已默认注册) 不要 new
Logger<t></t>—— 手动构造会丢失作用域上下文、配置和性能优化
想写入文件?别自己拼 StreamWriter
,用 FileLoggerProvider
或第三方包
.NET 原生不带文件日志提供程序,
Microsoft.Extensions.Logging.Console和
Debug是自带的,但
File需要额外引入。官方没推内置文件提供者,所以常见选择是: 用
Microsoft.Extensions.Logging.Configuration+
NLog或
Serilog(更推荐,配置灵活、支持滚动、结构化) 轻量场景可用社区维护的
Microsoft.Extensions.Logging.File(注意 NuGet 包名是
Microsoft.Extensions.Logging.File,不是官方第一方) 自己封装
ILoggerProvider成本高,且容易在并发写入、日志轮转、编码错误上翻车
示例(Serilog):
Log.Logger = new LoggerConfiguration().WriteTo.File("logs/log-.txt", rollingInterval: RollingInterval.Day).Create();然后在
Program.cs中调用
builder.Host.UseSerilog()
LogInformation
/ LogWarning
/ LogError
别乱用级别
日志级别不是“越详细越好”,它直接影响性能和可观测性:
LogDebug:仅开发期启用,发布后默认被过滤掉(除非显式配置最低级别为
Debug)
LogInformation:记录常规流程,比如“用户登录成功”,但别塞敏感字段(如密码明文、token)
LogWarning:异常未抛出但可能有问题,比如重试三次后降级处理
LogError:必须伴随
Exception对象传入(
logger.LogError(ex, "msg")),否则堆栈丢失
错误示范:
logger.LogError("Failed to connect: " + ex.Message) → 堆栈没了,无法定位根本原因
结构化日志里别用字符串拼接,用占位符
logger.LogInformation("User {UserId} logged in at {Time}", userId, DateTime.Now) 这样写,才能被 Serilog/NLog 正确提取字段、做筛选和聚合。
反模式:
logger.LogInformation($"User {userId} logged in at {DateTime.Now}") → 日志变成纯文本,所有结构化能力失效。
占位符名不强制匹配变量名,但建议一致;大括号内不能有空格或表达式(如
{userId.ToString()} 不合法)
复杂对象可直接传入,Serilog 会自动序列化(前提是启用了相关配置),但避免传入含循环引用或敏感属性的对象
