当前位置: 首页 > article >正文

Serilog详解

零、文章目录

Serilog详解

1、简介

(1)概述
  • Serilog 是一个用于 .NET 应用程序的结构化日志库,它允许开发者记录应用程序运行时的日志信息。相比于传统的字符串拼接日志,Serilog 提供了更强大的功能和灵活性,包括结构化的事件数据、丰富的输出格式、以及各种各样的接收端(sink)支持。
  • 官网:https://serilog.net/
(2)关键特性
  • 结构化事件:Serilog 记录的是结构化事件,而不是简单的文本消息。这意味着你可以将日志信息作为键值对存储,使得后续分析更加容易。
  • 丰富的内容:除了基本的日志信息外,Serilog 还可以记录异常堆栈跟踪、属性等复杂对象。
  • 多接收端支持:Serilog 支持多种接收端(sinks),可以将日志发送到文件、控制台、数据库、第三方服务(如 Seq, Elasticsearch, Splunk 等)等地方。
  • 过滤和级别控制:你可以根据不同的条件来过滤日志,并且可以为不同的接收端设置不同的日志级别(如 Debug, Information, Warning, Error, Fatal)。
  • 易于集成:Serilog 可以与 ASP.NET Core, .NET Framework 以及其他 .NET 平台无缝集成。

2、快速使用

(1)创建项目
  • 创建一个控制台项目,基于 net8
(2)安装NuGet包
  • Serilog:核心包
  • Serilog.Sinks.File:你想要使用的接收端包
dotnet add package Serilog -v 4.2.0
dotnet add package Serilog.Sinks.File -v 6.0.0
(3)配置及使用
  • 创建了一个新的 LoggerConfiguration
  • 设置了最低日志级别为 Debug
  • 配置了一个文件接收端,日志将被写入 logs/myapp.txt 文件
  • 每天生成一个新的日志文件。
Log.Logger = new LoggerConfiguration()
    .MinimumLevel.Debug()
    .WriteTo.File("logs/myapp.txt", rollingInterval: RollingInterval.Day)
    .CreateLogger();

try
{
    Log.Information("Application Starting Up");
}
catch (Exception ex)
{
    Log.Fatal(ex, "Application start-up failed");
}
finally
{
    Log.CloseAndFlush();
}
(4)输出日志
2025-02-11 20:23:24.404 +08:00 [INF] Application Starting Up

3、代码配置详解

(1)核心配置对象
  • **<font style="color:rgba(0, 0, 0, 0.9);">LoggerConfiguration</font>**用于构建日志记录管道的核心对象,通过链式方法配置日志记录行为。
(2)创建记录器
  • 使用 LoggerConfiguration 对象创建记录器,日志记录器是日志记录的主体。
  • 记录器创建完即可进行使用,都是使用的默认配置
Log.Logger = new LoggerConfiguration().CreateLogger();
Log.Information("No one listens to me!");
(3)接收器(Sinks)
  • 功能:将日志输出到外部媒介(如控制台、文件、数据库等)。
  • 常用接收器:
    • Serilog.Sinks.Console:
      • 作用: 将日志输出到控制台。
      • 适用场景: 适用于开发环境或需要即时查看日志的应用。
    • Serilog.Sinks.File:
      • 作用: 将日志写入文件中,支持按时间滚动(如每天创建一个新的日志文件)。
      • 适用场景: 适合于生产环境中长期保存日志。
    • Serilog.Sinks.Seq:
      • 作用: 将日志发送到 Seq 日志服务器,Seq 提供了强大的查询和可视化功能。
      • 适用场景: 适合需要集中管理和分析大量日志的团队。
    • Serilog.Sinks.Elasticsearch:
      • 作用: 将日志发送到 Elasticsearch,配合 Kibana 使用可以进行复杂的日志分析和可视化。
      • 适用场景: 适合大型应用或微服务架构中,需要对日志进行高级分析和监控。
    • Serilog.Sinks.MSSqlServer:
      • 作用: 将日志记录到 Microsoft SQL Server 数据库中。
      • 适用场景: 适合已有 SQL Server 基础设施的企业,或者需要将日志与其他业务数据一起存储的情况。
    • Serilog.Sinks.MySQL:
      • 作用: 将日志记录到 MySQL 数据库中。
      • 适用场景: 类似于 MSSqlServer,但针对使用 MySQL 数据库的环境。
    • Serilog.Sinks.Http:
      • 作用: 通过 HTTP POST 请求发送日志到远程 API 或服务。
      • 适用场景: 适合自定义的日志收集系统或第三方日志管理平台。
    • Serilog.Sinks.Email:
      • 作用: 通过电子邮件发送错误或其他关键日志信息。
      • 适用场景: 适合需要及时通知相关人员的关键事件。
    • Serilog.Sinks.ApplicationInsights:
      • 作用: 将日志发送到 Azure Application Insights,提供性能监控和诊断工具。
      • 适用场景: 适合部署在 Azure 上的应用程序。
  • 配置方法:
    • 首先根据需要安装对应 nuget 包
