Easy-DotNET Easy-DotNET
🏠首页
  • 知识地图
  • 源码脑图

    • 总览
    • Program
    • WebApplication
    • Host主机
    • WebHost主机
    • 依赖注入
    • Autofac
    • Middleware中间件
    • RateLimiter限制速率
    • 响应缓存、请求解压缩
  • 设计初衷
  • 克隆
  • 类型转换
  • 日期时间
  • IO流
  • 工具类
  • 语言特性
  • 集合类
  • Codec编码
  • 文本操作
  • 数学
  • 图片
  • 网络
  • Emoji表情
  • C# 12
  • C# 11
  • C# 10
  • C# 9.0
  • C# 8.0
  • C# 早期版本
  • C# 教程
  • ORM
  • 定时任务
  • 日志
  • 认证与授权
  • Swagger
  • 对象映射
  • 熔断重试限流
  • 缓存
  • 注册发现
  • 网关
  • GraphQL
  • 更多
  • Docker

    • 简介
    • Adminer
    • Apisix
    • Apollo
    • Cassandra
    • Cerebro
    • ClickHouse
    • Consul
    • EasyMock
    • Elasticsearch
    • Emqx
    • FastDFS
    • Flink
    • Gitlab
    • Jenkins
    • Jrebel
    • MariaDB
    • MySQL
    • Percona
    • Phpmyadmin
    • PostgreSQL
    • Redis
  • Linux

    • 查看Linux系统信息
    • CentOS7调整磁盘分区
    • IO压测
    • 图形化监控工具Cockpit
  • 总览
  • 列表

    • 算法数据结构
    • API
    • 应用框架
    • 应用模板
    • 操作系统
    • 工作流
    • 入门套件
    • 示例
    • 人工智能
    • 程序集
    • Assets
    • 认证授权
    • Blazor
    • 区块链
    • 书籍
    • 自动构建
    • 报表
    • 缓存
    • 日历
    • 聊天
    • CLI
    • CLR
    • CMS
    • 代码分析和指标
    • 代码片段
    • 压缩
    • 持续集成
    • 密码学
    • 数据库
    • 数据库驱动
    • 日期时间
    • 反编译
    • 部署
    • DirectX
    • 分布式计算
    • DLR
    • 文档
    • 电商支付
    • 模拟器
    • 环境管理
    • ETL
    • 事件消息
    • Exception
    • 扩展
    • 函数式编程
    • 游戏引擎
    • GIS
    • Git工具
    • 绘图
    • GraphQL
    • GUI
    • HTML-CSS
    • HTTP
    • IDE
    • 图片处理
    • 安装工具
    • 交互式编程
    • 国际化
    • 互操作性
    • IoC
    • JS引擎
    • 日志
    • 机器学习和数据科学
    • Markdown
    • 邮件
    • 数学
    • 媒体
    • 指标
    • 微型框架
    • 最小化器
    • MVVM
    • 网络
    • 对象映射
    • Office
    • OpenAI
    • ORM
    • 包管理器
    • PDF
    • 性能分析工具
    • 协议
    • 推送通知
    • SQL构建器
    • 消息队列
    • RPC
    • 响应式编程
    • 实时通信
    • 正则表达式
    • 任务调度
    • SDK和API
    • 搜索引擎
    • 序列化
    • SMS
    • 状态机
    • 静态站点生成
    • 强命名
    • 风格指南
    • 模板引擎
    • 测试
    • 工具
    • 交易
    • UI自动测试
    • Visual Studio 插件
    • Web浏览器
    • Web框架
    • WebServers
    • WebSocket
    • Windows服务
    • WPF
    • 解析器
    • 源码生成
    • 其他
    • 资源
  • AspNetCore面试题
  • Elasticsearch面试题
  • MongoDB面试题
  • MySql面试题
  • Nginx面试题
  • RabbitMQ面试题
  • Redis面试题
  • 设计模式
  • 微服务
