[AspNetCore3.1] 使用Serilog记录日志
一、基础用法
1.1 添加 Nuget 引用
Serilog.AspNetCore
日志包主体
Serilog.AspNetCore.RollingFile
将日志写入文件
1.2 注册服务
1.2.1 在 appsettings.json
中添加 Serilog
节点。
简单说明下配置文件的意思:
- 将日志写入RollingFile(文件)和Console(控制台)。
RollingFile
的具体配置:记录文件到根目录/logs/{日期}.txt
文件内,每天记录一个文件,并且只记录Warning
及其以上的日志;- 默认日志级别记录
Debug
及其以上的日志。 - 如果日志包含
Microsoft
System
,只记录级别为Information
及以上的日志。
{
"Serilog": {
"WriteTo": [
{
"Name": "RollingFile",
"Args": {
"pathFormat": "logs\\{Date}.txt",
"RestrictedToMinimumLevel": "Warning"
}
},
{
"Name": "Console"
}
],
"MinimumLevel": {
"Default": "Debug",
"Override": {
"Microsoft": "Information",
"System": "Information"
}
}
},
}
1.2.2 修改 program.cs
,注册 Serilog
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
}).UseSerilog((context, configure) =>
{
configure.ReadFrom.Configuration(context.Configuration);
});
1.2.3 简单配置完成,现在可以在项目中方便的使用 Serilog
了。
private readonly ILogger<HomeController> _logger;
public HomeController(ILogger<HomeController> logger)
{
_logger = logger;
}
public IActionResult Index()
{
_logger.LogError("Error 测试");
return View();
}
二、Serilog 的重要组成部分
2.1 日志接收器 (Sink)
接收器用来配置日志记录到哪种介质。比如说 Console(输出到控制台),File(日志文件)等。就是我们上面配置的 WriteTo
节点。
接收器一般以扩展库的方式提供的,为了将日志写入文件,我们在上面引入了 Serilog.AspNetCore.Sinks.RollingFile
包。
除了在配置文件中使用 WriteTo
指定,也可以通过代码配置,比如在 Console
控制台程序中使用:
Log.Logger = new LoggerConfiguration()
.WriteTo.Console()
.CreateLogger();
Log.Information("Ah, there you are!");
可以同时使用多个接收器,用法很简单,支持链式调用:
Log.Logger = new LoggerConfiguration()
.WriteTo.Console()
.WriteTo.File("log-.txt", rollingInterval: RollingInterval.Day)
.CreateLogger();
基于文本的接收器使用 output templates
来控制格式。
Log.Logger = new LoggerConfiguration()
.WriteTo.File("log.txt",
outputTemplate: "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level:u3}] {Message:lj}{NewLine}{Exception}")
格式这部分涉及到扩展器,会在后面具体说明,这里只是简单提一下如何使用。
可以使用每个接收器指定不同的日志级别
Log.Logger = new LoggerConfiguration()
.MinimumLevel.Debug()
.WriteTo.File("log.txt")
.WriteTo.Console(restrictedToMinimumLevel: LogEventLevel.Information)
.CreateLogger();
上面代码中指定了默认日志级别为 Debug
,但为 Console Sink
的日志重写级别为 Information
==========
在声明Logger时可以通过 MinimumLevel.Debug()
指定最小级别,而在 WriteTo
中指定接收器Sink时,也可以通过 restrictetToMinimumLevel:LogEventLevel.Information
指定最小级别,那两者之间的关系是怎么样的呢?
注意:接收器Sink的级别必须高于Logger的级别。 假设Logger的默认级别为 Information
,即便 Sink
重写日志级别为 LogEventLevel.Debug
,也只能看到 Information
及以上级别的日志。这是因为默认级别的配置控制哪些事件级别的日志记录语句可以被创建,而 Sink
级别仅仅是对这些事件进行过滤。
2.2 扩展器 (Enricher)
顾名思义,扩展器可以添加,删除或修改附加到日志事件的属性。 例如,下面的代码可以达到将线程ID附加到每个事件的目的。
class ThreadIdEnricher : ILogEventEnricher
{
public void Enrich(LogEvent logEvent, ILogEventPropertyFactory propertyFactory)
{
logEvent.AddPropertyIfAbsent(propertyFactory.CreateProperty(
"ThreadId", Thread.CurrentThread.ManagedThreadId));
}
}
使用 Enricher
将扩展添加到配置对象
Log.Logger = new LoggerConfiguration()
.Enrich.With(new ThreadIdEnricher())
.WriteTo.Console(
outputTemplate: "{Timestamp:HH:mm} [{Level}] ({ThreadId}) {Message}{NewLine}{Exception}")
.CreateLogger();
注意模板中的 {ThreadId}
,在日志中打印的便是当前线程的ID了
如果扩展的属性值在整个应用程序运行期间都是恒定的,则可以使用快捷方式WithProperty方法简化配置。
Log.Logger = new LoggerConfiguration()
.Enrich.WithProperty("Version", "1.0.0")
.WriteTo.Console()
.CreateLogger();
2.3 过滤器 (Filter)
可以通过过滤器有选择的记录事件。过滤器只是 LogEvent
的谓词,其中一些常见的情况由 Matching
类处理。
只要在调试过程中打个断点,就可以看到 LogEvent
的详细属性,这里就不赘述,懒~~~
Log.Logger = new LoggerConfiguration()
.WriteTo.Console()
.Filter.ByExcluding(Matching.WithProperty<int>("Count", p => p < 10))
.CreateLogger();
上面的代码没测试过,猜测他的意思是:如果日志中有个叫Count的属性,只有该属性值小于10时才会记录日志。
三、说说输出格式吧
Serilog由Event组成,一个Event由一下几部分组成:
- Event发生时的时间戳【timestamp】,参数【@t】
- Event的级别【level】,参数【@l】
- Event的消息内容【message】,参数【@m】
- Event的命名属性【properties】,参数【@p】
- Exception 如果是log.Exception,则会有Exception对象
自定义模板
时间:【{Timestamp}】;级别:【{EventType} {Level}】;内容:【{Message}】;属性:【{abc}】
格式说明:
- Timestamp:时间戳,类型为
DateTimeOffset
,可用格式:yyyy-MM-dd HH:mm:ss.fff zzz
- Level:日志级别,默认为完整的级别名称,如:
Information
。可选格式:[Level:u3]=INF;[Level:w2]=inf - Message: 消息内容;可选格式
:l
和:j
var user = new User { Id = 1, Name = "Jack", Age = 12 };
log.Information("{@u}", user);
// 默认显示结果:
// User {Id=1, Name="Jack", Age=12};
// 格式定义为 :l 的情况下,显示结果:
// User {"Id": 1, "Name": "Jack", "Age": 12, "$type": "User"}
// 格式定义为 :j 的情况下, 显示结果:
// {"Id": 1, "Name": "Jack", "Age": 12, "$type": "User"}
上面的日志格式中还引用了一个 {abc}
,就是我们提过的 Enricher
扩展器
四、最后尝试使用代码的方式实现一个跟简单示例差不多功能的配置练练手吧
修改下 Program.cs
文件
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.ConfigureAppConfiguration(configure => configure.AddJsonFile("Serilog.json"));
webBuilder.UseStartup<Startup>();
})
.UseSerilog((context, configure) =>
{
configure.MinimumLevel.Information()
.WriteTo.Console(restrictedToMinimumLevel: LogEventLevel.Debug)
.Filter.With<MicrosoftFilter>()
.WriteTo.RollingFile("logs\\{Date}.txt", LogEventLevel.Warning);
});
自定义一个 Filter
public class MicrosoftFilter : ILogEventFilter
{
public bool IsEnabled(LogEvent logEvent)
{
if (!logEvent.Properties.TryGetValue("SourceContext", out var source))
{
return logEvent.Level >= LogEventLevel.Debug;
}
if (source.ToString().StartsWith("\"Microsoft"))
{
return logEvent.Level >= LogEventLevel.Warning;
}
return logEvent.Level >= LogEventLevel.Debug;
}
}
差不多就这样吧~~告辞!!!
原文:https://www.cnblogs.com/diwu0510/p/12828519.html