dotnet add package Serilog.Sinks.Console
dotnet add package Serilog.Sinks.File
- 使用 `WriteTo` 对象配置接收器
Log.Logger = new LoggerConfiguration()
.WriteTo.Console()
.CreateLogger();
- <font style="color:rgba(0, 0, 0, 0.9);">支持链式配置多个接收器。</font>多个接收器可以同时处于活跃状态。
Log.Logger = new LoggerConfiguration()
.WriteTo.Console()
.WriteTo.File("log.txt", rollingInterval: RollingInterval.Day)
.CreateLogger();
(4)输出模板(Output Template)
  • **作用:**基于文本的接收器使用输出模板来控制格式设置。通过 outputTemplate 参数进行修改:
  • 默认模板:包含时间戳、日志级别、消息和异常。
  • 自定义格式
Log.Logger = new LoggerConfiguration()
.WriteTo.File("log.txt",outputTemplate: "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level:u3}] {Message:lj}{NewLine}{Exception}")
.CreateLogger();
  • 特殊格式选项
    • <font style="color:rgba(0, 0, 0, 0.9);">{Level:u3}</font>:大写三字符级别(如 <font style="color:rgba(0, 0, 0, 0.9);">INF</font>)。
    • <font style="color:rgba(0, 0, 0, 0.9);">{Message:lj}</font>:消息中的嵌入数据以 JSON 格式输出。
(5)最低级别(Minimum Level)
  • 默认级别<font style="color:rgba(0, 0, 0, 0.9);">Information</font>(未配置时生效)。
  • 配置方式:通过 <font style="color:rgba(0, 0, 0, 0.9);">MinimumLevel</font> 设置全局最低级别。
Log.Logger = new LoggerConfiguration()
.MinimumLevel.Debug() // 处理 Debug 及更高级别事件 
.WriteTo.Console()
.CreateLogger();

日志级别分类

级别用途描述
Verbose最详细,通常不用于生产环境。
Debug内部调试信息,帮助定位问题。
Information系统正常运行时的可观测操作。
Warning服务降级或潜在问题。
Error功能不可用或预期中断。
Fatal需要立即处理的严重错误。
(5)覆盖接收器级别
  • 场景:不同接收器设置不同最低级别。
  • 关键规则:接收器级别只能“升高”,不能低于全局 <font style="color:rgba(0, 0, 0, 0.9);">MinimumLevel</font>
Log.Logger = new LoggerConfiguration()
.MinimumLevel.Debug() // 处理 Debug 及更高级别事件 
.WriteTo.File("log.txt") // 默认使用全局 Debug 级别 
.WriteTo.Console(restrictedToMinimumLevel: LogEventLevel.Information) // 仅处理 Information 及以上 
.CreateLogger();
(6)扩充器(Enrichers)
  • 作用:动态添加/修改日志事件的属性(如线程 ID、版本号)。
  • 常用扩充器:
    • Serilog.Enrichers.Environment: 添加有关运行时环境的信息,如操作系统版本、进程ID等。
    • <font style="color:rgba(0, 0, 0, 0.9);">Serilog.Enrichers.Thread</font>: 添加线程相关信息,如线程ID。
    • <font style="color:rgba(0, 0, 0, 0.9);">Serilog.Enrichers.Assembly</font>: 添加关于应用程序集的信息,如名称、版本号。
    • <font style="color:rgba(0, 0, 0, 0.9);">Serilog.Enrichers.ClientInfo</font>: 在 Web 应用程序中添加客户端信息,如 IP 地址、用户代理等。
    • <font style="color:rgba(0, 0, 0, 0.9);">Serilog.Enrichers.Property</font>: 允许你在配置时静态地添加任意属性到所有日志事件中。
