Cha*_*cox 7 c++ logging exception raii
在我最近写的一个程序中,我希望在我的"业务逻辑"代码在第三方或项目API中触发异常时进行记录.(为了澄清,我想在使用API导致异常时进行记录.这可能比实际高出许多帧throw
,并且可能比实际低很多帧catch
(可以发生异常有效负载的记录).)我做了以下:
void former_function()
{
/* some code here */
try
{
/* some specific code that I know may throw, and want to log about */
}
catch( ... )
{
log( "an exception occurred when doing something with some other data" );
throw;
}
/* some code here */
}
Run Code Online (Sandbox Code Playgroud)
简而言之,如果发生异常,请创建一个catch-all子句,记录错误并重新抛出.在我看来,这是安全的.我知道一般来说,catch-all被认为是错误的,因为根本没有对异常的引用来获取任何有用的信息.但是,我只是要重新抛出它,所以什么都不会丢失.
现在,它本身很好,但其他一些程序员修改了这个程序,最终违反了上述规定.具体来说,他们在一个案例中将大量代码放入try-block,在另一个案例中删除了'throw'并放置了'return'.
我现在看到我的解决方案很脆弱; 这不是未来修改的证据.
我想要一个没有这些问题的更好的解决方案.
我有另一个没有上述问题的潜在解决方案,但我想知道别人怎么想.它使用RAII,特别是一个"Scoped Exit"对象,如果在构造时std::uncaught_exception
不是真的则隐式触发,但在破坏时是真的:
#include <ciso646> // not, and
#include <exception> // uncaught_exception
class ExceptionTriggeredLog
{
private:
std::string const m_log_message;
bool const m_was_uncaught_exception;
public:
ExceptionTriggeredLog( std::string const& r_log_message )
: m_log_message( r_log_message ),
m_was_uncaught_exception( std::uncaught_exception() )
{
}
~ExceptionTriggeredLog()
{
if( not m_was_uncaught_exception
and std::uncaught_exception() )
{
try
{
log( m_log_message );
}
catch( ... )
{
// no exceptions can leave an destructor.
// especially when std::uncaught_exception is true.
}
}
}
};
void potential_function()
{
/* some code here */
{
ExceptionTriggeredLog exception_triggered_log( "an exception occurred when doing something with some other data" );
/* some specific code that I know may throw, and want to log about */
}
/* some code here */
}
Run Code Online (Sandbox Code Playgroud)
我想知道:
std::uncaught_exception
.注意:我已经更新了这个问题.具体来说,我:
try
/ .catch
log
std::uncaught_exception
建设状态.这样可以防止在另一个析构函数的"try"块中创建此对象,该析构函数作为异常堆栈展开的一部分触发.我对你的方法没有评论,但看起来很有趣!我有另一种方法,可能也适合你想要的,并且可能更通用一些。不过,它需要 C++11 中的 lambda,这对于您的情况可能是问题,也可能不是问题。
这是一个简单的函数模板,它接受 lambda、运行它并捕获、记录并重新抛出所有异常:
template <typename F>
void try_and_log (char const * log_message, F code_block)
{
try {
code_block ();
} catch (...) {
log (log_message);
throw;
}
}
Run Code Online (Sandbox Code Playgroud)
使用它的方式(最简单的情况)是这样的:
try_and_log ("An exception was thrown here...", [&] {
this_is_the_code ();
you_want_executed ();
and_its_exceptions_logged ();
});
Run Code Online (Sandbox Code Playgroud)
正如我之前所说,我不知道它与您自己的解决方案有何不同。请注意,lambda 正在捕获其封闭范围中的所有内容,这非常方便。另请注意,我实际上并没有尝试过此操作,因此可能会导致编译错误、逻辑问题和/或核战争。
我在这里看到的问题是,将其包装到宏中并不容易,并且期望您的同事始终正确编写[=] {
和}
部分可能太过分了!
出于包装和防白痴的目的,您可能需要两个宏: aTRY_AND_LOG_BEGIN
发出第一行,直到 lambda 的左大括号; anTRY_AND_LOG_END
发出右大括号和括号。就像这样:
#define TRY_AND_LOG_BEGIN(message) try_and_log (message, [&] {
#define TRY_AND_LOG_END() })
Run Code Online (Sandbox Code Playgroud)
你像这样使用它们:
TRY_AND_LOG_BEGIN ("Exception happened!") // No semicolons here!
whatever_code_you_want ();
TRY_AND_LOG_END ();
Run Code Online (Sandbox Code Playgroud)
这取决于您的观点,要么是净收益,要么是净损失!(我个人更喜欢简单的函数调用和 lambda 语法,这给了我更多的控制力和透明度。
此外,还可以将日志消息写入代码块的末尾;只需切换函数的两个参数即可try_and_log
。
归档时间: |
|
查看次数: |
470 次 |
最近记录: |