首页 > 解决方案 > 从 Serilog 将事件摄取到 Seq 中的问题

问题描述

我正在开发一个 C# 应用程序,它通过 Serilog (Serilog.Sinks.Seq)在远程Seq Sink上发送日志。在我添加更多日志之前它运行良好;之后,它只是将一些日志发送到 seq。我测试了文件接收器,但它没有任何问题,并将所有日志写入文件,但 seq 仍然有同样的问题。我什至在本地计算机上测试了 Seq,但没有利润。 所以我安装了Serilog.Sinks.PeriodicBatching希望能解决这个问题。但不幸的是,我没有找到任何文档或示例如何在我的项目中配置和启用它。我发现的唯一代码是https://github.com/serilog/serilog-sinks-periodicbatching
我不明白。有人知道如何使用它来解决 Seq 的这个问题吗?我需要一个简单的例子。
我正在使用最新版本的 Serilog 和 PeriodicBatching。
更新 1:
这是正确生成的文件日志。在 seq 中,最后三个日志被删除。

2021-02-06 09:45:36.164 +03:30 [INF] ⠀⠀⠀⠀⠀|  
2021-02-06 09:45:36.180 +03:30 [INF] Application Start.  
2021-02-06 09:45:36.180 +03:30 [ERR] It is a fresh OS  
System.ArgumentNullException: Value cannot be null.
Parameter name: value
   at Newtonsoft.Json.JsonConvert.DeserializeObject(String value, Type type, JsonSerializerSettings settings)
   at Newtonsoft.Json.JsonConvert.DeserializeObject[T](String value, JsonSerializerSettings settings)
   at SenderConsole.Program.scanClientAndSendIfDifferent() in D:\Programing\SysWatch\SenderConsole\Program.cs:line 434  
2021-02-06 09:45:36.195 +03:30 [DBG] getCurrentClientConfig() Started.  
2021-02-06 09:45:36.289 +03:30 [DBG] getCurrentClientConfig()==> CpuChanges  
2021-02-06 09:45:36.305 +03:30 [DBG] getCurrentClientConfig()==> StorageChanges  
2021-02-06 09:45:36.383 +03:30 [DBG] getCurrentClientConfig()==> RamChanges  
2021-02-06 09:45:36.398 +03:30 [DBG] getCurrentClientConfig()==> MotherboardChanges  
2021-02-06 09:45:36.414 +03:30 [DBG] getCurrentClientConfig()==> OsChanges  
2021-02-06 09:45:36.492 +03:30 [DBG] getCurrentClientConfig()==> NicChanges  
2021-02-06 09:45:36.679 +03:30 [DBG] getCurrentClientConfig()==> PrinterChanges  
2021-02-06 09:45:36.695 +03:30 [DBG] getCurrentClientConfig()==> DomainChanges  
2021-02-06 09:45:36.883 +03:30 [DBG] getCurrentClientConfig()==> iSMBIOSChanges  
2021-02-06 09:45:36.914 +03:30 [DBG] getCurrentClientConfig()==> AppChanges  
2021-02-06 09:45:36.929 +03:30 [DBG] getCurrentClientConfig()==> AntivirusChanges  
2021-02-06 09:45:36.929 +03:30 [DBG] getCurrentClientConfig() Ended.  
2021-02-06 09:45:36.929 +03:30 [DBG] configsAreDifferent() Started.  
2021-02-06 09:45:36.929 +03:30 [INF] Configs are different.  
2021-02-06 09:45:36.929 +03:30 [DBG] serializeByJson() Started.  
2021-02-06 09:45:37.148 +03:30 [DBG] serializeByJson() Ended.  
2021-02-06 09:45:39.210 +03:30 [FTL] Unable to connect to the remote server  
2021-02-06 09:45:39.210 +03:30 [INF] Sent to DB.  
2021-02-06 09:45:39.210 +03:30 [INF] Application End.  

标签: c#loggingserilogseq

解决方案


根据您的编辑更新:

程序结束前的最后几条消息似乎是被丢弃的消息。您需要刷新记录器以确保 Serilog 在应用程序有时间退出之前强制并等待任何挂起的日志事件:

public static void Main() 
{
   try
   {
       // Program Logic here
   } 
   finally
   {
       Serilog.Log.CloseAndFlush(); 
   } 
} 

原答案:

结构化日志记录属性可能会变得非常大,这会导致更大的 HTTP 请求和处理它们的 CPU 需求增加。您的事件“丢失”的原因是因为 Seq(服务器)和 Serilog Sink 都施加了限制,试图缓解这些问题。消息(单个事件或整个批次)可以由客户端或服务器丢弃,具体取决于特定配置和消息/批次大小。注意我说的是“批次”;调用Seq链接的扩展方法WriteTo将添加一个PeriodicBatchingSink(的实现IBatchedLogEventSink),它包装SeqSink. 所以你不需要自己尝试包装它——它已经完成了。

那么如何缓解你的问题呢?首先,您可以更新服务器上的设置。Seq 建议不要这样做,但是有明确的用例,特别是如果您要发送大量属性。您可以在Settings -> System -> Ingestion下面修改“原始摄取负载限制”和/或“原始事件主体限制”设置。就个人而言,我将前者保留为默认值,并根据我们基于如何配置 Sink 本身所做的一些计算来增加后者:

序列服务器设置

注意带下划线的警告!确保您了解修改这些设置的含义。

现在在客户端,您有几个选择。Seq扩展方法有一些参数可以用来调整记录器的行为。

范围 默认值 描述
eventBodyLimitBytes 262,144 事件的 JSON 表示在被删除而不是发送到 Seq 服务器之前可能占用的最大大小(以字节为单位)。指定null无限制
batchPostingLimit 1,000 单个批次中发布的最大事件数

如果批处理事件在序列化为“压缩 JSON”后不适合eventBodyLimitBytes,则整个批处理将被删除。batchPostingLimit用于确定在将PeriodBatchingSink事件发送到内部接收器(执行序列化/丢弃)之前要排队多少消息。您也可以考虑更改最低日志级别,因为它默认为Verbose或传入LoggingLevelSwitch

var maxSizeBytes = 512 * 1024; // 512KB, double the default
var batchLimit = 100; // 1/10 the default
logger.WriteTo.Seq(
    "http://seq.server.com", 
    eventBodyLimitBytes: maxSizeBytes, 
    batchPostingLimit: batchLimit, 
    restrictedToMinimumLevel: LogEventLevel.Information
);

配置较小的批处理大小可能会减少超出字节限制的机会,但这会导致发送更多的HTTP 请求,这可能是其自身的问题。现在请记住,您还需要坚持服务器的配置;您的组合事件大小需要小于“原始摄取负载限制”,以确保不会丢弃整个批次,并且单个事件必须小于“原始事件主体限制”。

由于我对您的实际事件一无所知,因此无法就此处的适当设置提供建议。我只能为您指出正确的方向。我只能说,您应该根据服务器设置、事件知识(及其附加属性)和业务需求执行一些有意义的计算:

您的另一个选择是使用“审计”接收器。在这种模式下,如果日志消息无法传输到目标介质,Serilog 将抛出异常。当对 使用Seq扩展方法时AuditTo,将DurableSeqSink使用 a 代替。日志首先保存到磁盘(作为临时存储),然后一次发送到 Seq 。如果您真的必须保证日志消息不会被丢弃(并且如果它们被通知了),那么这就是要走的路。这里有开销;消息必须写入文件,每个事件都需要一个新的 HTTP 请求,并且需要使用try/catch. 后一点是 IMO 反对这一点的最大原因,特别是如果您使用Microsoft.Extensions.Logging.ILogger围绕 Serilog 的抽象,因为消费者通常希望日志记录是无异常的。

您还可以使用日志过滤器/LoggingLevelSwitch和 SerilogFilter.ByExcluding来控制将要发送的消息。此外,您还可以考虑调整解构深度和大小,以确保嵌套属性和集合仅序列化到最大大小。

logger.Destructure.ToMaximumDepth(5) // default 10
      .Destructure.ToMaximumStringLength(1000) // made up value, default is int.MaxValue
      .Destructure.ToMaximumCollectionCount(10) // made up, default is int.MaxValue

推荐阅读