/* * Copyright Andrey Semashev 2007 - 2015. * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at * http://www.boost.org/LICENSE_1_0.txt) */ /*! * \file exception_handler_feature.hpp * \author Andrey Semashev * \date 17.07.2009 * * The header contains implementation of an exception handler support feature. */ #ifndef BOOST_LOG_SOURCES_EXCEPTION_HANDLER_FEATURE_HPP_INCLUDED_ #define BOOST_LOG_SOURCES_EXCEPTION_HANDLER_FEATURE_HPP_INCLUDED_ #include #include #include #include #include #include #include #include #include #include #if !defined(BOOST_LOG_NO_THREADS) #include #endif #include #ifdef BOOST_HAS_PRAGMA_ONCE #pragma once #endif namespace boost { BOOST_LOG_OPEN_NAMESPACE namespace sources { /*! * \brief Exception handler feature implementation */ template< typename BaseT > class basic_exception_handler_logger : public BaseT { //! Base type typedef BaseT base_type; typedef basic_exception_handler_logger this_type; BOOST_COPYABLE_AND_MOVABLE_ALT(this_type) public: //! Threading model being used typedef typename base_type::threading_model threading_model; //! Final logger type typedef typename base_type::final_type final_type; //! Exception handler function type typedef boost::log::aux::light_function< void () > exception_handler_type; #if defined(BOOST_LOG_DOXYGEN_PASS) //! Lock requirement for the open_record_unlocked method typedef typename strictest_lock< typename base_type::open_record_lock, no_lock< threading_model > >::type open_record_lock; //! Lock requirement for the push_record_unlocked method typedef typename strictest_lock< typename base_type::push_record_lock, no_lock< threading_model > >::type push_record_lock; #endif // defined(BOOST_LOG_DOXYGEN_PASS) //! Lock requirement for the swap_unlocked method typedef typename strictest_lock< typename base_type::swap_lock, #ifndef BOOST_LOG_NO_THREADS boost::log::aux::exclusive_lock_guard< threading_model > #else no_lock< threading_model > #endif // !defined(BOOST_LOG_NO_THREADS) >::type swap_lock; private: //! Exception handler exception_handler_type m_ExceptionHandler; public: /*! * Default constructor. The constructed logger does not have an exception handler. */ basic_exception_handler_logger() : base_type() { } /*! * Copy constructor */ basic_exception_handler_logger(basic_exception_handler_logger const& that) : base_type(static_cast< base_type const& >(that)), m_ExceptionHandler(that.m_ExceptionHandler) { } /*! * Move constructor */ basic_exception_handler_logger(BOOST_RV_REF(basic_exception_handler_logger) that) : base_type(boost::move(static_cast< base_type& >(that))), m_ExceptionHandler(boost::move(that.m_ExceptionHandler)) { } /*! * Constructor with arguments. Passes arguments to other features. */ template< typename ArgsT > explicit basic_exception_handler_logger(ArgsT const& args) : base_type(args) { } /*! * The method sets exception handler function. The function will be called with no arguments * in case if an exception occurs during either \c open_record or \c push_record method * execution. Since exception handler is called from a \c catch statement, the exception * can be rethrown in order to determine its type. * * By default no handler is installed, thus any exception is propagated as usual. * * \sa utility/exception_handler.hpp * \param handler Exception handling function * * \note The exception handler can be invoked in several threads concurrently. * * \note Thread interruptions are not affected by exception handlers. */ template< typename HandlerT > void set_exception_handler(HandlerT const& handler) { #ifndef BOOST_LOG_NO_THREADS boost::log::aux::exclusive_lock_guard< threading_model > lock(this->get_threading_model()); #endif m_ExceptionHandler = handler; } protected: /*! * Unlocked \c open_record */ template< typename ArgsT > record open_record_unlocked(ArgsT const& args) { try { return base_type::open_record_unlocked(args); } #ifndef BOOST_LOG_NO_THREADS catch (thread_interrupted&) { throw; } #endif catch (...) { handle_exception(); return record(); } } /*! * Unlocked \c push_record */ void push_record_unlocked(BOOST_RV_REF(record) rec) { try { base_type::push_record_unlocked(boost::move(rec)); } #ifndef BOOST_LOG_NO_THREADS catch (thread_interrupted&) { throw; } #endif catch (...) { handle_exception(); } } /*! * Unlocked swap */ void swap_unlocked(basic_exception_handler_logger& that) { base_type::swap_unlocked(static_cast< base_type& >(that)); m_ExceptionHandler.swap(that.m_ExceptionHandler); } private: #if !defined(BOOST_LOG_DOXYGEN_PASS) //! The function handles the intercepted exception void handle_exception() { #ifndef BOOST_LOG_NO_THREADS // Here's the trick with the lock type. Since the lock // is only needed when an exception is caught, we indicate // no locking requirements in the push_record_lock type. // However, if other features don't require locking either, // we shall acquire a read lock here, when an exception is caught. // If other features do require locking, the thread model is // already locked by now, and we don't do locking at all. typedef typename mpl::if_< is_same< no_lock< threading_model >, typename final_type::push_record_lock >, boost::log::aux::shared_lock_guard< threading_model >, no_lock< threading_model > >::type lock_type; lock_type lock(base_type::get_threading_model()); #endif // !defined(BOOST_LOG_NO_THREADS) if (m_ExceptionHandler.empty()) throw; m_ExceptionHandler(); } #endif // !defined(BOOST_LOG_DOXYGEN_PASS) }; /*! * \brief Exception handler support feature * * The logger with this feature will provide an additional method to * install an exception handler functional object. This functional * object will be called if during either opening or pushing a record * an exception is thrown from the logging core. */ struct exception_handler { template< typename BaseT > struct apply { typedef basic_exception_handler_logger< BaseT > type; }; }; } // namespace sources BOOST_LOG_CLOSE_NAMESPACE // namespace log } // namespace boost #include #endif // BOOST_LOG_SOURCES_EXCEPTION_HANDLER_FEATURE_HPP_INCLUDED_