Log.Logger = new LoggerConfiguration()
.WriteTo.Console()
.Enrich.WithThreadId() // 添加线程ID属性(需安装 Serilog.Enrichers.Thread)
.CreateLogger();
  • 自定义扩充器:需实现 <font style="color:rgba(0, 0, 0, 0.9);">ILogEventEnricher</font> 接口。
class ThreadIdEnricher : ILogEventEnricher
{
    public void Enrich(LogEvent logEvent, ILogEventPropertyFactory propertyFactory)
    {
        logEvent.AddPropertyIfAbsent(propertyFactory.CreateProperty(
                "ThreadId", Thread.CurrentThread.ManagedThreadId));
    }
}

Log.Logger = new LoggerConfiguration()
.Enrich.With(new ThreadIdEnricher())
.WriteTo.Console()
.CreateLogger();
  • 快捷方法:使用 <font style="color:rgba(0, 0, 0, 0.9);">WithProperty</font> 添加静态属性。
Log.Logger = new LoggerConfiguration()
.WriteTo.Console()
.Enrich.WithProperty("Version", "1.0.0")
.CreateLogger();
(7)过滤器(Filters)
  • 功能:按条件筛选日志事件。
  • **Serilog.Filters.Expressions**: 使用表达式语言来定义复杂的过滤规则。
  • 示例:排除 <font style="color:rgba(0, 0, 0, 0.9);">Count</font> 属性大于 10 的事件。
Log.Logger = new LoggerConfiguration()
.WriteTo.Console()
.Filter.ByExcluding(Matching.WithProperty<int>("Count", p => p < 10))
.CreateLogger();
(8)格式化器 (Formatters)
  • 格式化器用于控制日志消息的格式。
  • 常用的格式化器包括:
    • Serilog.Formatting.Compact: 提供紧凑的 JSON 格式的日志输出,适合机器读取。
    • Serilog.Formatting.Display: 允许你定义日志消息的文本模板,如 {Timestamp} [{Level}] {Message}{NewLine}{Exception}
(9)其他配置
  • Serilog.Settings.Configuration: 从应用程序配置文件(如 appsettings.json)中加载 Serilog 配置。
  • Serilog.AspNetCore: 提供 ASP.NET Core 的集成,自动记录请求和响应信息。
  • Serilog.Exceptions: 深度解析异常,提取更多细节并作为结构化数据记录。
  • Serilog.Sinks.PeriodicBatching: 为其他接收端提供批处理能力,减少 I/O 操作次数,提高性能。

4、使用配置文件进行配置

(1)创建项目
  • 创建一个控制台项目,基于 net8
(2)安装NuGet包
  • Serilog.Settings.Configuration:用于从配置文件中加载 Serilog 设置。
  • Microsoft.Extensions.Configuration.Json:加载 json 配置文件包。
dotnet add package Serilog.Settings.Configuration -v 9.0.0
dotnet add package Microsoft.Extensions.Configuration.Json -v 9.0.0
(3)配置文件
  • 创建配置文件 <font style="color:rgb(64, 64, 64);">appsettings.json</font>,确保这个文件被设置为始终复制。
{
  "Serilog": {
    "Using": ["Serilog.Sinks.File"],
    "MinimumLevel": "Information",
    "WriteTo": [
      {
        "Name": "File",
        "Args": {
          "path": "logs/log-.txt",
          "rollingInterval": "Day",
          "retainedFileCountLimit": 7,
          "outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level}] {Message}{NewLine}{Exception}"
        }
      }
    ],
    "Enrich": [ "FromLogContext", "WithMachineName" ]
  }
}
(4)代码实现
var configuration = new ConfigurationBuilder()
    .SetBasePath(Directory.GetCurrentDirectory())
    .AddJsonFile("appsettings.json")
    .Build();

// 创建 Logger
Log.Logger = new LoggerConfiguration()
    .ReadFrom.Configuration(configuration)
    .CreateLogger();