🧑‍💻.NET Blog
GitHub (opens new window)
🏠首页
  • 知识地图
  • 源码脑图

    • 总览
    • Program
    • WebApplication
    • Host主机
    • WebHost主机
    • 依赖注入
    • Autofac
    • Middleware中间件
    • RateLimiter限制速率
    • 响应缓存、请求解压缩
  • 设计初衷
  • 克隆
  • 类型转换
  • 日期时间
  • IO流
  • 工具类
  • 语言特性
  • 集合类
  • Codec编码
  • 文本操作
  • 数学
  • 图片
  • 网络
  • Emoji表情
  • C# 12
  • C# 11
  • C# 10
  • C# 9.0
  • C# 8.0
  • C# 早期版本
  • C# 教程
  • ORM
  • 定时任务
  • 日志
  • 认证与授权
  • Swagger
  • 对象映射
  • 熔断重试限流
  • 缓存
  • 注册发现
  • 网关
  • GraphQL
  • 更多
  • Docker

    • 简介
    • Adminer
    • Apisix
    • Apollo
    • Cassandra
    • Cerebro
    • ClickHouse
    • Consul
    • EasyMock
    • Elasticsearch
    • Emqx
    • FastDFS
    • Flink
    • Gitlab
    • Jenkins
    • Jrebel
    • MariaDB
    • MySQL
    • Percona
    • Phpmyadmin
    • PostgreSQL
    • Redis
  • Linux

    • 查看Linux系统信息
    • CentOS7调整磁盘分区
    • IO压测
    • 图形化监控工具Cockpit
  • 总览
  • 列表

    • 算法数据结构
    • API
    • 应用框架
    • 应用模板
    • 操作系统
    • 工作流
    • 入门套件
    • 示例
    • 人工智能
    • 程序集
    • Assets
    • 认证授权
    • Blazor
    • 区块链
    • 书籍
    • 自动构建
    • 报表
    • 缓存
    • 日历
    • 聊天
    • CLI
    • CLR
    • CMS
    • 代码分析和指标
    • 代码片段
    • 压缩
    • 持续集成
    • 密码学
    • 数据库
    • 数据库驱动
    • 日期时间
    • 反编译
    • 部署
    • DirectX
    • 分布式计算
    • DLR
    • 文档
    • 电商支付
    • 模拟器
    • 环境管理
    • ETL
    • 事件消息
    • Exception
    • 扩展
    • 函数式编程
    • 游戏引擎
    • GIS
    • Git工具
    • 绘图
    • GraphQL
    • GUI
    • HTML-CSS
    • HTTP
    • IDE
    • 图片处理
    • 安装工具
    • 交互式编程
    • 国际化
    • 互操作性
    • IoC
    • JS引擎
    • 日志
    • 机器学习和数据科学
    • Markdown
    • 邮件
    • 数学
    • 媒体
    • 指标
    • 微型框架
    • 最小化器
    • MVVM
    • 网络
    • 对象映射
    • Office
    • OpenAI
    • ORM
    • 包管理器
    • PDF
    • 性能分析工具
    • 协议
    • 推送通知
    • SQL构建器
    • 消息队列
    • RPC
    • 响应式编程
    • 实时通信
    • 正则表达式
    • 任务调度
    • SDK和API
    • 搜索引擎
    • 序列化
    • SMS
    • 状态机
    • 静态站点生成
    • 强命名
    • 风格指南
    • 模板引擎
    • 测试
    • 工具
    • 交易
    • UI自动测试
    • Visual Studio 插件
    • Web浏览器
    • Web框架
    • WebServers
    • WebSocket
    • Windows服务
    • WPF
    • 解析器
    • 源码生成
    • 其他
    • 资源
  • AspNetCore面试题
  • Elasticsearch面试题
  • MongoDB面试题
  • MySql面试题
  • Nginx面试题
  • RabbitMQ面试题
  • Redis面试题
  • 设计模式
  • 微服务
