blob: bd77fca5285bf36b0432af8889c3dd4072a022a5 [file] [log] [blame]
/*
* 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 <boost/mpl/if.hpp>
#include <boost/move/core.hpp>
#include <boost/move/utility.hpp>
#include <boost/type_traits/is_same.hpp>
#include <boost/log/detail/config.hpp>
#include <boost/log/detail/light_function.hpp>
#include <boost/log/detail/locks.hpp>
#include <boost/log/core/record.hpp>
#include <boost/log/sources/threading_models.hpp>
#include <boost/log/utility/strictest_lock.hpp>
#if !defined(BOOST_LOG_NO_THREADS)
#include <boost/thread/exceptions.hpp>
#endif
#include <boost/log/detail/header.hpp>
#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 <tt>utility/exception_handler.hpp</tt>
* \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 <boost/log/detail/footer.hpp>
#endif // BOOST_LOG_SOURCES_EXCEPTION_HANDLER_FEATURE_HPP_INCLUDED_