try
{
    Log.Information("程序启动");
    Log.Debug("这是一个调试信息");
    Log.Warning("示例警告信息");

    // 模拟业务逻辑
    for (int i = 0; i < 3; i++)
    {
        Log.Information("处理第 {Iteration} 次循环", i);
    }

    throw new Exception("示例异常");
}
catch (Exception ex)
{
    Log.Error(ex, "发生未处理异常");
}
finally
{
    Log.Information("程序退出");
    Log.CloseAndFlush(); // 确保所有日志都被写入
}
(5)输出日志
2025-02-11 20:25:37.236 +08:00 [Information] 程序启动
2025-02-11 20:25:37.261 +08:00 [Warning] 示例警告信息
2025-02-11 20:25:37.261 +08:00 [Information] 处理第 0 次循环
2025-02-11 20:25:37.262 +08:00 [Information] 处理第 1 次循环
2025-02-11 20:25:37.262 +08:00 [Information] 处理第 2 次循环
2025-02-11 20:25:37.271 +08:00 [Error] 发生未处理异常
System.Exception: 示例异常
   at Program.Main(String[] args) in D:\XCDEVDOC\00000000 开发文档\ConsoleMySerilog\Program.cs:line 53
2025-02-11 20:25:37.280 +08:00 [Information] 程序退出
(6)日志级别覆盖
  • 在配置文件中,你可以通过 MinimumLevel.Override覆盖特定命名空间的日志级别。这可以帮助你减少来自框架或第三方库的冗余日志信息。
{
  "Serilog": {
    "Using": ["Serilog.Sinks.File"],
    "MinimumLevel": { 
      "Default": "Information", 
      "Override": { 
        "Microsoft": "Warning", 
        "Microsoft.AspNetCore.Mvc": "Error", 
        "System": "Warning" 
      } 
    },
    "WriteTo": [
      {
        "Name": "File",
        "Args": {
          "path": "logs/log-.txt",
          "rollingInterval": "Day",
          "retainedFileCountLimit": 7,
          "outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level}] {Message}{NewLine}{Exception}"
        }
      }
    ]
  }
}
  • 全局基准:Default级别<font style="color:rgba(0, 0, 0, 0.9);">MinimumLevel.Default = Information</font> 表示:
    • 所有未被覆盖的日志源默认仅记录<font style="color:rgba(0, 0, 0, 0.9);">Information</font>及以上级别日志
    • 低于此级别的日志会被自动过滤
  • 精准控制:Override规则<font style="color:rgba(0, 0, 0, 0.9);">MinimumLevel.Override("Microsoft", Warning)</font> 表示:
    • 所有命名空间以**<font style="color:rgba(0, 0, 0, 0.9);">Microsoft.</font>**开头的日志(如<font style="color:rgba(0, 0, 0, 0.9);">Microsoft.AspNetCore</font><font style="color:rgba(0, 0, 0, 0.9);">Microsoft.EntityFrameworkCore</font>)。
    • 仅记录<font style="color:rgba(0, 0, 0, 0.9);">Warning</font>及以上级别(Warning/Error/Fatal)的日志,覆盖优先级高于Default,形成细粒度控制。

5、异步写日志

(1)安装NuGet包
  • Serilog.Sinks.Async:异步包
dotnet add package Serilog.Sinks.Async -v 2.0.0
(2)配置文件
  • 配置文件添加异步相关配置
{
  "Serilog": {
    "Using": [
      "Serilog.Sinks.File",
      "Serilog.Sinks.Async" //必须添加 Async 的 Using
    ],
    "MinimumLevel": {
      "Default": "Information",
      "Override": {
        "Microsoft": "Warning",
        "Microsoft.AspNetCore.Mvc": "Error",
        "System": "Warning"
      }
    },
    "WriteTo": [
      { // 异步文件输出配置
        "Name": "Async",
        "Args": {
          "configure": [
            {
              "Name": "File",
              "Args": {
                "path": "Logs/log-.txt",
                "rollingInterval": "Day",
                "retainedFileCountLimit": 7,
                "buffered": false, // 禁用内置缓冲
                "flushToDiskInterval": 5, // 秒
                "outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level}] {Message}{NewLine}{Exception}"
              }
            }
          ],
          "bufferSize": 1000, // 内存缓冲区大小
          "blockWhenFull": true // 缓冲区满时阻塞
        }
      }
    ],
    "Enrich": [ "FromLogContext", "WithMachineName" ]
  }
}
(3)代码实现
// 加载配置
var configuration = new ConfigurationBuilder()
    .SetBasePath(Directory.GetCurrentDirectory())
    .AddJsonFile("appsettings.json")
    .Build();

