在 ASP.NET Core 中使用 Serilog/Fluentd 将日志写入 Elasticsearch

开发 后端
在这篇文章中,我描述了如何将 Serilog 日志记录添加到您的 ASP.NET Core 应用程序并将其配置为以 Elasticsearch 期望的 JSON 格式将日志写入控制台。

[[416435]]

本文转载自微信公众号「DotNET技术圈」,作者Andrew Lock 。转载本文请联系DotNET技术圈公众号。

原文来自:https://andrewlock.net/writing-logs-to-elasticsearch-with-fluentd-using-serilog-in-asp-net-core/

对于在 Kubernetes 中运行的应用程序,将日志消息存储在一个中心位置尤为重要。我认为这对所有应用程序都很重要,无论您使用的是 Kubernetes 还是 docker,但 pod 和容器的短暂性质使得后一种情况特别重要。

如果您没有集中存储容器中的日志,那么如果容器崩溃并重新启动,日志可能会永远丢失。

有很多方法可以实现这一目标。您可以直接从您的应用程序登录Elasticsearch或Seq,或者登录到Elmah.io等外部服务。一种常见的方法是使用 Fluentd 从容器的控制台输出中收集日志,并将这些日志通过管道传输到 Elasticsearch 集群。

默认情况下,ASP.NET Core 中的控制台日志输出格式为人类可读格式。如果您采用 Fluentd/Elasticsearch 方法,您需要确保您的控制台输出采用 Elasticsearch 可以理解的结构化格式,即 JSON。

在这篇文章中,我描述了如何将 Serilog 添加到 ASP.NET Core 应用程序,以及如何自定义 Serilog 控制台接收器的输出格式,以便您可以使用 Fluentd 将控制台输出通过管道传输到 Elasticsearch。

请注意,也可以将 Serilog 配置为使用Elasticsearch sink直接写入Elasticsearch。如果您没有使用 Fluentd,或者没有将您的应用程序容器化,那么这是一个不错的选择。

将日志写入控制台输出

当您从模板创建新的 ASP.NET Core 应用程序时,您的程序文件将如下所示(至少在 .NET Core 2.1 中):

  1. public class Program 
  2.     public static void Main(string[] args) 
  3.     { 
  4.         CreateWebHostBuilder(args).Build().Run(); 
  5.     } 
  6.  
  7.     public static IWebHostBuilder CreateWebHostBuilder(string[] args) => 
  8.         WebHost.CreateDefaultBuilder(args) 
  9.             .UseStartup<Startup>(); 

静态辅助方法WebHost.CreateDefaultBuilder(args)创建一个WebHostBuilder并连接许多标准配置选项[1]。默认情况下,它配置控制台和调试记录器提供程序:

  1. .ConfigureLogging((hostingContext, logging) => 
  2.     logging.AddConfiguration(hostingContext.Configuration.GetSection("Logging")); 
  3.     logging.AddConsole(); 
  4.     logging.AddDebug(); 
  5. }) 

如果您从命令行使用 运行您的应用程序dotnet run,您将在控制台中看到每个请求的日志。下面显示了来自浏览器的两个请求生成的日志 - 一个用于主页,另一个用于 favicon.ico。

使用默认控制台记录器的控制台输出

不幸的是,控制台记录器在如何写入日志方面没有提供很大的灵活性。您可以选择包含 scopes或禁用颜色,但仅此而已。

ASP.NET Core 中默认Microsoft.Extensions.Logging基础结构的替代方法是使用 Serilog进行日志记录,并将其作为标准 ASP.NET Core 记录器进行连接。

将 Serilog 添加到 ASP.NET Core 应用程序

Serilog是一个成熟的开源项目,早于 ASP.NET Core 中的所有日志记录基础结构。在许多方面,ASP.NET Core 日志记录基础结构似乎以 Serilog 为模型:Serilog 具有类似的配置选项和可插拔的“接收器”来控制写入日志的位置。

开始使用 Serilog 的最简单方法是使用Serilog.AspNetCore NuGet 包。使用以下命令将其添加到您的应用程序中:

  1. dotnet add package Serilog.AspNetCore 

您还需要添加一个或多个“sink”包,以控制日志的写入位置。在这种情况下,我将安装控制台接收器,但如果您想一次写入多个目的地,您也可以添加其他接收器。

  1. dotnet add package Serilog.Sinks.Console 

Serilog.AspNetCore 包UseSerilog()在WebHostBuilder实例上提供了一个扩展方法。这用ILoggerFactorySerilog 的实现替换了默认值。您可以传入现有Serilog.ILogger实例,也可以内联配置记录器。例如,以下代码配置将写入的最低日志级别 ( info) 并注册控制台接收器:

  1. public static IWebHostBuilder CreateWebHostBuilder(string[] args) => 
  2.     WebHost.CreateDefaultBuilder(args) 
  3.         .UseSerilog((ctx, config) => 
  4.         { 
  5.             config 
  6.                 .MinimumLevel.Information() 
  7.                 .Enrich.FromLogContext() 
  8.                 .WriteTo.Console(); 
  9.         }) 
  10.         .UseStartup<Startup>(); 