🧑‍💻.NET Blog
GitHub (opens new window)
npm
  • 简介
  • ORM

    • EFCore
    • Dapper
    • FreeSql
    • SqlSugar
  • 任务调度

    • Hangfire
    • Quartz
    • FluentScheduler
    • Coravel
    • Quartzmin
  • 日志

    • Serilog
      • 基础知识
        • 日志级别
        • 日志输出
        • 日志格式
      • 安装
      • 使用
        • 基础使用
        • 详细使用
        • 日志级别
        • 日志属性
        • 输出模板定义
        • 输出到文件
        • 结构化记录日志
        • 写入变量
        • 写入类
        • 写入集合
        • 写入匿名类
        • 输出上下文
        • 方式1:固定值的上下文
        • 方式2:动态传递上下文
        • 日志过滤器
        • 几种常用过滤方式
        • a.不同等级,输出不同文件
        • b.不同类,输出不同文件
        • c.根据消息内容过滤,输出不同文件
        • d.根据上下文值,输出不同文件
        • e.实现接口ILogEventFilter
        • 配置文件
        • 扩展
        • 日志输出器扩展
        • 控制台输出器扩展
        • Elasticsearch 输出器扩展
        • 日志过滤器扩展
        • 日志格式化器扩展
    • NLog
    • Log4Net
    • Stackdriver
    • ExceptionLess
  • 身份认证与授权

    • IdentityServer4
    • Identity
    • JWTBearer
    • Auth0
    • OpenIddict
  • Swagger文档

    • Swagger
    • Swashbuckle
    • NSwag
    • ReDoc
  • 对象映射

    • AutoMapper
    • EmitMapper
    • AgileMapper
    • Mapster
  • 消息传递

    • MediatR
    • MassTransit
    • Rebus
    • NServiceBus
  • 熔断重试限流

    • Polly
    • Resilience4j
    • AkkaNET
  • 缓存

    • CsRedis
    • FreeRedis
    • EasyCaching
    • StackExchangeRedis
    • CacheCow
    • NCache
    • Memory
  • 注册发现

    • Consul
    • Nacos
    • Apollo
  • 网关

    • Ocelot
    • Kong
    • Traefik
    • Zuul
  • GraphQL

    • GraphQLPlatform
    • GraphQLdotnet
  • 更多

    • NodaTime
    • FluentAssertions
    • Humanizer
    • 爬虫-AngleSharp
    • 邮件-MailKit
  • NET微服务
  • 日志
一个大西瓜
2023-04-20
目录

Serilog

开源地址

Github:https://github.com/serilog/serilog (opens new window)

Serilog 是一个 .NET 平台上的强大的日志记录库。它提供了丰富的 API 以及可插拔的日志格式化器和输出器,使得在 .NET 应用程序中实现可定制化的、可扩展的日志记录变得轻而易举。

在本文中,我们将探讨 Serilog 的一些基础知识、API、配置和示例。

# 基础知识

# 日志级别

Serilog 支持多个日志级别,包括以下级别(按照严重程度从高到低排列):

  • Fatal: 程序已经无法继续运行,需要立即解决的问题。
  • Error: 一个错误发生,需要被处理。
  • Warning: 一个警告,通常需要被留意,但是不需要立即处理。
  • Information: 提供有用的信息,通常只有在调试应用程序时才需要关注。
  • Debug: 提供调试信息,有助于调试应用程序。
  • Verbose: 提供大量的细节信息,通常只用于调试复杂的问题。

# 日志输出

Serilog 支持多种日志输出,包括:

  • Console(控制台输出)
  • File(文件输出)
  • Seq(通过 Seq (opens new window) 输出到日志收集器)
  • Elasticsearch(通过 Elasticsearch (opens new window) 输出到搜索引擎)

此外,Serilog 还支持自定义日志输出器。

# 日志格式

Serilog 支持多种日志格式化方式,包括:

  • 简单文本格式
  • JSON 格式
  • Message Templates 格式(一种更加灵活的格式)

# 安装

可以通过 NuGet 安装 Serilog。


Install-Package Serilog

# 使用

# 基础使用

在应用程序中使用 Serilog 很简单。下面的示例演示了如何在控制台输出日志:


using Serilog;

class Program
{
    static void Main()
    {
        Log.Logger = new LoggerConfiguration()
            .MinimumLevel.Debug()
            .WriteTo.Console()
            .CreateLogger();

        Log.Information("Hello, Serilog!");

        Log.CloseAndFlush();
    }
}

上面的代码将 Hello, Serilog! 输出到控制台。

# 详细使用

# 日志级别

下面的示例演示了如何在 Serilog 中设置不同的日志级别:


using Serilog;

class Program
{
    static void Main()
    {
        Log.Logger = new LoggerConfiguration()
            .MinimumLevel.Verbose()
            .WriteTo.Console()
            .CreateLogger();

        Log.Verbose("This is a verbose log message.");
        Log.Debug("This is a debug log message.");
        Log.Information("This is an informational log message.");
        Log.Warning("This is a warning log message.");
        Log.Error("This is an error log message.");
        Log.Fatal("This is a fatal log message.");

        Log.CloseAndFlush();
    }
}