// 创建异步日志记录器
Log.Logger = new LoggerConfiguration()
    .ReadFrom.Configuration(configuration)
    .CreateLogger();

try
{
    Log.Information("程序启动(异步模式)");
    
    // 模拟高并发日志写入
    Parallel.For(0, 100, i => 
    {
        Log.Information("异步写入日志项 {Number}", i);
    });

    throw new InvalidOperationException("测试异步异常记录");
}
catch (Exception ex)
{
    Log.Error(ex, "异步异常示例");
}
finally
{
    Log.Information("程序结束");
    await Log.CloseAndFlushAsync();  // 异步关闭
}
(4)输出日志
2025-02-11 17:57:47.362 +08:00 [Information] 异步写入日志项 6
2025-02-11 17:57:47.362 +08:00 [Information] 异步写入日志项 30
2025-02-11 17:57:47.363 +08:00 [Information] 异步写入日志项 60
2025-02-11 17:57:47.362 +08:00 [Information] 异步写入日志项 12
2025-02-11 17:57:47.362 +08:00 [Information] 异步写入日志项 0
2025-02-11 17:57:47.362 +08:00 [Information] 异步写入日志项 54
2025-02-11 17:57:47.362 +08:00 [Information] 异步写入日志项 24
2025-02-11 17:57:47.362 +08:00 [Information] 异步写入日志项 48
2025-02-11 17:57:47.367 +08:00 [Information] 异步写入日志项 66
2025-02-11 17:57:47.362 +08:00 [Information] 异步写入日志项 36
2025-02-11 17:57:47.362 +08:00 [Information] 异步写入日志项 42
2025-02-11 17:57:47.368 +08:00 [Information] 异步写入日志项 55
2025-02-11 17:57:47.368 +08:00 [Information] 异步写入日志项 25
2025-02-11 17:57:47.368 +08:00 [Information] 异步写入日志项 37
2025-02-11 17:57:47.368 +08:00 [Information] 异步写入日志项 49
2025-02-11 17:57:47.368 +08:00 [Information] 异步写入日志项 13
2025-02-11 17:57:47.368 +08:00 [Information] 异步写入日志项 67
2025-02-11 17:57:47.368 +08:00 [Information] 异步写入日志项 7
2025-02-11 17:57:47.368 +08:00 [Information] 异步写入日志项 61
2025-02-11 17:57:47.368 +08:00 [Information] 异步写入日志项 31
2025-02-11 17:57:47.368 +08:00 [Information] 异步写入日志项 56
2025-02-11 17:57:47.368 +08:00 [Information] 异步写入日志项 26
2025-02-11 17:57:47.368 +08:00 [Information] 异步写入日志项 38
2025-02-11 17:57:47.368 +08:00 [Information] 异步写入日志项 14
2025-02-11 17:57:47.368 +08:00 [Information] 异步写入日志项 68
2025-02-11 17:57:47.368 +08:00 [Information] 异步写入日志项 50
2025-02-11 17:57:47.368 +08:00 [Information] 异步写入日志项 8
2025-02-11 17:57:47.368 +08:00 [Information] 异步写入日志项 43
2025-02-11 17:57:47.368 +08:00 [Information] 异步写入日志项 1
2025-02-11 17:57:47.368 +08:00 [Information] 异步写入日志项 39
2025-02-11 17:57:47.368 +08:00 [Information] 异步写入日志项 15
2025-02-11 17:57:47.368 +08:00 [Information] 异步写入日志项 62
2025-02-11 17:57:47.368 +08:00 [Information] 异步写入日志项 51
2025-02-11 17:57:47.368 +08:00 [Information] 异步写入日志项 40
2025-02-11 17:57:47.368 +08:00 [Information] 异步写入日志项 16
2025-02-11 17:57:47.368 +08:00 [Information] 异步写入日志项 9
2025-02-11 17:57:47.362 +08:00 [Information] 异步写入日志项 18
2025-02-11 17:57:47.368 +08:00 [Information] 异步写入日志项 57
2025-02-11 17:57:47.368 +08:00 [Information] 异步写入日志项 69
2025-02-11 17:57:47.369 +08:00 [Information] 异步写入日志项 17
2025-02-11 17:57:47.368 +08:00 [Information] 异步写入日志项 63
2025-02-11 17:57:47.369 +08:00 [Information] 异步写入日志项 19
2025-02-11 17:57:47.369 +08:00 [Information] 异步写入日志项 52
2025-02-11 17:57:47.369 +08:00 [Information] 异步写入日志项 41
2025-02-11 17:57:47.369 +08:00 [Information] 异步写入日志项 20
2025-02-11 17:57:47.369 +08:00 [Information] 异步写入日志项 21
2025-02-11 17:57:47.369 +08:00 [Information] 异步写入日志项 53
2025-02-11 17:57:47.369 +08:00 [Information] 异步写入日志项 10
2025-02-11 17:57:47.369 +08:00 [Information] 异步写入日志项 64
2025-02-11 17:57:47.368 +08:00 [Information] 异步写入日志项 32
2025-02-11 17:57:47.369 +08:00 [Information] 异步写入日志项 33
2025-02-11 17:57:47.369 +08:00 [Information] 异步写入日志项 22
2025-02-11 17:57:47.369 +08:00 [Information] 异步写入日志项 45
2025-02-11 17:57:47.369 +08:00 [Information] 异步写入日志项 58
2025-02-11 17:57:47.369 +08:00 [Information] 异步写入日志项 65
2025-02-11 17:57:47.369 +08:00 [Information] 异步写入日志项 11
2025-02-11 17:57:47.369 +08:00 [Information] 异步写入日志项 34
2025-02-11 17:57:47.369 +08:00 [Information] 异步写入日志项 23
2025-02-11 17:57:47.369 +08:00 [Information] 异步写入日志项 72
2025-02-11 17:57:47.369 +08:00 [Information] 异步写入日志项 46
2025-02-11 17:57:47.369 +08:00 [Information] 异步写入日志项 59
2025-02-11 17:57:47.369 +08:00 [Information] 异步写入日志项 70
2025-02-11 17:57:47.369 +08:00 [Information] 异步写入日志项 35
2025-02-11 17:57:47.368 +08:00 [Information] 异步写入日志项 44
2025-02-11 17:57:47.369 +08:00 [Information] 异步写入日志项 82
2025-02-11 17:57:47.368 +08:00 [Information] 异步写入日志项 27
2025-02-11 17:57:47.369 +08:00 [Information] 异步写入日志项 73
2025-02-11 17:57:47.369 +08:00 [Information] 异步写入日志项 47
2025-02-11 17:57:47.369 +08:00 [Information] 异步写入日志项 90
2025-02-11 17:57:47.369 +08:00 [Information] 异步写入日志项 84
2025-02-11 17:57:47.369 +08:00 [Information] 异步写入日志项 78
2025-02-11 17:57:47.369 +08:00 [Information] 异步写入日志项 71
2025-02-11 17:57:47.369 +08:00 [Information] 异步写入日志项 3
2025-02-11 17:57:47.369 +08:00 [Information] 异步写入日志项 96
2025-02-11 17:57:47.369 +08:00 [Information] 异步写入日志项 74
2025-02-11 17:57:47.369 +08:00 [Information] 异步写入日志项 83
2025-02-11 17:57:47.369 +08:00 [Information] 异步写入日志项 91
2025-02-11 17:57:47.369 +08:00 [Information] 异步写入日志项 85
2025-02-11 17:57:47.369 +08:00 [Information] 异步写入日志项 79
2025-02-11 17:57:47.369 +08:00 [Information] 异步写入日志项 4
2025-02-11 17:57:47.369 +08:00 [Information] 异步写入日志项 97
2025-02-11 17:57:47.369 +08:00 [Information] 异步写入日志项 28
2025-02-11 17:57:47.369 +08:00 [Information] 异步写入日志项 75
2025-02-11 17:57:47.369 +08:00 [Information] 异步写入日志项 92
2025-02-11 17:57:47.369 +08:00 [Information] 异步写入日志项 86
2025-02-11 17:57:47.369 +08:00 [Information] 异步写入日志项 80
2025-02-11 17:57:47.369 +08:00 [Information] 异步写入日志项 5
2025-02-11 17:57:47.369 +08:00 [Information] 异步写入日志项 29
2025-02-11 17:57:47.369 +08:00 [Information] 异步写入日志项 98
2025-02-11 17:57:47.369 +08:00 [Information] 异步写入日志项 76
2025-02-11 17:57:47.369 +08:00 [Information] 异步写入日志项 93
2025-02-11 17:57:47.369 +08:00 [Information] 异步写入日志项 87
2025-02-11 17:57:47.369 +08:00 [Information] 异步写入日志项 81
2025-02-11 17:57:47.369 +08:00 [Information] 异步写入日志项 99
2025-02-11 17:57:47.369 +08:00 [Information] 异步写入日志项 77
2025-02-11 17:57:47.369 +08:00 [Information] 异步写入日志项 94
2025-02-11 17:57:47.369 +08:00 [Information] 异步写入日志项 88
2025-02-11 17:57:47.369 +08:00 [Information] 异步写入日志项 95
2025-02-11 17:57:47.369 +08:00 [Information] 异步写入日志项 89
2025-02-11 17:57:47.368 +08:00 [Information] 异步写入日志项 2
2025-02-11 17:57:47.377 +08:00 [Error] 异步异常示例
System.InvalidOperationException: 测试异步异常记录
   at Program.Main(String[] args) in D:\XCDEVDOC\00000000 开发文档\ConsoleMySerilog\Program.cs:line 88
