2

我在使用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());
    }
});
4

1 回答 1

2

正如@Daniel A. White 的评论中提到的那样,您正在做一件有风险的事情——尝试在“如果所有其他方法都失败”的基础上提供的处理程序中写入文件。一些例子:

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

虽然Serilog 调试和诊断 Wiki 页面当前显示了写入文件的示例,但这根本不是合同的本质——它不能失败。

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

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

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

于 2022-02-23T10:18:18.737 回答