正确安装Serilog需用NuGet安装Serilog及对应输出扩展(如Serilog.Sinks.Console),初始化必须在Main方法开头执行Log.Logger配置,否则日志静默失败;中文乱码需设Console.OutputEncoding=UTF8;结构化日志须用占位符传参而非字符串拼接;ASP.NET Core中用UseSerilog()替换默认日志并配合Enrich.FromLogContext与LogContext.PushProperty注入上下文。

如何在.NET项目中正确安装并初始化Serilog
直接用 NuGet 安装两个核心包就够了:Serilog 和对应输出目标的扩展,比如控制台用 Serilog.Sinks.Console,文件用 Serilog.Sinks.File。别装 Serilog.AspNetCore 除非你用的是 ASP.NET Core —— 普通 .NET Framework 或 .NET 6+ 控制台项目不需要它。
初始化必须在 Main 方法最开头做,早于任何日志调用:
Log.Logger = new LoggerConfiguration()
.WriteTo.Console()
.WriteTo.File("logs/log-.txt", rollingInterval: RollingInterval.Day)
.CreateLogger();
漏掉这句或放错位置,后续所有 Log.Information(...) 都会静默失败(不是报错,是根本没输出)。
Serilog.WriteTo.Console() 输出中文乱码怎么办
默认控制台编码是 ANSI,Windows 上常见 GBK 环境下中文变问号。这不是 Serilog 的问题,是 Console 自身限制。
解决方式只有两种:
- 启动程序前执行
chcp 65001切换到 UTF-8(临时有效) - 在代码里加一句
Console.OutputEncoding = Encoding.UTF8;,且必须放在Log.Logger = ...之前
注意:.NET Core 3.0+ 默认支持 UTF-8 控制台,但若项目降级兼容旧框架,仍需手动设置。
结构化日志怎么写才真正“结构化”
关键不是用 Log.Information,而是用占位符传参,而不是字符串拼接:
// ✅ 正确:生成带 property 的结构化事件
Log.Information("User {UserId} logged in from {IpAddress}", userId, ip);
// ❌ 错误:只是普通字符串,无字段可查
Log.Information($"User {userId} logged in from {ip}");
这样写之后,日志目标(如 Seq、Elasticsearch)才能把 UserId 和 IpAddress 当成独立字段过滤或聚合。如果值是对象,Serilog 会自动序列化其公共属性——但别传 this 或大集合,容易拖慢性能或泄露敏感数据。
ASP.NET Core 中如何替换默认 ILogger 并注入上下文信息
在 Program.cs(.NET 6+)或 Startup.ConfigureServices(.NET 5 及以前)里,用 UseSerilog() 替换掉 Microsoft 的日志系统:
var builder = WebApplication.CreateBuilder(args);
builder.Host.UseSerilog((ctx, lc) => lc
.WriteTo.Console()
.ReadFrom.Configuration(ctx.Configuration));
然后用 ILogger 注入即可,和原来完全兼容。想自动带上请求 ID、路径等?加 .Enrich.FromLogContext(),并在中间件里用 LogContext.PushProperty:
app.Use(async (ctx, next) =>
{
LogContext.PushProperty("Path", ctx.Request.Path);
await next();
});
不加 Enrich.FromLogContext(),PushProperty 就无效;不配中间件,Web 请求日志就缺上下文——这两步缺一不可。
结构化日志真正的门槛不在配置,而在写日志时是否习惯用命名参数、是否理解 LogContext 的作用域边界、以及是否意识到日志输出目标对字段解析能力的依赖。