2025-02-11 17:57:47.377 +08:00 [Information] 程序结束
(5)关键优化点说明
  • 异步架构
    • 通过 <font style="color:rgb(64, 64, 64);">Serilog.Sinks.Async</font> 实现非阻塞日志写入
    • 主线程将日志放入内存缓冲区,后台线程处理实际文件写入
  • 性能参数
"bufferSize": 1000,          // 内存缓冲队列容量
"blockWhenFull": true        // 缓冲区满时阻塞(防止日志丢失)
  • 文件写入优化
"buffered": false,           // 关闭文件缓冲(已由 Async 控制)
"flushToDiskInterval": 5     // 每5秒强制刷盘
  • 异常安全
await Log.CloseAndFlushAsync();  // 异步确保所有日志写入完成
(6)异步 vs 同步
特性同步模式异步模式
线程阻塞可能阻塞主线程非阻塞
吞吐量较低高(批量写入)
数据安全性实时写入更安全崩溃时可能丢失少量缓冲日志
适用场景低频率日志/关键系统高并发日志/性能敏感系统

6、Asp.NetCore集成Serilog

(1)创建项目
  • 创建Asp.NetCore WebApi 项目,基于 net8
(2)安装nuget包
  • Serilog:Serilog 核心库。
  • Serilog.AspNetCore:ASP.NET Core 集成包。
  • Serilog.Sinks.File:将日志输出到文件。
  • Serilog.Sinks.Async:异步写日志。
