ILogger 实例由 ASP.NET Core 内置 DI 容器提供,通过构造函数注入;不可手动 new LoggerFactory;结构化日志需用 {FieldName} 占位符传参;生产环境需显式添加文件等日志提供程序并配置权限与级别。

ILogger 实例从哪来?别手动画 new
ASP.NET Core 项目里,ILogger 不是靠 new 出来的,而是由内置的依赖注入容器提供。你直接在控制器、服务类或中间件的构造函数里声明参数,框架自动塞进来。
常见错误:自己写 new LoggerFactory().CreateLogger —— 这会绕过配置、丢失作用域(如请求 ID)、无法统一管理日志级别。
- Web API / MVC 控制器中直接写:
public MyController(ILoggerlogger) - 普通服务类也一样,只要注册进 DI 容器(比如
services.AddScoped),就能在构造函数里接() ILogger - 如果非要在静态上下文或 Program.cs 顶层代码里用,优先取
app.Services.GetRequiredService,而不是自己 new>()
LogInformation 和 LogError 的参数怎么传才不丢上下文
LogInformation、LogError 等方法看起来只接受字符串,但背后支持结构化日志 —— 关键是用占位符 + 后续参数,不是字符串拼接。
错误做法:logger.LogInformation("User " + userId + " failed login"); → 日志变成纯文本,没法按 userId 字段过滤或聚合。
- 正确写法:
logger.LogInformation("Login failed for user {UserId}", userId)→{UserId}会被识别为结构化字段,值单独存储 - 多个参数就挨个跟上:
logger.LogWarning("Failed to process order {OrderId} after {RetryCount} retries", orderId, retryCount) - 避免在占位符里写表达式,比如
{user.Name}—— 会当作文本字面量,不会求值;应拆成{UserName}并传user.Name
为什么本地能看到日志,部署到 IIS 或 Linux 就没了
默认情况下,ASP.NET Core 只启用 Console 和 Debug 日志提供程序,而这两者在生产环境往往不可见或被截断。
IIS 下 Console 输出被重定向且可能被回收;Linux systemd 服务默认不显示 Console 日志;同时,日志级别默认是 Information,但某些提供程序(如文件)可能没显式配置,导致“写了但没地方存”。
- 检查
Program.cs是否调用了builder.Logging.AddConsole()(开发够用,生产建议换) - 生产环境推荐加文件日志:
builder.Logging.AddFile("logs/myapp-{Date}.txt"),需先dotnet add package Microsoft.Extensions.Logging.File - 确认
appsettings.Production.json中"Logging": { "LogLevel": { "Default": "Warning" } }没把Information级别拦在外面 - Linux 上还要检查进程对日志目录是否有写权限,路径别用
~或相对路径
自定义日志范围(BeginScope)什么时候该用
BeginScope 不是为了“让日志更花哨”,而是给一批日志打上可追踪的上下文标签,比如请求 ID、订单号、用户 ID —— 特别适合排查分布式调用或并发请求中的日志混乱问题。
滥用表现:每个方法开头都 using var scope = logger.BeginScope("Entering method X") → 日志膨胀、嵌套深、实际检索价值低。
- 真正该用的地方:进 HTTP 请求时,在中间件里统一加
logger.BeginScope(new EventId(100), "Request={TraceId}", httpContext.TraceIdentifier) - 处理特定业务实体时:
using var _ = logger.BeginScope("OrderId={OrderId}", orderId),后续该作用域内所有日志自动带上OrderId字段 - 注意:Scope 是异步本地存储(AsyncLocal),跨
await依然有效;但手动开的using块必须配对,否则字段泄漏到其他请求
结构化日志字段名大小写、空格、特殊字符都影响后续查询,比如 {user_id} 和 {UserId} 在 Kibana 里是两个字段;Scope 嵌套过深会导致日志体积翻倍,这些细节上线前不验证,出问题时只能干瞪眼。










