.Net Core日志记录之第三方框架Serilog
原文链接:https://www.jb51.net/article/251755.htm
https://blog.csdn.net/hiose89/article/details/125012881
这篇文章介绍了.Net Core日志记录之第三方框架Serilog
一、前言
对内置日志系统的整体实现进行了介绍之后,可以通过使用内置记录器来实现日志的输出路径。而在实际项目开发中,使用第三方日志框架(如: Log4Net、NLog、Loggr、Serilog、Sentry 等)来记录也是非常多的。首先一般基础的内置日志记录器在第三方日志框架中都有实现,然后第三方日志框架在功能上更加强大和丰富,能满足我们更多的项目分析和诊断的需求。
所以在这一篇中,我们将介绍第三方日志记录提供程序——Serilog
二、回顾
系统内置日志系列:
这个时候我们发现,其实在asp.net core中已经内置了日志系统,并提供了各种内置和第三方日志记录提供程序的日志记录接口,在进行应用开发中,可以进行统一配置,并且利用第三方日志框架相结合,更加有效的实现日志记录。所以在这个系列中,主要是对内置日志记录系统的学习,以及后续使用第三方日志框架集成我们需要的日志系统。
在新建项目成功之后,我们都会看到一个命名为appsettings.json配置,打开一看,短短的几行配置,
然后启动运行的时候,程序会在调试面板和控制台中分别输出显示来源如下:
在控制台中:
在调试面板中:
这里的日志配置,在系统中到底都起来什么作用?让我们来一探究竟吧!
三、开始
3.1 默认配置
我们查看源代码发现,在程序的入口点中发现,在初始化时候,通过CreateDefaultBuilder方法来实现日志记录的默认配置。
从Serilog的官方介绍中,我们可以发现 其框架是.net中的诊断日志库,可以在所有的.net平台上运行。支持结构化日志记录,对复杂、分布式、异步应用程序的支持非常出色。
Serilog是基于日志事件(log events),而不是日志消息(log message)。可以将日志事件格式化为控制台的可读文本或者将事件化为JSON格式。应用程序中的日志语句会创建LogEvent对象,而连接到管道的接收器(sinks)会知道如何记录它们。(接收器 包括各种终端、控制台、文本、SqlServer、ElasticSearch等等可用的列表)
为什么要使用Serilog?
Serilog比NLog 功能更为强大,能支持结构化的消息,不像NLog扁平和繁琐,配置也更加方便。支持代码配置、json、xml。但我觉得用代码配置就挺好,nlog就是XML配置太麻烦。
1、nuget 安装
Serilog.AspNetCore 会自动安装依赖项
2、(可选,异步写入)nuget 安装 Serilog.Sinks.Async
3、注册服务配置写入文件
builder.Services.AddLogging(bulid => { Log.Logger = new LoggerConfiguration() .MinimumLevel.Debug() .Enrich.FromLogContext() WriteTo.Async(config => config.File( "d://.log", rollingInterval: RollingInterval.Day, fileSizeLimitBytes: 1024 * 1024 * 10,//单位字节 不配置时默認1GB retainedFileCountLimit: 10,//保留最近多少個文件 不配置时默認31個 rollOnFileSizeLimit: true,//超過文件大小時 自動創建新文件 shared: true) )) .CreateLogger(); bulid.AddSerilog(); });
4、随便找个控制器在构造函数注入后即可使用
[HttpGet(Name = "GetWeatherForecast")] public IEnumerable<WeatherForecast> Get() { while (true) { _logger.LogInformation("ASDASDASDASDASDADSASDASDASDASDASDADSASDASDASDASDASDADSASDASDASDASDASDADS"); } return Enumerable.Range(1, 5).Select(index => new WeatherForecast { Date = DateTime.Now.AddDays(index), TemperatureC = Random.Shared.Next(-20, 55), Summary = Summaries[Random.Shared.Next(Summaries.Length)] }) .ToArray(); }
打开d盘找到即可看见日志文本
输出格式如下:
2022-05-28 00:12:35.949 +08:00 [INF] ASDASDASDASDASDADSASDASDASDASDASDADSASDASDASDASDASDADSASDASDAS
(推荐)更高级一些的详细配置,建议把log等级分开配置 推荐配置4种
1、设置好4个路径,对应不同的日志类型
string infoPath = Directory.GetCurrentDirectory() + @"\logs\info\.log"; ; string waringPath = Directory.GetCurrentDirectory() + @"\logs\waring\.log"; string errorPath = Directory.GetCurrentDirectory() + @"\logs\error\.log"; string fatalPath = Directory.GetCurrentDirectory() + @"\logs\fatal\.log";
2、(推荐,不设也行)设置好模板
string template = "{NewLine}时间:{Timestamp:yyyy-MM-dd HH:mm:ss.fff}{NewLine}等级:{Level}{NewLine}来源:{SourceContext}{NewLine}具体消息:{Message}{NewLine}{Exception}";
3、具体配置
builder.Services.AddLogging(bulid => { Log.Logger = new LoggerConfiguration() .MinimumLevel.Information() .Enrich.FromLogContext() .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( waringPath, 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(); bulid.AddSerilog();
只做了基本配置,不够用的话,具体更多配置或更高级用法自行查询官网。
https://github.com/serilog
疑问
Serilog 在 ASP.NET Core 5 中用的好好的,原项目升级到6也没有问题,可是为什么新建ASP.NET Core 6.0项目,使用不了"UseSerilog()"呢?
解释
因为6使用了"new minimal hosting model",5上面"UseSerilog()"是扩展在"IHostBuilder"上面的,而6上使用的是"WebApplicationBuilder",所以"UseSerilog()"自然就无法使用了,但是"builder.Host"上是"IHostBuilder"类型,可以把"UseSerilog()"用在"builder.Host"上,不建议使用"builder.WebHost"哦。
正确示例
.csproj 文件
<ItemGroup> <PackageReference Include="Serilog" Version="2.10.0" /> <PackageReference Include="Serilog.AspNetCore" Version="4.1.0" /> <PackageReference Include="Serilog.Enrichers.Thread" Version="3.1.0" /> <PackageReference Include="Serilog.Sinks.Console" Version="4.0.0" /> <PackageReference Include="Serilog.Sinks.File" Version="5.0.0" /> </ItemGroup>
Program.cs
using Serilog; const string OUTPUT_TEMPLATE = "{Timestamp:yyyy-MM-dd HH:mm:ss.fff} <{ThreadId}> [{Level:u3}] {Message:lj}{NewLine}{Exception}"; Log.Logger = new LoggerConfiguration()
.MinimumLevel.Override("Microsoft", LogEventLevel.Information)//排除Microsoft日志
.MinimumLevel.Debug()
.Enrich.WithThreadId()
.Enrich.FromLogContext()
.WriteTo.Console(outputTemplate: OUTPUT_TEMPLATE)
.WriteTo.File("logs/app.txt" , rollingInterval: RollingInterval.Day , outputTemplate: OUTPUT_TEMPLATE)
.CreateLogger();
try {
Log.Information("Starting web host");
var builder = WebApplication .CreateBuilder(args);
builder.Host.UseSerilog(Log.Logger, dispose: true); // Add services to the container
. builder.Services.AddControllers();
var app = builder.Build(); // Configure the HTTP request pipeline
. app.UseAuthorization();
app.UseSerilogRequestLogging();
app.MapControllers();
app.Run();
} catch (Exception ex)
{ Log.Fatal(ex, "Host terminated unexpectedly"); }
finally { Log.CloseAndFlush(); }