​```csharp

上面的代码将演示如何使用不同的日志级别来记录日志消息。

#### 消息模板

Serilog 采用消息模板来格式化日志消息。下面是一个简单的消息模板示例:

​```csharp
using Serilog;

class Program
{
    static void Main()
    {
        Log.Logger = new LoggerConfiguration()
            .MinimumLevel.Debug()
            .WriteTo.Console(outputTemplate: "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level:u3}] {Message:lj}{NewLine}{Exception}")
            .CreateLogger();

        Log.Information("Hello, {Name}!", "Serilog");

        Log.CloseAndFlush();
    }
}

在上面的示例中,我们使用了一个带有模板的控制台输出器,并且在消息模板中使用了占位符 {Name}。当日志记录方法被调用时,{Name} 将被替换为 Serilog。我们可以看到 Hello, Serilog! 在控制台输出。

# 日志属性

Serilog 支持日志属性,这使得我们可以在日志消息中记录更多的信息。下面的示例演示了如何在日志消息中添加属性:


using Serilog;

class Program
{
    static void Main()
    {
        Log.Logger = new LoggerConfiguration()
            .MinimumLevel.Debug()
            .WriteTo.Console()
            .CreateLogger();

        Log.Information("Processed {@Count} records in {Time} ms.", new { Count = 10, Time = 123 });

        Log.CloseAndFlush();
    }
}

在上面的示例中,我们使用了一个匿名类型来表示日志属性。在日志消息中,我们使用了 @ 符号来引用这个匿名类型。当日志记录方法被调用时,Serilog 将自动将匿名类型的属性添加到日志消息中。上面的代码将输出 Processed { Count: 10, Time: 123 } records in 0 ms.。

# 输出模板定义

outputTemplate: "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level:u3}] {Message:lj}{NewLine}{Exception}")

这个也是官方的默认模板,我们可以这个扩展

.WriteTo.File("log.txt",
    outputTemplate: "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level:u3}] {Message:lj}{NewLine}{Exception}")

# 输出到文件

rollingInterval: RollingInterval.Day 每天一个日志文件

outputTemplate 输出格式模板

.WriteTo.File(
                    $"logs\\log-.txt" ,
                    //每天一个文件 ,生成类似:log-20230914.txt
                    //fileSizeLimitBytes: null 文件限制大小:无   如果不配置默认是:1GB 1GB就不记录了
                    //retainedFileCountLimit: null   保留文件数量   如果不配置只保留31天的日志
                    //https://github.com/serilog/serilog-sinks-file 
                    rollingInterval: RollingInterval.Day , retainedFileCountLimit: null ,
                    //fileSizeLimitBytes: null,
                    //单个文件大小: 1024000 1024000是1M
                    //rollOnFileSizeLimit: true 就是滚动文件,如果超过单个文件大小,会滚动文件 产生类似:log.txt log_001.txt log_002.txt
                    fileSizeLimitBytes: 3024000 , rollOnFileSizeLimit: true ,
                    //非必填:指定最小等级
                    restrictedToMinimumLevel: LogEventLevel.Information ,
                    //非必填: 也可以指定输出格式:这种格式好像与系统默认没有什么区别
                    //outputTemplate: "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level:u3}] {Message:lj}{NewLine}{Exception}"

                    //outputTemplate: "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level:u3}] {Message:lj}{NewLine}{Exception} {NewLine}{Version}{myval}"

                    outputTemplate: "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level:u3}] {Message:lj}{NewLine}{Exception} {NewLine}{Version}{myval} {NewLine}{UserId}{myid}{NewLine}"
                )

# 结构化记录日志

# 写入变量
var itemNumber = 10;
var itemCount = 999;

// 使用占位符写入
// 结果:2023-09-15 22:23:54.576 +08:00 [INF] Processing item 10 of 999
this._logger.LogDebug( "Processing item {ItemNumber} of {ItemCount}" , itemNumber , itemCount );
# 写入类

特别提示:记录对象后 1.日志中会多一个$type属性 2.日期类型数据格式化后都是这样格式:2023-09-16T22:26:27.5905512+08:00

