一个应该如何当一个异常被触发日志?(How should one log when an excep

2019-07-22 00:53发布

在节目我最近写了,我想登录时,我的“商业逻辑”代码触发第三方或项目的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 */
}

总之,如果发生异常,创建一个包罗万象的条款,记录错误,并重新抛出。 在我的心目中,这是安全的。 我知道一般捕获所有被认为是不好的,因为一个没有到异常的引用都得到任何有用的信息。 不过,我只是要重新把它,所以没有什么损失。

现在,对自己还不错,但一些其他的程序员修改了此方案,并结束了违反以上。 具体来说,他们把一个巨大的代码量进入试块在一种情况下,而在另一个去除“扔”,并放置在“回归”。

我现在我的解决办法是脆看; 它不是未来的修改防。

我希望有一个更好的解决方案,没有这些问题。

我有没有上述问题的另一种可能的解决方案,但我不知道别人怎么想的吧。 它采用RAII,特别是隐含触发如果“作用域退出”对象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 */
}

我想知道:

  • 技术上,将这项工作有力? 最初,它似乎工作,但我知道有关于使用一些需要注意std::uncaught_exception
  • 有另一种方式来完成我想要什么?

:我已经更新了这个问题。 具体来说,我有:

  • 添加的try / catch ,最初失踪,周围的log函数调用。
  • 添加跟踪std::uncaught_exception施工状态。 这可以防止其中被触发的异常堆栈回卷的一部分,另一析构函数的一个“尝试”块内创建该对象的情况。
  • 固定新的“potential_function”创建一个名为对象,而不是临时对象如前。

Answer 1:

我对你的方法没有任何评论,但似乎有趣! 我有另一种方式,也可能会为你想要的东西的工作,并可能有点更通用。 它需要从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;
    }
}

你使用它(在简单的情况下)的方法是这样的:

try_and_log ("An exception was thrown here...", [&] {
    this_is_the_code ();
    you_want_executed ();
    and_its_exceptions_logged ();
});

正如我以前说过,我不知道它如何对自己的解决方案。 注意lambda是捕捉一切从封闭的范围,这是相当方便。 另外请注意,我还没有真正尝试这一点,所以编译错误,逻辑问题和/或核战争可能会从这个结果。

我在这里看到的问题是,它是不容易的包装成一个宏这一点,并期待你的同事写的[=] {}正确的部件和所有的时间可能是太多了!

对于包装和白痴打样的目的,你可能需要两个宏:一个TRY_AND_LOG_BEGIN发出第一线,直到为拉姆达和左括号TRY_AND_LOG_END发出结束的括号和括号。 像这样:

#define TRY_AND_LOG_BEGIN(message)  try_and_log (message, [&] {
#define TRY_AND_LOG_END()           })

而你使用它们像这样:

TRY_AND_LOG_BEGIN ("Exception happened!")  // No semicolons here!
    whatever_code_you_want ();
TRY_AND_LOG_END ();

这是 - 这取决于你的观点 - 要么是净收益或净亏损! (我个人比较喜欢简单的函数调用和lambda语法,这给了我更多的控制和透明度。

另外,也可以在码块的末尾写入日志消息; 只是切换的两个参数try_and_log功能。



文章来源: How should one log when an exception is triggered?