c# - 为什么在使用 Serilog 日志记录时会出现 Serilog SelfLog 错误?

标签 c# serilog ioexception .net-framework-version serilog-sinks-file

我在使用Serilog SelfLog时遇到一个有趣的错误。错误是:

Application: XXX.exe
Framework Version: v4.0.30319
Description: The process was terminated due to an unhandled exception.
Exception Info: System.IO.IOException
   at System.IO.__Error.WinIOError(Int32, System.String)
   at System.IO.FileStream.Init(System.String, System.IO.FileMode, System.IO.FileAccess, Int32, Boolean, System.IO.FileShare, Int32, System.IO.FileOptions, SECURITY_ATTRIBUTES, System.String, Boolean, Boolean, Boolean)
   at System.IO.FileStream..ctor(System.String, System.IO.FileMode, System.IO.FileAccess, System.IO.FileShare, Int32, System.IO.FileOptions, System.String, Boolean, Boolean, Boolean)
   at System.IO.StreamWriter.CreateFile(System.String, Boolean, Boolean)
   at System.IO.StreamWriter..ctor(System.String, Boolean, System.Text.Encoding, Int32, Boolean)
   at System.IO.StreamWriter..ctor(System.String, Boolean, System.Text.Encoding)
   at System.IO.File.InternalAppendAllText(System.String, System.String, System.Text.Encoding)
   at Serilog.Debugging.SelfLog.WriteLine(System.String, System.Object, System.Object, System.Object)
   at Serilog.Sinks.PeriodicBatching.PeriodicBatchingSink+<OnTick>d__16.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(System.Threading.Tasks.Task)
   at Serilog.Sinks.PeriodicBatching.PortableTimer+<OnTick>d__8.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean)
   at System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean)
   at System.Threading.QueueUserWorkItemCallback.System.Threading.IThreadPoolWorkItem.ExecuteWorkItem()
   at System.Threading.ThreadPoolWorkQueue.Dispatch()

我不知道会发生什么。我有 .Net Framework 4.6.1,Serilog 版本 2.9.0,我无法再次产生错误。

请问您能帮我描述一下错误吗?为什么我收到错误?您知道此错误的解决方案吗?

我使用以下库:

  • Serilog v2.9.0
  • Serilog.Enrichers.Context v2.4.0
  • Serilog.Extensions.Logging v2.0.4
  • Serilog.Settings.AppSettings v2.2.2
  • Serilog.Sinks.Console v3.1.1
  • Serilog.Sinks.File v4.1.0
  • Serilog.Sinks.Http v5.2.1
  • Serilog.Sinks.PeriodicBatching v2.2.0
  • Serilog.Sinks.RollingFile v3.3.0
  • Microsoft.Extensions.Logging.Abstractions v1.0.0

编辑: 我的应用程序配置在这里:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <appSettings>
    <add key="serilog:minimum-level" value="Verbose" />
    <add key="serilog:using:Console" value="Serilog.Sinks.Console" />
    <add key="serilog:write-to:Console" />
    <add key="serilog:using:Http" value="Serilog.Sinks.Http" />
    <add key="serilog:write-to:Http.requestUri" value="http://log.XXX.com:8080/TestEngine" />
    <add key="serilog:write-to:Http.batchPostingLimit" value="1" />
    <add key="serilog:write-to:Http.batchFormatter" value="Serilog.Sinks.Http.BatchFormatters.ArrayBatchFormatter, Serilog.Sinks.Http" />
    <add key="serilog:enrich:with-property:application" value="TestEngine" />
  </appSettings>
    <startup> 
    ...

此处集成 Serilog:

var config = new LoggerConfiguration()
    .Enrich.FromLogContext()
    .Enrich.WithMachineName()
    .Enrich.WithUserName()
    .ReadFrom.AppSettings();

if (CustomLogContext == null)
{
   CustomLogContext = new Dictionary<string, object>();
}

foreach (var logContext in CustomLogContext)
{
   config.Enrich.WithProperty(logContext.Key, logContext.Value);
}

if (!string.IsNullOrEmpty(CustomLogFileFullName))
{
   config = config.WriteTo.File($"{CustomLogFileFullName}");
}

Serilog.Log.Logger = config.CreateLogger();

Serilog.Debugging.SelfLog.Enable(msg => File.AppendAllText("internallog.log", msg, Encoding.UTF8));

ILoggerProvider loggerProvider = new SerilogLoggerProvider(Serilog.Log.Logger);

_logger = loggerProvider.CreateLogger("XXX.Logging.Serilog");

解决方案: 正如 @RubenBartelink 所说,如果您使用 Selflog 但使用自定义日志文件,那么您会承担一些风险。因为Serilog可能不会写自定义文件并且可能被Serilog抛出IO异常。这个问题不属于Serilog。问题实际上是File.AppendAlltext操作。解决办法如下:

Serilog.Debugging.SelfLog.Enable(msg => 
{
    try
    {
        File.AppendAllText("internallog.log", msg, Encoding.UTF8);
    }
    catch (Exception ex)
    {
        Console.WriteLine(ex.ToString());
    }
});

最佳答案

正如 @Daniel A. White 的评论中提到的,您正在做一件危险的事情 - 尝试在“如果一切都失败”的基础上提供的处理程序中写入文件。一些例子:

  • 如果磁盘已满并且文件记录器无法写入(文件接收器不一定会这样做,但如果它们想要通信失败,则可以通过SelfLog)
  • 如果消息字符串格式错误(Serilog 日志记录调用永远不会抛出异常;这是基于 wiki 中关于日志记录不够重要而无法阻止正在运行的应用程序运行的基本原则)

Serilog debugging and diagnostics Wiki page当前显示了写入文件的示例,这根本不是合约的本质——它不能失败。

因此,如果您确实想将 SelfLog 发送到文件,则需要添加 try/catch 并吞下处理程序中的异常。

我想说,当文件接收器是您的主要输出时,将文件作为备份的值(value)相当值得怀疑。情况更是如此,因为您没有任何机制来确保它被修剪(想象一下您有一个带有格式错误的消息字符串的紧密循环日志记录 - 它最终会填满您的磁盘)。

我个人已经通过将SelfLog回显到我的Console Sink(根据上面的记录不会抛出异常)来处理这种权衡,基于操作环境(想想 Kubernetes)可以信任捕获它,或者发出警报。

关于c# - 为什么在使用 Serilog 日志记录时会出现 Serilog SelfLog 错误?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/71223500/

相关文章:

c# - 枚举列表 <Object> (Id, Name)

c# - 类实例是引用类型,结构是值类型 C#。它是否也适用于 C++

c# - 是否有任何 SQL Server Serilog 接收器支持 .Net Core

c# - Serilog的ReadFrom.KeyValuePairs方法如何使用?

java - 运行 JGraphX Hello World 示例的错误消息

c# - 在 MVC View 中为 HTML DropDownList 创建标签和值

c# - 当用户单击表头时,如何对 List<T> 进行排序?

c# - 如何使用 Serilog 以有效的 json 格式记录复杂对象?

Scala 在不同的工作目录上运行进程

java - 分析从 Java 文件中读取的文本