var wf = new WeatherForecast
        {
            Date = DateTime.Now.AddDays( 1 ) ,
            TemperatureC = 55 ,
            Summary = ""
        };
        
// @表示一个对象 这样就可以把一个对象直接传递进去
// 特别提示:记录对象后
// 1.日志中会多一个$type属性
// 2.日期类型数据格式化后都是这样格式:2023-09-16T22:26:27.5905512+08:00
//结果:2023-09-15 22:26:27.601 +08:00 [INF] WeatherForecast 的数据 {"Date":"2023-09-16T22:26:27.5905512+08:00","TemperatureC":55,"TemperatureF":130,"Summary":"","$type":"WeatherForecast"}
this._logger.LogInformation( "WeatherForecast 的数据 {@wf}" , wf );
# 写入集合
List<string> list1 = new List<string>() { "q1" , "q2" };
        
//写入集合
//结果:2023-09-15 22:36:46.751 +08:00 [INF] 集合的数据 ["q1","q2"]
this._logger.LogInformation( "集合的数据 {@list1}" , list1 );
List<WeatherForecast> listw = new List<WeatherForecast>() {
        new WeatherForecast
        {
            Date = DateTime.Now.AddDays( 1 ) ,
            TemperatureC = 11 ,
            Summary = "one"
        },
        new WeatherForecast
        {
            Date = DateTime.Now.AddDays( 2 ) ,
            TemperatureC = 22 ,
            Summary = "two"
        }};
        
//写入集合
//结果: 2023-09-15 22:39:53.863 +08:00 [INF] 集合的数据 [{"Date":"2023-09-16T22:39:53.8634787+08:00","TemperatureC":11,"TemperatureF":51,"Summary":"one","$type":"WeatherForecast"},{"Date":"2023-09-17T22:39:53.8634842+08:00","TemperatureC":22,"TemperatureF":71,"Summary":"two","$type":"WeatherForecast"}]
this._logger.LogInformation( "集合的数据 {@listw}" , listw );
# 写入匿名类
var user = new
            {
                Name = "Nick" ,
                Id = "nblumhardt" ,
                add = new List<string>() { "add1" , "add2" } ,
                man = new
                {
                    age = 1 ,
                    names = "qq"
                }
            };
            
// @表示一个对象(上面这个是匿名类也可以写入的)  
//结果:2023-09-15 22:23:54.576 +08:00 [INF] Logged on user {"Name":"Nick","Id":"nblumhardt","add":["add1","add2"],"man":{"age":1,"names":"qq"}}
this._logger.LogInformation( "Logged on user {@user}" , user );

# 输出上下文

# 方式1:固定值的上下文
Log.Logger = new LoggerConfiguration()
     // 注册日志上下文
    .Enrich.FromLogContext()
    //  上下文
    .Enrich.WithProperty( "Version" , "1.0.0" )
    .Enrich.WithProperty( "myval" , 123 )

配置模版定义上下文

//outputTemplate中配置写入上下文
outputTemplate: "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level:u3}] {Message:lj}{NewLine}{Exception} {NewLine}{Version}{myval}"
# 方式2:动态传递上下文

配置模版定义上下文

outputTemplate中定义了2个上下文:UserId和myid
outputTemplate: "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level:u3}] {Message:lj}{NewLine}{Exception} {NewLine}{Version}{myval} {NewLine}{UserId}{myid}{NewLine}"

代码传递值

//利用BeginScope传递上下文
using ( this._logger.BeginScope( new Dictionary<string , object>
{
    ["UserId"] = "svrooij" ,
    ["myid"] = 123456 ,
} ) )
{
    this._logger.LogInformation( "我传递上下文参数过来了"  );
}



//不是每个都要传递上下文,没有传递也不报错
this._logger.LogError( new Exception( "0异常啦" ) , "我自己造的" );
this._logger.LogInformation( new Random().Next( 10000 ).ToString() );

# 日志过滤器

Serilog 支持过滤器来控制日志输出。下面的示例演示了如何使用过滤器来仅输出错误级别以上的日志:


using Serilog;