当您使用 Serilog 而不是默认记录器时再次运行应用程序会提供以下控制台输出:

使用 Serilog 而不是默认的控制台记录器的控制台输出

输出类似于默认记录器,但重要的是它是非常可配置的。您可以随意更改输出模板。例如,您可以通过包含SourceContext参数来显示生成日志的类的名称。

有关 Serilog.AspNetCore 包的更多详细信息和示例,请参阅 GitHub 存储库[2]。有关控制台格式选项,请参阅Serilog.Sinks.Console 存储库[3]。

除了对输出模板的简单更改外,控制台接收器还允许完全控制消息的呈现方式。我们将使用该功能将日志呈现为 Fluentd 的 JSON,而不是人性化的格式。

自定义Serilog Console Sink的输出格式写入JSON

要更改数据的呈现方式,您可以添加自定义ITextFormatter. Serilog 包含一个JsonFormatter您可以使用的,但建议您考虑使用Serilog.Formatting.Compact包[4]:

“CompactJsonFormatter与 Serilog 的默认值相比,大大减少了小日志事件的字节数JsonFormatter,同时保持人类可读。它通过更短的内置属性名称、更精简的格式以及排除冗余信息来实现这一点。”

我们不会将这个包用于我们的 Fluentd/Elasticsearch 用例,但我将展示如何在任何情况下插入它。使用 添加包dotnet add package Serilog.Formatting.Compact,创建格式化程序的新实例,并将其传递给调用中的WriteTo.Console()方法UseSerilog():

  1. .UseSerilog((ctx, config) => 
  2.     config 
  3.         .MinimumLevel.Information() 
  4.         .Enrich.FromLogContext() 
  5.         .WriteTo.Console(new CompactJsonFormatter()); 
  6. }) 

现在,如果您运行您的应用程序,您将看到以 JSON 格式写入控制台的日志:

使用 CompactJsonFormatter 以 JSON 格式写入控制台的日志图像

这个格式化程序可能对您有用,但就我而言,我希望编写 JSON 以便 Elasticsearch 能够理解它。您可以看到紧凑的 JSON 格式(在下面打印得很漂亮),正如承诺的那样,为时间戳 ( @t)、消息模板 ( @mt) 和呈现的消息 ( @r)使用了紧凑的名称:

  1.   "@t""2018-05-17T10:23:47.0727764Z"
  2.   "@mt""{HostingRequestStartingLog:l}"
  3.   "@r": [ 
  4.     "Request starting HTTP\/1.1 GET http:\/\/localhost:5000\/  " 
  5.   ], 
  6.   "Protocol""HTTP\/1.1"
  7.   "Method""GET"
  8.   "ContentType"null
  9.   "ContentLength"null
  10.   "Scheme""http"
  11.   "Host""localhost:5000"
  12.   "PathBase"""
  13.   "Path""\/"
  14.   "QueryString"""
  15.   "HostingRequestStartingLog""Request starting HTTP\/1.1 GET http:\/\/localhost:5000\/  "
  16.   "EventId": { 
  17.     "Id": 1 
  18.   }, 
  19.   "SourceContext""Microsoft.AspNetCore.Hosting.Internal.WebHost"
  20.   "RequestId""0HLDRS135F8A6:00000001"
  21.   "RequestPath""\/"
  22.   "CorrelationId"null
  23.   "ConnectionId""0HLDRS135F8A6" 

对于最简单的 Fluentd/Elasticsearch 集成,我希望使用标准 Elasticsearch 名称(例如@timestamp时间戳)输出 JSON 。幸运的是,所需要的只是更换格式化程序。

使用与 Elasticsearch 兼容的 JSON 格式化程序

该Serilog.Sinks.Elasticsearch包包含正是我们所需要的格式ElasticsearchJsonFormatter。这使用标准 Elasticsearch 字段(如@timestamp和 )呈现数据fields。

不幸的是,目前除了复制和粘贴源代码首先检查许可证之外,将格式化程序添加到您的项目的唯一方法是安装整个Serilog.Sinks.Elasticsearch包,它有很多依赖项。