dotnet add package Serilog -v 4.2.0
dotnet add package Serilog.AspNetCore -v 9.0.0
dotnet add package Serilog.Sinks.File -v 6.0.0
dotnet add package Serilog.Sinks.Async -v 2.0.0
(3)配置日志记录器
  • 创建一个扩展类,在扩展类里面配置日志记录器
using Serilog;
using Serilog.Events;

namespace AspNetCoreWebApiMySerilog
{
    public static class Extends
    {
        const string infoPath = "Logs/info.log";
        const string warnPath = "Logs/warn.log";
        const string errorPath = "Logs/error.log";
        const string fatalPath = "Logs/fatal.log";
        const string template = "时间: {Timestamp:yyyy-MM-dd HH:mm:ss}{NewLine}来源: {SourceContext}{NewLine}内容: [{Level:u3}] {Message}{NewLine}{Exception}{NewLine}";

        // 可以将日志输出到控制台、文件、数据库、ES等
        public static void AddSerilog(this IServiceCollection c)
        {
            Log.Logger = new LoggerConfiguration()
                .MinimumLevel.Information()
                .MinimumLevel.Override("Microsoft", LogEventLevel.Warning) // 排除Dotnet自带的日志
                .Enrich.FromLogContext()
                .WriteTo.Console(outputTemplate: template)
                .WriteTo.Logger(lg => lg.Filter.ByIncludingOnly(lev => lev.Level == LogEventLevel.Information).WriteTo.Async(congfig => congfig.File(
                    infoPath,
                    rollingInterval: RollingInterval.Day,
                    fileSizeLimitBytes: 1024 * 1024 * 10,    //默认1GB
                    retainedFileCountLimit: 10,                   //保留最近多少个文件,默认31个
                    rollOnFileSizeLimit: true,                       //超过文件大小时,自动创建新文件  
                    shared: true,
                    outputTemplate: template)
                                                                                                                            ))

                .WriteTo.Logger(lg => lg.Filter.ByIncludingOnly(lev => lev.Level == LogEventLevel.Warning).WriteTo.Async(congfig => congfig.File(
                    warnPath,
                    rollingInterval: RollingInterval.Day,
                    fileSizeLimitBytes: 1024 * 1024 * 10,
                    retainedFileCountLimit: 10,
                    rollOnFileSizeLimit: true,
                    shared: true,
                    outputTemplate: template)
                                                                                                                        ))

                .WriteTo.Logger(lg => lg.Filter.ByIncludingOnly(lev => lev.Level == LogEventLevel.Error).WriteTo.Async(congfig => congfig.File(
                    errorPath,
                    rollingInterval: RollingInterval.Day,
                    fileSizeLimitBytes: 1024 * 1024 * 10,
                    retainedFileCountLimit: 10,
                    rollOnFileSizeLimit: true,
                    shared: true,
                    outputTemplate: template)
                                                                                                                      ))

                .WriteTo.Logger(lg => lg.Filter.ByIncludingOnly(lev => lev.Level == LogEventLevel.Fatal).WriteTo.Async(congfig => congfig.File(
                    fatalPath,
                    rollingInterval: RollingInterval.Day,
                    fileSizeLimitBytes: 1024 * 1024 * 10,
                    retainedFileCountLimit: 10,
                    rollOnFileSizeLimit: true,
                    shared: true,
                    outputTemplate: template)
                                                                                                                      )).CreateLogger();

            // 注入到容器
            c.AddLogging(opt =>
            {
                opt.ClearProviders();
                opt.AddSerilog(dispose: true);
            });
        }
    }
}
(4)配置Serilog到框架
  • 在Program 添加Serilog 配置
