自己建网站服务器,网站建设公司厂,保定软件开发公司,电商网站的宣传推广前言对内置日志系统的整体实现进行了介绍之后#xff0c;可以通过使用内置记录器来实现日志的输出路径。而在实际项目开发中#xff0c;使用第三方日志框架#xff08;如#xff1a;Log4Net、NLog、Loggr、Serilog、Sentry 等#xff09;来记录也是非常多的。首先一般基础… 前言对内置日志系统的整体实现进行了介绍之后可以通过使用内置记录器来实现日志的输出路径。而在实际项目开发中使用第三方日志框架如Log4Net、NLog、Loggr、Serilog、Sentry 等来记录也是非常多的。首先一般基础的内置日志记录器在第三方日志框架中都有实现然后第三方日志框架在功能上更加强大和丰富能满足我们更多的项目分析和诊断的需求。所以在这一篇中我们将介绍第三方日志记录提供程序——Serilog回顾系统内置日志系列1. 基于.NetCore3.1系列 —— 日志记录之日志配置揭秘2. 基于.NetCore3.1系列 —— 日志记录之日志核心要素揭秘3. 基于.NetCore3.1系列 —— 日志记录之自定义日志组件从之前学习的内置日志系统中我们根据日志配置的方式了解到了通过配置的方式可以有效的输出日志记录方便我们查找发现问题。而在进一步对内部运行的主要核心机制进行深入探究后发现了内置日志记录的几个核心要素在日志工厂记录器(ILoggerFactory)中实现将日志记录提供器(ILoggerProvider)对象都可以集成到Logger对象组合中这样的话我们就可以通过基于ILoggerProvider自定义日志记录程序集成到Logger中再创建写日志定义Ilogger自定义日志记录器实现日志的输出方式这样实现自定义日志记录工具。在最后我们通过自定义的方式简单的实现了自定义日志组件在这个基础上我们可以根据具体的需求进行完善修改。当然了我们也可以借用第三方日志框架组件程序进行使用。说明我们都知道日志记录在项目开发中或者生产环境中都起到举足轻重的作用。因此我们都会采用在项目加入第三方框架日志或自行封装日志记录来记录日志。所以在这一篇中我们会采用在项目中使用Serilog目的不仅仅在于希望在用户使用之前发现代码中的BUG和错误更多的是方便我们可以快速的查询生产环境的日志问题深入的了解系统运行的表现。从Serilog的官方介绍中我们可以发现 其框架是.net中的诊断日志库可以在所有的.net平台上运行。支持结构化日志记录对复杂、分布式、异步应用程序的支持非常出色。Serilog是基于日志事件(log events),而不是日志消息(log message)。可以将日志事件格式化为控制台的可读文本或者将事件化为JSON格式。应用程序中的日志语句会创建LogEvent对象而连接到管道的接收器sinks会知道如何记录它们。接收器 包括各种终端、控制台、文本、SqlServer、ElasticSearch等等可用的列表结构化与非结构化之间的问题对于日志的处理在大部分情况下会权衡是否对开发者的友好型以及对程序解析的方便性。在很多情况下开发者可能只是想记录一段日志而已所以可以会考虑简单的加上一行代码来以达到记录日志的目的,如(log.debug(Disk quota {0} exceeded by user {1}, quota, user);)当然了日志的执行结构可能被存于文本文件或者数据库中。这样的日志从开发者的角度来说清晰易懂十分友好。但是如果后续要使用程序取查找海量的的上述例子在某段时间内的特定用户则很难高效率地完成这一要求因为需要对每个日志进行字符串解析。因此我们就需要寻求更快更方便的方式来查找记录。非结构的日志对自由格式文本的解析往往依赖于正则表达式并且依赖于不变的文本。这会使解析自由格式的文本变得非常脆弱即解析与代码中的确切文本紧密耦合。还考虑搜索/查找的情况例如SELECT text FROM logs WHERE text LIKE Disk quota;LIKE条件需要与每个text行值进行比较再次这在计算上是相对浪费的尤其是在使用通配符时SELECT text FROM logs WHERE text LIKE Disk %;结构化的日志使用结构化日志记录与磁盘错误相关的日志消息在JSON中可能如下所示{ level: DEBUG, user: username, error_type: disk, text: Disk quota ... exceeded by user ... }这种结构的字段可以很容易地映射到例如 SQL表列名这意味着查找可以更具体/更细粒度SELECT user, text FROM logs WHERE error_type disk;您可以在希望经常搜索/查找其值的列上放置索引只要您不对LIKE这些列值使用子句即可。您可以将日志消息细分为特定类别的内容越多查找的对象就越有针对性。例如除了error_type上面示例中的字段/列之外您甚至可以设置为be error_category: disk, error_type: quota或诸如此类。结构越多你的日志消息通过解析/检索系统如fluentdelasticsearchkibana可以利用该结构并以更快的速度和更低的CPU /内存执行任务。总之这不仅与速度和效率有关更重要的是使用结构化日志记录和“结构化查询”时能以特定格式捕获以及呈现结构化日志同时提供对开发者与程序友好的解析支持。可以更方便地以其为条件进行筛选搜索结果的相关性将更高。如果没有这种搜索那么在不同上下文中出现的任何单词都会给您带来大量无关的点击。开始为了更好的理解认识Serilog,我们这简单的创建一个新的项目来认识一下Serilog的使用。这里我们就简单的使用Console和Debug的方式来实现后续有机会我们可以实现更多方式的接收器写入日志。4.1 Serilog使用4.1.1 安装依赖包Serilog.AspNetCore : 基于AspNetCore框架整合的Serilog日志记录程序包包含了Serilog基本库和控制台日志的实现。当然了你也可以直接安装Serilog 基本库然后根据需要安装对应的拓展包。说明Serilog.Extensions.Logging 包含了注入了Serilog的拓展方法。Serilog.Sinks.Async 实现了日志异步收集。Serilog.Sinks.Console 实现了控制台输出日志。Serilog.Sinks.Debug 实现了调试台输出日志。Serilog.Sinks.File 实现了文件输出日志。4.1.2 配置Serilog在应用程序中Program.cs文件中配置Serilog记录确保正确记录任何配置日志问题。 public static void Main(string[] args){Log.Logger new LoggerConfiguration().MinimumLevel.Debug().MinimumLevel.Override(Microsoft, LogEventLevel.Information).Enrich.FromLogContext().WriteTo.Console().CreateLogger();try{Log.Information(Starting web host);CreateHostBuilder(args).Build().Run();}catch (Exception ex){Log.Fatal(ex, Host terminated unexpectedly);}finally{Log.CloseAndFlush();}}然后添加UseSerilog()到CreateHostBuilder()中的通用主机中。 public static IHostBuilder CreateHostBuilder(string[] args) Host.CreateDefaultBuilder(args) //从appsettings.json中读取配置。.UseSerilog() // -- Add this line.ConfigureLogging((hostingContext, logging) {logging.ClearProviders(); //去掉默认添加的日志提供程序}).ConfigureWebHostDefaults(webBuilder {webBuilder.UseStartupStartup();});
}最后通过删除默认记录器的其余配置进行清理从appsettings.json文件中删除Logging对应的配置部分。可以再使用根据Serilog的配置规则进行相应配置替换它。Serilog: {
MinimumLevel: {
Default: Information,
Override: {
Microsoft: Warning,
System: Warning
}
}
}4.1.3 提示当在IIS下运行时候要在Visual Studio输出窗口中查看Serilog输出日志的时候需要将输出方式选择为 Web 服务器方式输出窗口查看日志或者使用WriteTo.Debug()替换记录器配置中的WriteTo.Console()。4.2 输出格式4.2.1 文本格式作为文本它的格式如下[21:45:15 INF] HTTP GET / responded 200 in 227.3253 ms测试在控制台中输出如下上述事件格式中可以看出由以下几个格式组成事件发生时的时间戳[timestamp]描述何时应该捕获事件的级别[level]记录事件的消息[message]内容]描述事件的命名属性[properties]还可能有一个Exception对象4.2.2 JSON格式作为JSON格式它的格式如下{t: 2020-08-27T13:59:44.6410761Z,mt: HTTP {RequestMethod} {RequestPath} responded {StatusCode} in {Elapsed:0.0000} ms,r: [224.5185],RequestMethod: GET,RequestPath: /,StatusCode: 200,Elapsed: 224.5185,RequestId: 0HLNPVG1HI42T:00000001,CorrelationId: null,ConnectionId: 0HLNPVG1HI42T
}在写入日志文件中根据Serilog的多种接收器的中Console()、Debug()、File()等支持使用JSON写入日志记录通过引用紧凑的JSON格式化类库[Serilog.Formatting.Compact]接收所有JSON格式的输出。要编写以换行符分隔的JSON请将CompactJsonFormatter或RenderedCompactJsonFormatter传递到接收器配置方法,如下 .WriteTo.Console(new RenderedCompactJsonFormatter())或.WriteTo.Console(new CompactJsonFormatter())运行这个程序将产生使用Serilog的紧凑格式JSON并在对应的输出路径中生成换行符分隔的JSON流。4.3 示例4.3.1 安装依赖包安装 Serilog.AspNetCore NuGet 包 4.3.2 配置文件在appsettings.json配置文件添加 Serilog 配置WriteTo 指定输出目标位置它是一个数组类型所以可以指定多个目标位置这里暂时只指定输出到控制台{Serilog: {MinimumLevel: {Default: Debug}}
}4.3.3 设置配置信息读取配置文件信息设置配置信息public static IConfiguration Configuration { get; } new ConfigurationBuilder().SetBasePath(Directory.GetCurrentDirectory()).AddJsonFile(appsettings.json, optional: false, reloadOnChange: true).AddJsonFile($appsettings.{Environment.GetEnvironmentVariable(ASPNETCORE_ENVIRONMENT) ?? Production}.json, optional: true).AddEnvironmentVariables().Build();在main方法中 public static void Main(string[] args){Log.Logger new LoggerConfiguration().ReadFrom.Configuration(Configuration).Enrich.FromLogContext().WriteTo.Debug() //输出路径.WriteTo.Console(outputTemplate: [{Timestamp:HH:mm:ss} {Level:u3}] {Message:lj} {Properties:j}{NewLine}{Exception}) //模板.CreateLogger();try{Log.Information(Starting web host);CreateHostBuilder(args).Build().Run();}catch (Exception ex){Log.Fatal(ex, Host terminated unexpectedly);}finally{Log.CloseAndFlush();}}在Program.cs 添加 UseSerilog()public static IHostBuilder CreateHostBuilder(string[] args)
Host.CreateDefaultBuilder(args).ConfigureWebHostDefaults(webBuilder {webBuilder.UseStartupStartup();}).UseSerilog(); //添加4.3.4 设置请求管道在 Startup.cs 的 中的Configure 请求管道中添加 UseSerilogRequestLoggingpublic void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{if (env.IsDevelopment()){app.UseDeveloperExceptionPage();}app.UseStaticFiles();app.UseSerilogRequestLogging();app.UseRouting();app.UseAuthorization();app.UseEndpoints(endpoints {endpoints.MapControllers();});
}重要的是UseSerilogRequestLogging()调用应出现在诸如MVC之类的处理程序之前。中间件不会对管道中出现在它之前的组件进行时间或日志记录。通过将UseSerilogRequestLogging()放在它们之后可以将其用于从日志中排除杂乱的处理程序例如UseStaticFiles()。为了减少每个HTTP请求需要构造传输和存储的日志事件的数量。在同一事件上具有许多属性还可以使请求详细信息和其他数据的关联更加容易。默认情况下以下请求信息将作为属性添加请求方法请求路径状态码响应时间您可以使用UseSerilogRequestLogging()上的选项回调来修改用于请求完成事件的消息模板添加其他属性或更改事件级别app.UseSerilogRequestLogging(options
{// 自定义消息模板options.MessageTemplate Handled {RequestPath};// 发出调试级别的事件而不是默认事件options.GetLevel (httpContext, elapsed, ex) LogEventLevel.Debug; //将其他属性附加到请求完成事件options.EnrichDiagnosticContext (diagnosticContext, httpContext) {diagnosticContext.Set(RequestHost, httpContext.Request.Host.Value);diagnosticContext.Set(RequestScheme, httpContext.Request.Scheme);};
});4.3.5 输出效果由于日志总是输出一堆我们不能快速的查找定位问题其实 Serilog 输出的日志是非常简洁的只有 HTTP GET ... 这一条其他都是 AspNetCore 系统本身输出的所以我们可以对输出的日志进行简化操作。4.3.6 输出简化为了使日志输出更简洁我们可以设置不输出 AspNetCore Info 日志只需在 Serilog配置节点中设置 AspNetCore 日志输出级别为 Warning{Serilog: {MinimumLevel: {Default: Debug,Override: {Microsoft: Warning,System: Warning}}}
}总结 1. 本篇主要是对Serilog的说明认识到是一个基于日志事件的而非日志消息的结构化日志类库。 2. 简单的涉及对基础知识的认识以及使用通过构建一个新的项目来实现Serilog的日志记录以及怎么使用这个框架。 3. 在后续中如何结合这个日志类库引入项目中使用以及对日志怎么存储和查询进行说明会考虑 ELK存储采集分析 。 4. 如果有不对的或不理解的地方希望大家可以多多指正提出问题一起讨论,不断学习,共同进步。 5. 参考资料官方简介 、Serilog文档、serilog-aspnetcore 6. 搜索关注公众号【DotNet技术谷】--回复【serilog】可获取本篇文章的源码。