C# 斯蒂芬·克利里';s关于异步的新日志记录模式问题
一旦我测试过斯蒂芬·克利里的新手机,我就喜欢它了。然而,有一点我不明白: 不幸的是,这里的解决方案不能很好地处理异步代码。这是因为异步将导致捕获异常,然后在等待时重新抛出。因此,异常过滤器在等待点运行,而不是在异常最初抛出的位置 我想举一个这样的例子,因为我的代码在C# 斯蒂芬·克利里';s关于异步的新日志记录模式问题,c#,C#,一旦我测试过斯蒂芬·克利里的新手机,我就喜欢它了。然而,有一点我不明白: 不幸的是,这里的解决方案不能很好地处理异步代码。这是因为异步将导致捕获异常,然后在等待时重新抛出。因此,异常过滤器在等待点运行,而不是在异常最初抛出的位置 我想举一个这样的例子,因为我的代码在Handle(…)/hisTrue(…)和nothrow中似乎运行良好 我故意让SubscribeAsync抛出一个异常 公共异步任务StartAsync(CancellationToken CancellationToken) {
Handle(…)
/hisTrue(…)
和nothrow中似乎运行良好代码>
我故意让SubscribeAsync抛出一个异常
公共异步任务StartAsync(CancellationToken CancellationToken)
{
尝试
{
wait SubscribeAsync().configurewait(false);
}
当(句柄(()=>_logger.LogError(例如,“意外错误”)时捕获(异常)
{
}
}
公共静态类ExceptionFilterUtility
{
公共静态布尔句柄(操作)
{
动作();
返回true;
}
公共静态布尔传播(操作)
{
动作();
返回false;
}
}
我的目标是:
[2021-03-13 20:16:32 Error] ElonMuskBot.Core.TradeManagers.LiveTradeManager
Unexpected error.
ElonMuskBot.Core.Exceptions.RequestFailedException: Error while subscribing to the Spot candlestick update stream
at ElonMuskBot.Core.Clients.SpotBotClient.SubscribeToCandleUpdatesAsync(String symbol, KlineInterval timeInterval, Action`1 onMessage) in E:\GitHub\elonmuskbot\src\ElonMuskBot.Core\Clients\SpotBotClient.cs:line 88
at ElonMuskBot.Core.TradeManagers.LiveTradeManager.SubscribeAsync() in E:\GitHub\elonmuskbot\src\ElonMuskBot.Core\TradeManagers\LiveTradeManager.cs:line 54
at ElonMuskBot.Core.TradeManagers.LiveTradeManager.StartAsync(CancellationToken cancellationToken) in E:\GitHub\elonmuskbot\src\ElonMuskBot.Core\TradeManagers\LiveTradeManager.cs:line 38
我想举一个这样的例子,因为我的代码在Handle(…)/histtrue(…)和no-throw;方面似乎运行良好
该模式的要点是在抛出点捕获日志范围。无论哪种方式,异常处理本身都可以正常工作,但捕获的作用域是不同的
同步代码的日志范围被正确捕获,因为异常过滤器实际上是在抛出点执行的。因此,异常记录在抛出
,包括存在的所有日志作用域
但是,对于异步代码,它不能正常工作。异常将被很好地记录,但记录范围将不存在。这是因为异常过滤器在等待
点执行,而不是在抛出
点执行
下面是一个无法正确捕获异常日志记录范围的示例:
public async Task SubscribeAsync()
{
using var _ = _logger.BeginScope("This will not be logged");
await Task.Yield();
throw new InvalidOperationException("This will be logged");
}
自从写了那篇博文之后,我已经开发出了一个更好的解决方案,它可以同时处理同步和异步异常以及异常。我还没来得及写一篇新的博文(对不起!),但一旦我写了,我会把旧的解决方案指向新的解决方案
较新的解决方案仅为.NET Core,因为它与ILogger
相关联。用法示例:
// Don't forget to call IServiceCollection.AddExceptionLoggingScopes() in your startup.
public async Task StartAsync(CancellationToken cancellationToken)
{
try
{
await SubscribeAsync().ConfigureAwait(false);
}
catch (Exception ex)
{
using (_logger.BeginCapturedExceptionLoggingScopes(ex))
_logger.LogError(ex, "Unexpected error.");
}
}
你声称“没问题”的结果是…@CaiusJard,我不明白你的意思。你的异常的堆栈跟踪是什么?@CaiusJard,这是正确的。就在那里。我从来没有见过这么严格的字符限制,但考虑到你在截图中只显示了大约6行,你显然掌握了“什么是证明这一点所需的合理数据量”,所以在将文本编辑到问题中时,请随意使用相同的判断谢谢你的回答!我看到了其他选择:。我实际上在用Serilog。哪一个更好?我肯定会用Serilog的。因为您可以在启动时设置它,然后不必麻烦使用BeginCaptureXceptionLoggingScopes
BeginCaptureXceptionLoggingScopes
之所以存在,是因为Microsoft依赖项注入库的功能不够强大,无法扩展记录器以自动执行此操作。Serilog库直接扩展Serilog记录器,因此它没有相同的限制,因此其API更易于使用(无需BeginCaptureDeceptionLoggingScopes
必要)。非常感谢您的解释!