C#.NET Serilog 结构化日志全解析

阅读 27

07-22 06:00

C#.NET Serilog 详解

Serilog 是 .NET 生态中强大的结构化日志记录库,通过事件属性和丰富输出格式,显著提升日志的可分析性和可观测性。以下是核心概念与使用详解:

一、核心特性
  1. 结构化日志
    将日志转化为键值对数据结构:

Log.Information("订单 {OrderId} 处理完成,金额:{Amount}", order.Id, order.Total);

输出为结构化数据(如 JSON),便于 ELK/Splunk 等工具分析。

  1. 灵活的 Sink 系统
    支持 100+ 输出目标:
  • 控制台:Serilog.Sinks.Console
  • 文件:Serilog.Sinks.File
  • Seq:Serilog.Sinks.Seq (专为 Serilog 设计的日志服务器)
  • Elasticsearch/数据库/Email 等
  1. 动态日志级别
    运行时动态调整日志级别:

Log.Logger = new LoggerConfiguration()
    .MinimumLevel.ControlledBy(new LoggingLevelSwitch(LogEventLevel.Information)) // 初始级别
    .CreateLogger();

// 运行时动态调整为 Debug
var levelSwitch = Log.Logger.GetLevelSwitch();
levelSwitch.MinimumLevel = LogEventLevel.Debug;

二、基础配置

using Serilog;

// 创建 Logger
Log.Logger = new LoggerConfiguration()
    .MinimumLevel.Debug()                         // 全局最小日志级别
    .WriteTo.Console()                            // 输出到控制台
    .WriteTo.File("logs/log-.txt", 
        rollingInterval: RollingInterval.Day)     // 每日滚动日志
    .Enrich.WithThreadId()                        // 附加线程ID
    .CreateLogger();

// 记录日志
Log.Information("服务启动");
Log.Error(ex, "处理订单失败,ID: {OrderId}", orderId);

// 程序退出时释放资源
Log.CloseAndFlush();

三、高级功能
  1. 日志上下文增强
    使用 LogContext 附加上下文信息:

using (LogContext.PushProperty("RequestId", Guid.NewGuid()))
{
    Log.Information("处理请求"); // 自动附加 RequestId
}

  1. 自定义输出模板
    控制日志格式:

.WriteTo.Console(outputTemplate:
    "[{Timestamp:HH:mm:ss} {Level:u3}] {Message:lj} {Properties}{NewLine}{Exception}")

  1. 异步日志写入
    使用缓冲队列提升性能:

.WriteTo.Async(a => a.File("logs/async-log.txt"))

  1. 日志过滤
    按条件过滤日志:

.Filter.ByExcluding(e => e.Properties["SourceContext"].ToString().Contains("NoisyComponent"))

四、与依赖注入集成

在 ASP.NET Core 中配置:

// Program.cs
builder.Host.UseSerilog((ctx, config) => 
    config.ReadFrom.Configuration(ctx.Configuration));

// appsettings.json
{
  "Serilog": {
    "MinimumLevel": "Information",
    "WriteTo": [
      { "Name": "Console" },
      { 
        "Name": "File", 
        "Args": { "path": "logs/log.txt" } 
      }
    ],
    "Enrich": [ "WithThreadId" ]
  }
}

五、最佳实践
  1. 异常日志标准化
    始终传递异常对象:

try { /* ... */ }
catch (Exception ex) {
    Log.Error(ex, "操作失败"); // 包含堆栈信息
}

  1. 避免字符串拼接
    使用模板参数代替拼接:

// 推荐
Log.Debug("用户 {UserId} 登录", user.Id);

// 避免
Log.Debug($"用户 {user.Id} 登录"); // 影响性能

  1. 关键业务附加属性
    为关键操作添加业务维度:

Log.ForContext("Order", new { order.Id, order.Status })
   .Information("订单状态更新");

六、性能优化
  • 使用 Logger.IsEnabled(LogLevel) 避免高开销操作:

if (Log.IsEnabled(LogEventLevel.Debug)) {
    var data = ExpensiveDataQuery();
    Log.Debug("数据: {Data}", data);
}

  • 异步 Sink 减少 I/O 阻塞
  • 控制日志量(避免 Verbose 级生产环境日志)

通过结构化日志和丰富生态系统,Serilog 显著提升 .NET 应用的运维效率和故障排查能力。建议结合 Seq 或 ELK 实现可视化日志分析。

精彩评论(0)

0 0 举报