从 Serilog 将事件提取到 Seq 中时出现问题

Problems ingesting events into Seq from Serilog

我正在开发一个 C# 应用程序,它在远程 Seq Serilog (Serilog.Sinks.Seq) 上发送日志.在我添加更多日志之前它一直运行良好;之后它只是将一些日志发送到 seq。我测试了 File sink 但它没有任何问题并将所有日志写入文件,但 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.  

根据您的编辑进行更新:

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

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

原回答:

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

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

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

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

Parameter Default Value Description
eventBodyLimitBytes 262,144 The maximum size, in bytes, that the JSON representation of an event may take before it is dropped rather than being sent to the Seq server. Specify null for no limit
batchPostingLimit 1,000 The maximum number of events to post in a single batch

如果 batched 事件在序列化为“compacted JSON”后不适合 eventBodyLimitBytes,则 整个 批次将被删除。 PeriodBatchingSink 使用 batchPostingLimit 来确定在将事件发送到内部接收器(执行 serialization/dropping)之前要排队的消息数。您还可以考虑更改最低日志级别,因为它默认为 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 将抛出异常。当对 AuditTo 使用 Seq 扩展方法时,使用 DurableSeqSink 代替。日志首先保存到磁盘(作为临时存储),然后传送到 Seq 一次一个。如果您真的必须保证日志消息不会被丢弃(并且,如果它们被通知您),这就是要走的路。这里有开销;消息必须写入文件,每个事件需要一个新的 HTTP 请求 并且 您需要使用 try/catch 保护所有日志记录语句。后一点是 IMO 反对这一点的最大原因,特别是如果您使用围绕 Serilog 的 Microsoft.Extensions.Logging.ILogger 抽象,因为消费者通常希望日志记录没有异常。

您还可以使用日志过滤器/LoggingLevelSwitch 和 Serilog 的 Filter.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