namespace AspNetCoreWebApiMySerilog
{
    public class Program
    {
        public static void Main(string[] args)
        {
            var builder = WebApplication.CreateBuilder(args);

            // Add services to the container.

            builder.Services.AddControllers();

            // 添加Serilog日志
            builder.Services.AddSerilog();

            var app = builder.Build();

            // Configure the HTTP request pipeline.

            app.UseAuthorization();


            app.MapControllers();

            app.Run();
        }
    }
}
(5)在代码中使用日志
  • 创建控制器,用构造函数注入日志,使用日志
using Microsoft.AspNetCore.Mvc;

namespace AspNetCoreWebApiMySerilog.Controllers
{
    [ApiController]
    [Route("[controller]/[action]")]
    public class MyController : Controller
    {
        private readonly ILogger<MyController> _logger;

        public MyController(ILogger<MyController> logger)
        {
            _logger = logger;
        }

        [HttpGet]
        public IActionResult Index()
        {
            _logger.LogDebug("这是一条调试消息");
            _logger.LogInformation("这是一条提示消息");
            _logger.LogWarning("这是一条警告消息");
            _logger.LogError("这是一条错误消息");
            _logger.LogCritical("这是一条严重错误");
            return Ok("Hello World");
        }
    }
}
  • 访问地址:http://localhost:5135/my/index
  • 日志写入日志文件


http://www.kler.cn/a/560104.html

相关文章:

  • 2024-2025 学年广东省职业院校技能大赛 “信息安全管理与评估”赛项 技能测试试卷(一)
  • Linux主机用户登陆安全配置
  • 第46天:Web开发-JavaEE应用原生和FastJson反序列化URLDNS链JDBC链Gadget手搓
  • Python入门教程丨3.5 正则表达式
  • Gin从入门到精通(八)身份验证与授权(JWT)
  • 【C语言基础】基本数据类型和常量介绍
  • 2025 银行业科技金融创新与发展报告
  • 如何查看图片的原始格式
  • c高级终端指令
  • 【R语言】dplyr包经典函数summarise函数
  • 测试面试题:以一个登录窗口为例,设计一下登录界面测试的思路和方法
  • 【JavaEE】SpringMVC 请求传参
  • Ubuntu非conda环境python3.8下安装labelme
  • Vue全局变量的定义和使用,创建 Store变量、读取、修改
  • Django数据库操作
  • 最长递增子序列(贪心算法)思路+源码
  • zookeeper从入门到精通
  • 在CentOS7上部署与关闭Flask接口
  • GoFly框架中集成Bolt 和badfer两个Go语言嵌入式键值数据库
  • 2025.2.24总结