Chris@16: /* Chris@101: * Copyright Andrey Semashev 2007 - 2015. Chris@16: * Distributed under the Boost Software License, Version 1.0. Chris@16: * (See accompanying file LICENSE_1_0.txt or copy at Chris@16: * http://www.boost.org/LICENSE_1_0.txt) Chris@16: */ Chris@16: /*! Chris@16: * \file global_logger_storage.hpp Chris@16: * \author Andrey Semashev Chris@16: * \date 21.04.2008 Chris@16: * Chris@16: * The header contains implementation of facilities to declare global loggers. Chris@16: */ Chris@16: Chris@16: #ifndef BOOST_LOG_SOURCES_GLOBAL_LOGGER_STORAGE_HPP_INCLUDED_ Chris@16: #define BOOST_LOG_SOURCES_GLOBAL_LOGGER_STORAGE_HPP_INCLUDED_ Chris@16: Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: Chris@16: #ifdef BOOST_HAS_PRAGMA_ONCE Chris@16: #pragma once Chris@16: #endif Chris@16: Chris@16: namespace boost { Chris@16: Chris@16: BOOST_LOG_OPEN_NAMESPACE Chris@16: Chris@16: namespace sources { Chris@16: Chris@16: namespace aux { Chris@16: Chris@16: //! The base class for logger holders Chris@16: struct BOOST_LOG_NO_VTABLE BOOST_SYMBOL_VISIBLE logger_holder_base Chris@16: { Chris@16: //! The source file name where the logger was registered Chris@16: const char* m_RegistrationFile; Chris@16: //! The line number where the logger was registered Chris@16: unsigned int m_RegistrationLine; Chris@16: Chris@16: logger_holder_base(const char* file, unsigned int line) : Chris@16: m_RegistrationFile(file), Chris@16: m_RegistrationLine(line) Chris@16: { Chris@16: } Chris@16: virtual ~logger_holder_base() {} Chris@16: virtual std::type_info const& logger_type() const = 0; Chris@16: }; Chris@16: Chris@16: //! The actual logger holder class Chris@16: template< typename LoggerT > Chris@16: struct BOOST_SYMBOL_VISIBLE logger_holder : Chris@16: public logger_holder_base Chris@16: { Chris@16: //! The logger instance Chris@16: LoggerT m_Logger; Chris@16: Chris@16: logger_holder(const char* file, unsigned int line, LoggerT const& logger) : Chris@16: logger_holder_base(file, line), Chris@16: m_Logger(logger) Chris@16: { Chris@16: } Chris@16: std::type_info const& logger_type() const { return typeid(LoggerT); } Chris@16: }; Chris@16: Chris@16: //! The class implements a global repository of tagged loggers Chris@16: struct global_storage Chris@16: { Chris@16: typedef shared_ptr< logger_holder_base >(*initializer_t)(); Chris@16: Chris@16: //! Finds or creates the logger and returns its holder Chris@16: BOOST_LOG_API static shared_ptr< logger_holder_base > get_or_init(std::type_info const& key, initializer_t initializer); Chris@16: Chris@16: // Non-constructible, non-copyable, non-assignable Chris@16: BOOST_DELETED_FUNCTION(global_storage()) Chris@16: BOOST_DELETED_FUNCTION(global_storage(global_storage const&)) Chris@16: BOOST_DELETED_FUNCTION(global_storage& operator= (global_storage const&)) Chris@16: }; Chris@16: Chris@16: //! Throws the \c odr_violation exception Chris@16: BOOST_LOG_API BOOST_LOG_NORETURN void throw_odr_violation( Chris@16: std::type_info const& tag_type, Chris@16: std::type_info const& logger_type, Chris@16: logger_holder_base const& registered); Chris@16: Chris@16: //! The class implements a logger singleton Chris@16: template< typename TagT > Chris@16: struct logger_singleton : Chris@16: public boost::log::aux::lazy_singleton< Chris@16: logger_singleton< TagT >, Chris@16: shared_ptr< logger_holder< typename TagT::logger_type > > Chris@16: > Chris@16: { Chris@16: //! Base type Chris@16: typedef boost::log::aux::lazy_singleton< Chris@16: logger_singleton< TagT >, Chris@16: shared_ptr< logger_holder< typename TagT::logger_type > > Chris@16: > base_type; Chris@16: //! Logger type Chris@16: typedef typename TagT::logger_type logger_type; Chris@16: Chris@16: //! Returns the logger instance Chris@16: static logger_type& get() Chris@16: { Chris@16: return base_type::get()->m_Logger; Chris@16: } Chris@16: Chris@16: //! Initializes the logger instance (called only once) Chris@16: static void init_instance() Chris@16: { Chris@16: shared_ptr< logger_holder< logger_type > >& instance = base_type::get_instance(); Chris@16: shared_ptr< logger_holder_base > holder = global_storage::get_or_init( Chris@16: typeid(boost::log::aux::visible_type< TagT >), Chris@16: &logger_singleton::construct_logger); Chris@16: instance = boost::dynamic_pointer_cast< logger_holder< logger_type > >(holder); Chris@16: if (!instance) Chris@16: { Chris@16: // In pure C++ this should never happen, since there cannot be two Chris@16: // different tag types that have equal type_infos. In real life it can Chris@16: // happen if the same-named tag is defined differently in two or more Chris@16: // dlls. This check is intended to detect such ODR violations. However, there Chris@16: // is no protection against different definitions of the logger type itself. Chris@16: throw_odr_violation(typeid(TagT), typeid(logger_type), *holder); Chris@16: } Chris@16: } Chris@16: Chris@16: private: Chris@16: //! Constructs a logger holder Chris@16: static shared_ptr< logger_holder_base > construct_logger() Chris@16: { Chris@16: return boost::make_shared< logger_holder< logger_type > >( Chris@16: TagT::registration_file(), Chris@16: static_cast< unsigned int >(TagT::registration_line), Chris@16: TagT::construct_logger()); Chris@16: } Chris@16: }; Chris@16: Chris@16: } // namespace aux Chris@16: Chris@16: //! The macro forward-declares a global logger with a custom initialization Chris@16: #define BOOST_LOG_GLOBAL_LOGGER(tag_name, logger)\ Chris@16: struct tag_name\ Chris@16: {\ Chris@16: typedef logger logger_type;\ Chris@16: enum registration_line_t { registration_line = __LINE__ };\ Chris@16: static const char* registration_file() { return __FILE__; }\ Chris@16: static logger_type construct_logger();\ Chris@16: static inline logger_type& get()\ Chris@16: {\ Chris@16: return ::boost::log::sources::aux::logger_singleton< tag_name >::get();\ Chris@16: }\ Chris@16: }; Chris@16: Chris@16: //! The macro defines a global logger initialization routine Chris@16: #define BOOST_LOG_GLOBAL_LOGGER_INIT(tag_name, logger)\ Chris@16: tag_name::logger_type tag_name::construct_logger() Chris@16: Chris@16: //! The macro defines a global logger initializer that will default-construct the logger Chris@16: #define BOOST_LOG_GLOBAL_LOGGER_DEFAULT(tag_name, logger)\ Chris@16: BOOST_LOG_GLOBAL_LOGGER_INIT(tag_name, logger)\ Chris@16: {\ Chris@16: return logger_type();\ Chris@16: } Chris@16: Chris@16: //! The macro defines a global logger initializer that will construct the logger with the specified constructor arguments Chris@16: #define BOOST_LOG_GLOBAL_LOGGER_CTOR_ARGS(tag_name, logger, args)\ Chris@16: BOOST_LOG_GLOBAL_LOGGER_INIT(tag_name, logger)\ Chris@16: {\ Chris@16: return logger_type(BOOST_PP_SEQ_ENUM(args));\ Chris@16: } Chris@16: Chris@16: //! The macro declares a global logger with a custom initialization Chris@16: #define BOOST_LOG_INLINE_GLOBAL_LOGGER_INIT(tag_name, logger)\ Chris@16: BOOST_LOG_GLOBAL_LOGGER(tag_name, logger)\ Chris@16: inline BOOST_LOG_GLOBAL_LOGGER_INIT(tag_name, logger) Chris@16: Chris@16: //! The macro declares a global logger that will be default-constructed Chris@16: #define BOOST_LOG_INLINE_GLOBAL_LOGGER_DEFAULT(tag_name, logger)\ Chris@16: BOOST_LOG_INLINE_GLOBAL_LOGGER_INIT(tag_name, logger)\ Chris@16: {\ Chris@16: return logger_type();\ Chris@16: } Chris@16: Chris@16: //! The macro declares a global logger that will be constructed with the specified arguments Chris@16: #define BOOST_LOG_INLINE_GLOBAL_LOGGER_CTOR_ARGS(tag_name, logger, args)\ Chris@16: BOOST_LOG_INLINE_GLOBAL_LOGGER_INIT(tag_name, logger)\ Chris@16: {\ Chris@16: return logger_type(BOOST_PP_SEQ_ENUM(args));\ Chris@16: } Chris@16: Chris@16: } // namespace sources Chris@16: Chris@16: BOOST_LOG_CLOSE_NAMESPACE // namespace log Chris@16: Chris@16: } // namespace boost Chris@16: Chris@16: #include Chris@16: Chris@16: #endif // BOOST_LOG_SOURCES_GLOBAL_LOGGER_STORAGE_HPP_INCLUDED_