为什么在使用 Serilog 日志记录时会出现 Serilog SelfLog 错误?
我在使用 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());
}
});
I have an interesting error while using Serilog SelfLog. The error is:
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()
I do not have an idea what happens. I have .Net framework 4.6.1, Serilog version 2.9.0 and I cannot produce the error again.
Please Can you help me to describe the error? Why did I get the error? Do you know any solutions for this error?
I use libraries below:
- 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
EDIT:
My app conf here:
<?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 integration here:
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(quot;{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");
SOLUTION:
As @RubenBartelink says, if you use Selflog but you use custom log files, you take a few risks. Because Serilog may not write a custom file and may be Serilog throw an IO exception. This problem does not belong to Serilog. The problem is actually File.AppendAlltext operation. The solution is as follows:
Serilog.Debugging.SelfLog.Enable(msg =>
{
try
{
File.AppendAllText("internallog.log", msg, Encoding.UTF8);
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
});
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
正如 @Daniel A. White 的评论中提到的,您正在做一件危险的事情 - 尝试在“如果一切都失败”的基础上提供的处理程序中写入文件。一些示例:
SelfLog
)而 Serilog 调试和诊断 Wiki 页面 当前显示了写入文件的示例,这根本不是合同的本质——它不能失败。
因此,如果您确实想将
SelfLog
发送到文件,则需要添加try
/catch
并吞下异常处理程序。我想说,当文件接收器是您的主要输出时,将文件作为备份的价值相当值得怀疑。情况更是如此,因为您没有任何机制来确保它被修剪(想象一下您有一个带有格式错误的消息字符串的紧密循环日志记录 - 它最终会填满您的磁盘)。
我个人已经通过将
SelfLog
回显到我的Console
Sink(根据上面的内容,日志记录不会抛出异常)来处理这种权衡,基于操作环境(想想 Kubernetes) )可以信任捕获它,或发出警报。As alluded to in the comment from @Daniel A. White, you are doing a risky thing -- trying to write to a file, in a handler that's provided on an "if all else fails" basis. Some examples:
SelfLog
)While the Serilog debugging and diagnostics Wiki page currently shows an example of writing to a file, that's simply not the nature of the contract -- it must not fail.
Hence, if you actually want to emit the
SelfLog
to a file, you will need to add atry
/catch
and swallow the exception in the handler.I would say its pretty questionable value to have a file as a backup when the File Sink is your primary output. This is doubly the case as you don't have any mechanism to ensure it gets trimmed (imagine you had a tight loop logging with a malformed message string - it would fill your disk eventually).
I personally have handled this tradeoff by echoing the
SelfLog
to myConsole
Sink (which logging won't throw, per the above) on the basis that the operating environment (think Kubernetes) can be trusted to capture it, or alert.