class Program
{
    static void Main()
    {
        Log.Logger = new LoggerConfiguration()
            .MinimumLevel.Debug()
            .WriteTo.Console()
            .Filter.ByIncludingOnly(logEvent => logEvent.Level >= LogEventLevel.Error)
            .CreateLogger();

        Log.Verbose("This is a verbose log message.");
        Log.Debug("This is a debug log message.");
        Log.Information("This is an informational log message.");
        Log.Warning("This is a warning log message.");
        Log.Error("This is an error log message.");
        Log.Fatal("This is a fatal log message.");

        Log.CloseAndFlush();
    }
}

在上面的示例中,我们使用了 ByIncludingOnly 过滤器来仅输出错误级别以上的日志。

# 几种常用过滤方式

Filter.ByIncludingOnly:是包括

Filter.ByExcluding:是不包括

# a.不同等级,输出不同文件
Func<LogEvent , bool> isInformation = ( logEvent ) => logEvent.Level == LogEventLevel.Information;
Func<LogEvent , bool> isError = ( logEvent ) => logEvent.Level == LogEventLevel.Error;
       // 输出到文件
       //不同等级,输出不同文件
       .WriteTo.Logger( lg =>
       {
           lg.Filter.ByIncludingOnly( p => isInformation( p ) )
                       .WriteTo.File( $"logs\\log_Information-.txt" , rollingInterval: RollingInterval.Day );
       } )
       .WriteTo.Logger( lg =>
       {
           lg.Filter.ByIncludingOnly( p => isError( p ) )
                   .WriteTo.File( $"logs\\log_Error-.txt" , rollingInterval: RollingInterval.Day );
       } )
# b.不同类,输出不同文件
    //不同类,输出不同文件
    .WriteTo.Logger( lg =>
    {
        lg.Filter.ByIncludingOnly( Matching.FromSource<WeatherForecastController>() )
            .WriteTo.File( $"logs\\WeatherForecastController-.txt" , rollingInterval: RollingInterval.Day );
    } )
    .WriteTo.Logger( lg =>
    {
        lg.Filter.ByIncludingOnly( Matching.FromSource<ValuesController>() )
           .WriteTo.File( $"logs\\ValuesController-.txt" , rollingInterval: RollingInterval.Day );
    } )
# c.根据消息内容过滤,输出不同文件
Func<LogEvent , bool> isbsWeatherForecastController = ( p ) =>
{
    var msg = p.RenderMessage();

    if ( !string.IsNullOrEmpty( msg ) )
    {
        return msg.Contains( "bs:WeatherForecastController" , StringComparison.OrdinalIgnoreCase );
    }

    return false;
};
       //根据消息内容过滤,输出不同文件
       .WriteTo.Logger( lg =>
       {
           lg.Filter.ByIncludingOnly( p => isbsWeatherForecastController( p ) )
           .Filter.ByIncludingOnly( isMidServices )
               .WriteTo.File( $"logs\\WeatherForecastController-.txt" , rollingInterval: RollingInterval.Day );
       } )
# d.根据上下文值,输出不同文件
    //根据上下文值,输出不同文件
    .WriteTo.Logger( lg =>
    {
        //lg.Filter.ByIncludingOnly( Matching.WithProperty( "UserId" , "svrooij" ) )
        
        //下面这个,也是等效写法
        lg.Filter.ByIncludingOnly( Matching.WithProperty<string>( "UserId" , str => !string.IsNullOrEmpty( str ) && str.Equals( "svrooij" , StringComparison.OrdinalIgnoreCase ) ) )
            .WriteTo.File( $"logs\\WeatherForecastController-.txt" ,
                rollingInterval: RollingInterval.Day ,
                outputTemplate: "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level:u3}] {Message:lj}{NewLine}{Exception}   {NewLine}{UserId}{myid}{NewLine}" );
    } )
# e.实现接口ILogEventFilter
   public class CustomFilter : ILogEventFilter
    {
        private readonly string _propertyName;
        private readonly string _propertyValue;

        public CustomFilter ( string propertyName , string propertyValue )
        {
            _propertyName = propertyName;
            _propertyValue = propertyValue;
        }


        public bool IsEnabled ( LogEvent logEvent )
        {
            //下面的判断逻辑是:Information等级的,MidServices类产生的,判断某个上下文是否为某个值

            if ( logEvent.Level == LogEventLevel.Information )
            {
                var f = Matching.FromSource<MidServices>();
                bool bl = f.Invoke( logEvent );

                if ( bl )
                {
                    var f2 = Matching.WithProperty<string>( _propertyName ,
                                                                                str => !string.IsNullOrEmpty( str ) && str.Equals( _propertyValue , StringComparison.OrdinalIgnoreCase ) );

                    bool bl2 = f2.Invoke( logEvent );

                    if ( bl2 )
                    {
                        return true;
                    }
                }

            }

            return false;
        }
    }

