Skip to content
.NET 开发者指北.NET 开发者指北
CMS
.NET指北
FreeKit
Docker
关于
博客
github icon
    • .NET Core 学习示例文档
      • 创建简单Hello World
        • .NET Core 简单测试项目
          • FreeSql+ASP.NET Core
            • RESTful+FreeSql+AutoMapper
              • IdentityServer4
                • 七牛云对象存储
                  • ImCore 即时通讯
                    • Nacos 配置中心
                      • Serilog指北
                        • 1.概述
                          • 2. Hello, Serilog!
                            • 3. 事件和级别
                              • Logging levels
                                • 4. 发送和收集结构化数据
                                  • 将事件写入JSON日志文件
                                    • 将事件写入日志服务器
                                      • 5.标记用于筛选和关联的事件
                                      • 增加事件或记录器特定属性
                                        • 丰富源类型信息
                                          • 丰富环境语境
                                        • 在 ASP.NET Core 6 如何添加 Startup.cs
                                          • 在 ASP.NET Core 6 中添加Startup.cs的整洁方式

                                          Serilog指北

                                          calendar icon2022年1月7日timer icon大约 8 分钟word icon约 2378 字

                                          此页内容
                                          • 1.概述
                                          • 2. Hello, Serilog!
                                          • 3. 事件和级别
                                          • Logging levels
                                          • 4. 发送和收集结构化数据
                                          • 将事件写入JSON日志文件
                                            • 将事件写入日志服务器
                                            • 5.标记用于筛选和关联的事件
                                          • 增加事件或记录器特定属性
                                            • 丰富源类型信息
                                            • 丰富环境语境

                                          # Serilog指北

                                          • 原文:https://blog.datalust.co/serilog-tutorial/#3eventsandlevelsopen in new window
                                          • github: https://github.com/serilog/serilogopen in new window

                                          # 1.概述

                                          serilog是一个完全结构化事件的简单.NET日志记录

                                          fully-structured,结构化

                                          • 支持多种Provider,可将日志推送到不同的中间件,如文件,数据库(mysql,sql server,mariadb等)

                                          # 2. Hello, Serilog!

                                          让我们从最简单的开始,跟随以下教程,你需要创建一个Console项目,适用于.NET FrameWork 和.NET Core。

                                          Serilog 通过 NuGet 分发包. 该项目以Serilog包为核心组织,配合许多 sinks(接收器) (超过上百!), 用于将事件写入终端,文件,数据库,日志服务器的插件中。

                                          我们从 Serilog 和 Serilog.Sinks.Console开始, 稍后再讨论其他选项:

                                          Install-Package Serilog
                                          Install-Package Serilog.Sinks.Console
                                          
                                          1
                                          2

                                          以下是世界上最简单的 Serilog 配置:

                                          using Serilog;
                                          
                                          class Program
                                          {
                                              public static void Main(string[] args)
                                              {
                                                  using (var log = new LoggerConfiguration()
                                                      .WriteTo.Console()
                                                      .CreateLogger())
                                                  {
                                                      log.Information("Hello, Serilog!");
                                                      log.Warning("Goodbye, Serilog.");
                                                  }
                                              }
                                          }
                                          
                                          1
                                          2
                                          3
                                          4
                                          5
                                          6
                                          7
                                          8
                                          9
                                          10
                                          11
                                          12
                                          13
                                          14
                                          15

                                          明确以下几点

                                          • LoggerConfiguration 类提供 了一个fluent 接口 构建一个日志管道
                                          • WriteTo.Console() 将一个控制台接收器 添加到管道中
                                          • CreateLogger() 集合构建后会 返回一个 Logger 对象, 他实现了 ILogger的接口
                                          • Logger 接口继承 IDisposable, 所以我们使用 using 块
                                          • 最后, log.Information() 和 log.Warning() 通过logger记录所有的发出的事件

                                          运行程序

                                          image

                                          现在最迫切的问题是: 在我们的应用程序中,其他类如何得到这个Log对象? 除了通过参数进行传递, 有两种可能性

                                          • 如果您使用的是 IoC 容器, 你 可以使用组件接收ILogger对象,即通过 dependency injection(依赖注入) ILogger的方式使用. 像集成 AutofacSerilogIntegrationopen in new window等包即可。

                                          或者,你可以把Logger存储到一个已知的位置中;为此 Serilog有一个静态日志类

                                          Log.Logger = new LoggerConfiguration()
                                              .WriteTo.Console()
                                              .CreateLogger();
                                          
                                          Log.Information("Hello again, Serilog!");
                                          
                                          Log.CloseAndFlush();
                                          
                                          1
                                          2
                                          3
                                          4
                                          5
                                          6
                                          7

                                          Log 类提供了与ILogger接口相同的所有方法.用于替换使用using 块,我们可以调用 Log.CloseAndFlush(),重置Serilog.Log.Logger,并释放原有的资源

                                          你可能选择基于ILogger的注入方式使用,或使用静态Log类 -这种选择是基于个人口味和爱好的问题. 为了保持简单 我们将在此教程中使用静态日志类。

                                          # 3. 事件和级别

                                          如果使用过log4net等较旧的库,在使Serilog时,您需要在思维方式上做的最大改变是从日志事件而不是日志消息的角度来思考。活动由以下部分组成:

                                          • 记录事件发生时的时间戳
                                          • 描述何时应捕获事件的级别
                                          • 记录事件所代表内容的消息
                                          • 描述事件的命名属性
                                          • 可能是一个异常对象

                                          您可以将日志事件格式化为控制台的可读文本,正如我们在第一个示例中看到的:

                                          11:33:01 [INF] Hello, Serilog!
                                          
                                          1

                                          或者,您可以将同一事件格式化为JSON,并将其发送到远程日志服务器:

                                          {"@t":"2017-11-20T11:33:01.22138","@m":"Hello, Serilog!"}`
                                          
                                          1

                                          在幕后,应用程序中的日志语句创建LogEvent对象,而连接到管道的接收器则确定如何记录它们。

                                          # Logging levels

                                          Serilog速度很快,但始终构造和记录详细的日志事件可能会浪费CPU、磁盘和网络资源。为了管理这一点,Serilog事件被分配了调试、信息、警告和错误等级别。每个支持的级别都有一个Log.*()方法。

                                          在开发过程中,可能会打开调试级别事件:

                                          Log.Logger = new LoggerConfiguration()
                                              .MinimumLevel.Debug() // <- Set the minimum level
                                              .WriteTo.Console()
                                              .CreateLogger();
                                          
                                          // In a tight loop...
                                          Log.Debug("Processing item {ItemNumber} of {ItemCount}", itemNumber, itemCount);
                                          
                                          1
                                          2
                                          3
                                          4
                                          5
                                          6
                                          7

                                          在生产中,通常关闭调试事件并将最低级别设置为信息,以便只记录重要事件。阅读文档中有关Serilog级别的更多信息open in new window。

                                          # 4. 发送和收集结构化数据

                                          var itemNumber = 10;
                                          var itemCount = 999;
                                          Log.Debug("Processing item {ItemNumber} of {ItemCount}", itemNumber, itemCount);
                                          
                                          1
                                          2
                                          3

                                          您注意到日志消息中的{ItemNumber}之类的命名占位符了吗?这不是C#插值字符串:Log.*()方法接受消息模板,这是.NET格式字符串的一种变体,除了通常的{0}位置字符串外,还支持{Named}占位符。

                                          这似乎有点奇怪,直到您意识到,通过这样做,Serilog可以将消息的一部分作为一级属性与人性化文本一起捕获:

                                          {
                                              "@t": "2017-11-20T11:33:01.22138",
                                              "@l": "Debug",
                                              "@m": "Processing item 10 of 999",
                                              "ItemNumber": 10,
                                              "ItemCount": 999
                                          }
                                          
                                          1
                                          2
                                          3
                                          4
                                          5
                                          6
                                          7

                                          我们为什么要这样做?由于日志事件附带了一些有趣的字段作为属性,因此我们可以立即使用简单的过滤器(如ItemNumber>900)来查找事件,而不必通过正则表达式从消息中提取信息。

                                          更进一步,我们可以使用@structure捕获操作符不仅获取平面属性值,还获取完整的对象:

                                          var user = new { Name = "Nick", Id = "nblumhardt" };
                                          Log.Information("Logged on user {@User}", user);
                                          
                                          1
                                          2

                                          在这里,用户对象被捕获到生成的JSON中,因此我们可以使用诸如user.Id='nblumhardt'之类的查询来查找事件:

                                          {
                                              "@t": "2017-11-20T11:33:01.22138",
                                              "@m": "Logged on user {\"Name\": \"Nick\", \"Id\": \"nblumhardt\"}",
                                              "User": {"Name": "Nick", "Id": "nblumhardt"}
                                          }
                                          
                                          1
                                          2
                                          3
                                          4
                                          5

                                          生产监控和调试已经是一项艰巨、耗时且经常充满压力的任务:通常这些相关数据触手可及,Serilog消除了与操作相关 活动中最大的分歧之一。

                                          提示:从VisualStudioMarketplace安装了不起的Serilog分析器open in new window,以便在键入时检查消息模板语法

                                          这实际上会产生多大的差异,很大程度上取决于您如何从Serilog收集事件。传统上,日志事件进入文本文件并使用grep进行搜索。Serilog也可以记录文本文件,但您不能在记事本中执行ItemNumber>900,因此您需要评估更强大的工具来实现这一点。

                                          # 将事件写入JSON日志文件

                                          如果您的需求很简单,可以将JSON写入日志文件,并使用JSON感知工具直接查询文件。Serilog的文件接收器和紧凑的JSON格式化程序使第一部分变得简单。让我们尝试另一个安装了以下软件包的小型控制台应用程序:

                                          Install-Package Serilog;
                                          Install-Package Serilog.Sinks.File
                                          Install-Package Serilog.Formatting.Compact
                                          
                                          1
                                          2
                                          3

                                          在Main()方法中:

                                          Log.Logger = new LoggerConfiguration()
                                              .MinimumLevel.Debug()
                                              .WriteTo.File(new CompactJsonFormatter(), "log.clef")
                                              .CreateLogger();
                                          
                                          var itemCount = 99;
                                          for (var itemNumber = 0; itemNumber < itemCount; ++itemNumber)
                                              Log.Debug("Processing item {ItemNumber} of {ItemCount}", itemNumber, itemCount);
                                          
                                          Log.CloseAndFlush();
                                          
                                          1
                                          2
                                          3
                                          4
                                          5
                                          6
                                          7
                                          8
                                          9
                                          10

                                          运行此应用程序将使用Serilog的压缩日志事件格式在log.clef中生成一个新行分隔的JSON流open in new window。(如果没有CompactJsonFormatter,我们将创建一个简单的平面日志文件。)

                                          如果在文本编辑器中打开该文件,您将看到JSON事件,如我们上面使用的示例。

                                          # 将事件写入日志服务器

                                          Install-Package Serilog.Sinks.Seq
                                          
                                          1
                                          Log.Logger = new LoggerConfiguration()
                                              .MinimumLevel.Debug()
                                              .WriteTo.Seq("http://localhost:5341")
                                              .CreateLogger();
                                          
                                          1
                                          2
                                          3
                                          4

                                          # 5.标记用于筛选和关联的事件

                                          # 增加固定属性

                                          最简单的充实方法是向源自日志管道的所有事件添加固定属性值。这是使用记录器配置中的Enrich.WithProperty()完成的:

                                          Log.Logger = new LoggerConfiguration()
                                              .Enrich.WithProperty("Application", "Demo")
                                              .WriteTo.Seq("http://localhost:5341")
                                              .CreateLogger();
                                          
                                          1
                                          2
                                          3
                                          4

                                          在LogEvents上,通过扩展添加的属性与源自消息模板的属性相同:

                                          {
                                              "@t": "2017-11-20T11:33:01.22138",
                                              "@l": "Debug",
                                              "@m": "Processing item 10 of 999",
                                              "ItemNumber": 10,
                                              "ItemCount": 999,
                                              "Application": "Demo"
                                          }
                                          
                                          1
                                          2
                                          3
                                          4
                                          5
                                          6
                                          7
                                          8

                                          这种策略有助于放大集中日志流中的特定日志源;以这种方式添加的属性包括应用程序、环境和版本等内容。

                                          # 增加事件或记录器特定属性

                                          通过创建和使用上下文记录器,可以将属性添加到一个或几个相关事件中,而不是使用相同的值丰富所有事件:

                                          var orderLog = Log.ForContext("OrderId", order.Id);
                                          orderLog.Information("Looking up product codes");
                                          // ...
                                          orderLog.Information("Product lookup took {Elapsed} ms", elapsed.TotalMilliseconds);
                                          
                                          1
                                          2
                                          3
                                          4

                                          在这里,通过orderLog发出的两个事件都将附加OrderId属性。

                                          扩展是可添加的:如果Application属性设置在管道级别,则上面的第二个事件将携带经过(来自消息)、OrderId(来自上下文记录器)和Application(来自日志管道)。

                                          # 丰富源类型信息

                                          特定于记录器的充实的一个特例是如何用创建事件的类标记事件。

                                          在名为HomeController的类中,使用以下方法创建特定于类型的记录器:

                                          private readonly ILogger _log = Log.ForContext<HomeController>();
                                          
                                          1

                                          通过_log发出的事件将携带值为MyApp.Controller.HomeController的SourceContext属性。

                                          # 丰富环境语境

                                          为了丰富工作单元中引发的所有事件,Serilog提供了LogContext。首先需要在LoggerConfiguration级别使用Enrich.FromLogContext()启用此功能:

                                          Log.Logger = new LoggerConfiguraition()
                                               .Enrich.FromLogContext()
                                               // ...
                                          
                                          1
                                          2
                                          3

                                          LogContext可以看作是(键、值)对的堆栈;当从日志上下文中丰富事件时,这些事件将作为属性添加到事件中。

                                          using (LogContext.PushProperty("MessageId", message.Id))
                                          {
                                              Log.Debug("Dispatching message of type {MessageType}", message.GetType());
                                              await handler.HandleAsync(message);
                                          }
                                          
                                          1
                                          2
                                          3
                                          4
                                          5

                                          LogContext的有趣之处在于不需要传递任何信息。在示例代码中,HandleAsync()的实现以及它调用的任何其他方法都可以直接使用Log和ILogger、 MessageId属性将被提取并添加到后台。

                                          提示:LogContext是一个堆栈;推送到堆栈上的属性必须通过处理从PushProperty()返回的对象再次弹出-必须使用块。

                                          edit icon在 GitHub 上编辑此页open in new window
                                          上次编辑于: 2022/8/15 16:21:26
                                          贡献者: igeekfan,luoyunchong
                                          上一页
                                          Nacos 配置中心
                                          下一页
                                          在 ASP.NET Core 6 如何添加 Startup.cs
                                          MIT Licensed | Copyright © 2021-present luoyunchong
                                          苏ICP备16046457号-1

                                          该应用可以安装在你的 PC 或移动设备上。这将使该 Web 应用程序外观和行为与其他应用程序相同。它将在出现在应用程序列表中,并可以固定到主屏幕,开始菜单或任务栏。此 Web 应用程序还将能够与其他应用程序和你的操作系统安全地进行交互。

                                          详情