C# Serilog配置方法 C#如何集成Serilog进行结构化日志记录

正确安装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.AspNetC

ore 除非你用的是 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)才能把 UserIdIpAddress 当成独立字段过滤或聚合。如果值是对象,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 的作用域边界、以及是否意识到日志输出目标对字段解析能力的依赖。