# 配置文件

Serilog 还支持使用配置文件来配置日志记录。下面是一个配置文件示例:


<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<appSettings>
<add key="serilog:minimum-level" value="Verbose" />
<add key="serilog:write-to:Console" />
</appSettings>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.8" />
</startup>
</configuration>

在上面的示例中,我们使用了一个配置文件来配置 Serilog。我们将日志级别设置为 Verbose,并且将输出器设置为 Console。

# 扩展

Serilog 提供了丰富的扩展方式,包括:

  • 日志输出器扩展
  • 日志过滤器扩展
  • 日志格式化器扩展

# 日志输出器扩展

Serilog 提供了多种扩展方式来添加自定义日志输出器。

# 控制台输出器扩展

以下示例演示了如何添加一个自定义的控制台输出器:

using Serilog;
using Serilog.Configuration;
using Serilog.Events;
using Serilog.Formatting;

public static class CustomConsoleSinkExtensions
{
    public static LoggerConfiguration CustomConsole(
        this LoggerSinkConfiguration sinkConfiguration,
        ITextFormatter formatter = null,
        LogEventLevel restrictedToMinimumLevel = LevelAlias.Minimum)
    {
        return sinkConfiguration.Sink(
            new CustomConsoleSink(formatter),
            restrictedToMinimumLevel);
    }
}

public class CustomConsoleSink : ILogEventSink
{
    private readonly ITextFormatter _formatter;

    public CustomConsoleSink(ITextFormatter formatter)
    {
        _formatter = formatter ?? throw new ArgumentNullException(nameof(formatter));
    }

    public void Emit(LogEvent logEvent)
    {
        var message = new StringWriter();
        _formatter.Format(logEvent, message);
        Console.WriteLine(message.ToString());
    }
}

class Program
{
    static void Main()
    {
        Log.Logger = new LoggerConfiguration()
            .MinimumLevel.Debug()
            .WriteTo.CustomConsole()
            .CreateLogger();

        Log.Information("Hello, Serilog!");

        Log.CloseAndFlush();
    }
}

在上面的示例中,我们定义了一个名为 CustomConsoleSink 的自定义控制台输出器,并将其添加到 Serilog 的输出器列表中。

# Elasticsearch 输出器扩展

以下示例演示了如何添加一个自定义的 Elasticsearch 输出器:


using Serilog;
using Serilog.Configuration;
using Serilog.Events;
using Serilog.Formatting;
using Serilog.Sinks.Elasticsearch;

public static class CustomElasticsearchSinkExtensions
{
    public static LoggerConfiguration CustomElasticsearch(
        this LoggerSinkConfiguration sinkConfiguration,
        ITextFormatter formatter = null,
        ElasticsearchSinkOptions elasticsearchOptions = null,
        LogEventLevel restrictedToMinimumLevel = LevelAlias.Minimum)
    {
        return sinkConfiguration.Sink(
            new CustomElasticsearchSink(formatter, elasticsearchOptions),
            restrictedToMinimumLevel);
    }
}

public class CustomElasticsearchSink : ElasticsearchSink
{
    public CustomElasticsearchSink(
        ITextFormatter formatter,
        ElasticsearchSinkOptions elasticsearchOptions) :
        base(elasticsearchOptions)
    {
        Formatter = formatter;
    }

    public ITextFormatter Formatter { get; }

    protected override void EmitBatch(
        IEnumerable<LogEvent> events,
        IBulkWriter writer)
    {
        foreach (var logEvent in events)
        {
            var message = new StringWriter();
            Formatter.Format(logEvent, message);
            var json = message.ToString();
            writer.IndexDocument(json);
        }
    }
}

class Program
{
    static void Main()
    {
        Log.Logger = new LoggerConfiguration()
            .MinimumLevel.Debug()
            .WriteTo.CustomElasticsearch(new ElasticsearchSinkOptions(new Uri("[http://localhost:9200](http://localhost:9200/) ")),new ElasticsearchJsonFormatter(),LogEventLevel.Information)
            .CreateLogger();

        Log.Information("Hello, Serilog!");

        Log.CloseAndFlush();
    }
}