理想情况下,我希望将格式化程序视为它自己的独立包,就像Serilog.Formatting.Compac一我提出了一个问题[5]如果这对您来说不是问题(这对我来说不是问题,因为我已经依赖Elasticsearch.Net,那么添加 Elasticsearch Sink 来访问格式化程序是最简单的解决方案。使用添加接收器dotnet add package Serilog.Sinks.ElasticSearch,并更新您的 Serilog 配置使用ElasticsearchJsonFormatter:

  1. .UseSerilog((ctx, config) => 
  2.     config 
  3.         .MinimumLevel.Information() 
  4.         .Enrich.FromLogContext() 
  5.         .WriteTo.Console(new ElasticsearchJsonFormatter(); 
  6. }) 

连接此格式化程序后,控制台输出将包含常见的 Elasticsearch 字段,如@timestamp,如下面(漂亮打印)输出所示:

  1. {  "@timestamp""2018-05-17T22:31:43.9143984+12:00",  "level""Information",  "messageTemplate""{HostingRequestStartingLog:l}",  "message""Request starting HTTP\/1.1 GET http:\/\/localhost:5000\/  ",  "fields": {    "Protocol""HTTP\/1.1",    "Method""GET",    "ContentType"null,    "ContentLength"null,    "Scheme""http",    "Host""localhost:5000",    "PathBase""",    "Path""\/",    "QueryString""",    "HostingRequestStartingLog""Request starting HTTP\/1.1 GET http:\/\/localhost:5000\/  ",    "EventId": {      "Id": 1    },    "SourceContext""Microsoft.AspNetCore.Hosting.Internal.WebHost",    "RequestId""0HLDRS5H8TSM4:00000001",    "RequestPath""\/",    "CorrelationId"null,    "ConnectionId""0HLDRS5H8TSM4"  },  "renderings": {    "HostingRequestStartingLog": [      {        "Format""l",        "Rendering""Request starting HTTP\/1.1 GET http:\/\/localhost:5000\/  "      }    ]  }} 

现在日志以一种可以直接从 Fluentd 传输到 Elasticsearch 的格式呈现。我们可以只写到控制台。

根据托管环境在输出格式化程序之间切换

最后的提示。如果您想在本地开发时获得人类可读的控制台输出,并且只在 Staging 或 Production 中使用 JSON 格式化程序怎么办?

这很容易实现,因为UseSerilog扩展提供了IHostingEnvironment通过WebHostBuilderContext. 例如,在以下代码段中,我将应用程序配置为在开发中使用人类可读的控制台,并在其他环境中使用 JSON 格式化程序。

  1. .UseSerilog((ctx, config) => 
  2.     config 
  3.         .MinimumLevel.Information() 
  4.         .Enrich.FromLogContext(); 
  5.  
  6.     if (ctx.HostingEnvironment.IsDevelopment()) 
  7.     { 
  8.         config.WriteTo.Console(); 
  9.     } 
  10.     else 
  11.     { 
  12.         config.WriteTo.Console(new ElasticsearchJsonFormatter()); 
  13.     } 
  14. }) 

除了环境之外,您还可以根据通过IConfiguration对象 at提供的配置值进行切换ctx.Configuration。

概括

将日志存储在一个中心位置很重要,尤其是在您构建容器化应用程序时。一种可能的解决方案是将日志输出到控制台,让 Fluentd 监控控制台,并将输出通过管道传输到 Elasticsearch 集群。在这篇文章中,我描述了如何将 Serilog 日志记录添加到您的 ASP.NET Core 应用程序并将其配置为以 Elasticsearch 期望的 JSON 格式将日志写入控制台。

References

[1] 连接许多标准配置选项: https://github.com/aspnet/MetaPackages/blob/2.1.0-rc1-final/src/Microsoft.AspNetCore/WebHost.cs#L150

[2] 请参阅 GitHub 存储库: https://github.com/serilog/serilog-aspnetcore

[3] Serilog.Sinks.Console 存储库: https://github.com/serilog/serilog-sinks-console

[4] 考虑使用Serilog.Formatting.Compact包: https://github.com/serilog/serilog-formatting-compact 

[5] 我提出了一个问题: https://github.com/serilog/serilog-sinks-elasticsearch/issues/176

 

责任编辑:武晓燕 来源: DotNET技术圈
相关推荐

2021-02-02 16:19:08

Serilog日志框架

2009-07-20 16:45:41

使用StringBuiASP.NET

2021-03-17 09:45:31

LazyCacheWindows

2021-02-06 21:40:13

SignalR通讯TypeScript

2021-01-31 22:56:50

FromServiceASP

2021-03-10 09:40:43

LamarASP容器

2021-01-07 07:39:07

工具接口 Swagger

2021-02-03 13:35:25

ASPweb程序

2021-01-28 22:39:35

LoggerMessa开源框架

2021-02-28 20:56:37

NCache缓存框架

2021-03-03 22:37:16

MediatR中介者模式

2009-05-05 14:02:14

PlaceHolder控件ASP.NET

2021-02-07 17:29:04

监视文件接口

2021-02-17 08:51:55

cookie身份验证

2021-11-02 13:54:41

ElasticSear.NET程序

2021-11-01 14:52:38

ElasticSear索引SQL

2016-12-01 09:44:29

ASP.NET在线编辑器

2009-02-05 13:40:03

TreeviewXMLASP.NET

2021-06-22 16:59:56

微软.NETC# 软件开发

2021-04-12 07:03:10

轻量级模块化框架
点赞
收藏

51CTO技术栈公众号