在上面的示例中,我们定义了一个名为 CustomElasticsearchSink 的自定义 Elasticsearch 输出器,并将其添加到 Serilog 的输出器列表中。

# 日志过滤器扩展

Serilog 提供了多种扩展方式来添加自定义日志过滤器。

以下示例演示了如何添加一个自定义的日志过滤器:

using Serilog;
using Serilog.Configuration;
using Serilog.Events;

public static class CustomFilterExtensions
{
    public static LoggerConfiguration CustomFilter(
        this LoggerFilterConfiguration filterConfiguration,
        string propertyName,
        string propertyValue,
        LogEventLevel minimumLevel = LevelAlias.Minimum)
    {
        return filterConfiguration.Add(
            new CustomFilter(propertyName, propertyValue),
            minimumLevel);
    }
}

public class CustomFilter : ILogEventFilter
{
    private readonly string _propertyName;
    private readonly string _propertyValue;

    public CustomFilter(string propertyName, string propertyValue)
    {
        _propertyName = propertyName;
        _propertyValue = propertyValue;
    }

    public bool IsEnabled(LogEvent logEvent)
    {
        if (logEvent == null) throw new ArgumentNullException(nameof(logEvent));

        var property = logEvent.Properties[_propertyName];
        if (property == null) return false;

        return property.ToString().Equals(_propertyValue);
    }
}

class Program
{
    static void Main()
    {
        Log.Logger = new LoggerConfiguration()
            .MinimumLevel.Debug()
            .WriteTo.Console()
            .Filter.CustomFilter("Environment", "Production")
            .CreateLogger();

        Log.Information("Hello, Serilog!");

        Log.CloseAndFlush();
    }
}

在上面的示例中,我们定义了一个名为 CustomFilter 的自定义过滤器,并将其添加到 Serilog 的过滤器列表中。该过滤器将仅输出 Environment 属性为 Production 的日志。

# 日志格式化器扩展

Serilog 提供了多种扩展方式来添加自定义日志格式化器。

以下示例演示了如何添加一个自定义的日志格式化器:


using Serilog;
using Serilog.Configuration;
using Serilog.Events;
using Serilog.Formatting.Display;

public static class CustomFormatterExtensions
{
    public static LoggerConfiguration CustomFormatter(
        this LoggerConfiguration loggerConfiguration,
        string format,
        IFormatProvider formatProvider = null,
        LogEventLevel minimumLevel = LevelAlias.Minimum)
    {
        return loggerConfiguration.Sink(
            new CustomFormatterSink(format, formatProvider),
            minimumLevel);
    }
}

public class CustomFormatterSink : ILogEventSink
{
    private readonly MessageTemplateTextFormatter _formatter;

    public CustomFormatterSink(string format, IFormatProvider formatProvider = null)
    {
        _formatter = new MessageTemplateTextFormatter(format, formatProvider);
    }

    public void Emit(LogEvent logEvent)
    {
        var message = new StringWriter();

        _formatter.Format(logEvent, message);
            Console.WriteLine(message.ToString());
        }
}

class Program
{
    static void Main()
    {
        Log.Logger = new LoggerConfiguration()
            .MinimumLevel.Debug()
            .WriteTo.CustomFormatter("Hello, {Name}!", null, LogEventLevel.Information)
            .CreateLogger();
        Log.Information("{Name}", "Serilog");
        Log.CloseAndFlush();
    }
}

​```markdown

在上面的示例中,我们定义了一个名为 `CustomFormatterSink` 的自定义格式化器,并将其添加到 Serilog 的输出器列表中。该格式化器将 `Hello, {Name}!` 格式化为 `Hello, Serilog!`。

## 结论

Serilog 是一个功能强大的 .NET 平台上的日志记录库。它提供了丰富的 API 以及可插拔的日志格式化器和输出器,使得在 .NET 应用程序中实现可定制化的、可扩展的日志记录变得轻而易举。希望本文对您有所帮助。
上次更新: 2023/09/21, 11:15:03
Quartzmin
NLog

← Quartzmin NLog→

Theme by Vdoing | Copyright © 2019-2024 一个大西瓜 | MIT License | 苏ICP备2023013501号
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式