1 /* 2 * Copyright Andrey Semashev 2007 - 2015. 3 * Distributed under the Boost Software License, Version 1.0. 4 * (See accompanying file LICENSE_1_0.txt or copy at 5 * http://www.boost.org/LICENSE_1_0.txt) 6 */ 7 /*! 8 * \file global_logger_storage.hpp 9 * \author Andrey Semashev 10 * \date 21.04.2008 11 * 12 * The header contains implementation of facilities to declare global loggers. 13 */ 14 15 #ifndef BOOST_LOG_SOURCES_GLOBAL_LOGGER_STORAGE_HPP_INCLUDED_ 16 #define BOOST_LOG_SOURCES_GLOBAL_LOGGER_STORAGE_HPP_INCLUDED_ 17 18 #include <stdexcept> 19 #include <boost/type_index.hpp> 20 #include <boost/smart_ptr/shared_ptr.hpp> 21 #include <boost/smart_ptr/make_shared_object.hpp> 22 #include <boost/preprocessor/seq/enum.hpp> 23 #include <boost/log/detail/config.hpp> 24 #include <boost/log/detail/singleton.hpp> 25 #include <boost/log/detail/header.hpp> 26 27 #ifdef BOOST_HAS_PRAGMA_ONCE 28 #pragma once 29 #endif 30 31 namespace boost { 32 33 BOOST_LOG_OPEN_NAMESPACE 34 35 namespace sources { 36 37 namespace aux { 38 39 //! The base class for logger holders 40 struct logger_holder_base 41 { 42 //! The source file name where the logger was registered 43 const char* const m_RegistrationFile; 44 //! The line number where the logger was registered 45 const unsigned int m_RegistrationLine; 46 //! Stored logger type 47 const typeindex::type_index m_LoggerType; 48 logger_holder_baseboost::sources::aux::logger_holder_base49 logger_holder_base(const char* file, unsigned int line, typeindex::type_index logger_type) BOOST_NOEXCEPT : 50 m_RegistrationFile(file), 51 m_RegistrationLine(line), 52 m_LoggerType(logger_type) 53 { 54 } 55 }; 56 57 //! The actual logger holder class 58 template< typename LoggerT > 59 struct logger_holder : 60 public logger_holder_base 61 { 62 //! The logger instance 63 LoggerT m_Logger; 64 logger_holderboost::sources::aux::logger_holder65 logger_holder(const char* file, unsigned int line, LoggerT const& logger) : 66 logger_holder_base(file, line, typeindex::type_id< LoggerT >()), 67 m_Logger(logger) 68 { 69 } 70 71 #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) logger_holderboost::sources::aux::logger_holder72 logger_holder(const char* file, unsigned int line, LoggerT&& logger) : 73 logger_holder_base(file, line, typeindex::type_id< LoggerT >()), 74 m_Logger(static_cast< LoggerT&& >(logger)) 75 { 76 } 77 #endif 78 }; 79 80 //! The class implements a global repository of tagged loggers 81 struct global_storage 82 { 83 typedef shared_ptr< logger_holder_base >(*initializer_t)(); 84 85 //! Finds or creates the logger and returns its holder 86 BOOST_LOG_API static shared_ptr< logger_holder_base > get_or_init(typeindex::type_index key, initializer_t initializer); 87 88 // Non-constructible, non-copyable, non-assignable 89 BOOST_DELETED_FUNCTION(global_storage()) 90 BOOST_DELETED_FUNCTION(global_storage(global_storage const&)) 91 BOOST_DELETED_FUNCTION(global_storage& operator= (global_storage const&)) 92 }; 93 94 //! Throws the \c odr_violation exception 95 BOOST_LOG_API BOOST_LOG_NORETURN void throw_odr_violation( 96 typeindex::type_index tag_type, 97 typeindex::type_index logger_type, 98 logger_holder_base const& registered); 99 100 //! The class implements a logger singleton 101 template< typename TagT > 102 struct logger_singleton : 103 public boost::log::aux::lazy_singleton< 104 logger_singleton< TagT >, 105 shared_ptr< logger_holder< typename TagT::logger_type > > 106 > 107 { 108 //! Base type 109 typedef boost::log::aux::lazy_singleton< 110 logger_singleton< TagT >, 111 shared_ptr< logger_holder< typename TagT::logger_type > > 112 > base_type; 113 //! Logger type 114 typedef typename TagT::logger_type logger_type; 115 116 //! Returns the logger instance getboost::sources::aux::logger_singleton117 static logger_type& get() 118 { 119 return base_type::get()->m_Logger; 120 } 121 122 //! Initializes the logger instance (called only once) init_instanceboost::sources::aux::logger_singleton123 static void init_instance() 124 { 125 shared_ptr< logger_holder< logger_type > >& instance = base_type::get_instance(); 126 const typeindex::type_index tag_type_index = typeindex::type_id< TagT >(); 127 shared_ptr< logger_holder_base > holder = global_storage::get_or_init(tag_type_index, &logger_singleton::construct_logger); 128 const typeindex::type_index logger_type_index = typeindex::type_id< logger_type >(); 129 if (holder->m_LoggerType == logger_type_index) 130 { 131 // Note: dynamic_cast may fail here if logger_type is not visible (for example, with Clang on Linux, if the original logger 132 // instance was initialized in a different DSO than where it's being queried). logger_holder visibility doesn't 133 // have effect since it is inhibited by the template parameter visibility. 134 instance = boost::static_pointer_cast< logger_holder< logger_type > >(holder); 135 } 136 else 137 { 138 // In pure C++ this should never happen, since there cannot be two 139 // different tag types that have equal type_infos. In real life it can 140 // happen if the same-named tag is defined differently in two or more 141 // dlls. This check is intended to detect such ODR violations. However, there 142 // is no protection against different definitions of the logger type itself. 143 boost::log::sources::aux::throw_odr_violation(tag_type_index, logger_type_index, *holder); 144 } 145 } 146 147 private: 148 //! Constructs a logger holder construct_loggerboost::sources::aux::logger_singleton149 static shared_ptr< logger_holder_base > construct_logger() 150 { 151 return boost::make_shared< logger_holder< logger_type > >( 152 TagT::registration_file(), 153 static_cast< unsigned int >(TagT::registration_line), 154 TagT::construct_logger()); 155 } 156 }; 157 158 } // namespace aux 159 160 //! The macro forward-declares a global logger with a custom initialization 161 #define BOOST_LOG_GLOBAL_LOGGER(tag_name, logger)\ 162 struct tag_name\ 163 {\ 164 typedef logger logger_type;\ 165 enum registration_line_t { registration_line = __LINE__ };\ 166 static const char* registration_file() { return __FILE__; }\ 167 static logger_type construct_logger();\ 168 static inline logger_type& get()\ 169 {\ 170 return ::boost::log::sources::aux::logger_singleton< tag_name >::get();\ 171 }\ 172 }; 173 174 //! The macro defines a global logger initialization routine 175 #define BOOST_LOG_GLOBAL_LOGGER_INIT(tag_name, logger)\ 176 tag_name::logger_type tag_name::construct_logger() 177 178 //! The macro defines a global logger initializer that will default-construct the logger 179 #define BOOST_LOG_GLOBAL_LOGGER_DEFAULT(tag_name, logger)\ 180 BOOST_LOG_GLOBAL_LOGGER_INIT(tag_name, logger)\ 181 {\ 182 return logger_type();\ 183 } 184 185 //! The macro defines a global logger initializer that will construct the logger with the specified constructor arguments 186 #define BOOST_LOG_GLOBAL_LOGGER_CTOR_ARGS(tag_name, logger, args)\ 187 BOOST_LOG_GLOBAL_LOGGER_INIT(tag_name, logger)\ 188 {\ 189 return logger_type(BOOST_PP_SEQ_ENUM(args));\ 190 } 191 192 //! The macro declares a global logger with a custom initialization 193 #define BOOST_LOG_INLINE_GLOBAL_LOGGER_INIT(tag_name, logger)\ 194 BOOST_LOG_GLOBAL_LOGGER(tag_name, logger)\ 195 inline BOOST_LOG_GLOBAL_LOGGER_INIT(tag_name, logger) 196 197 //! The macro declares a global logger that will be default-constructed 198 #define BOOST_LOG_INLINE_GLOBAL_LOGGER_DEFAULT(tag_name, logger)\ 199 BOOST_LOG_INLINE_GLOBAL_LOGGER_INIT(tag_name, logger)\ 200 {\ 201 return logger_type();\ 202 } 203 204 //! The macro declares a global logger that will be constructed with the specified arguments 205 #define BOOST_LOG_INLINE_GLOBAL_LOGGER_CTOR_ARGS(tag_name, logger, args)\ 206 BOOST_LOG_INLINE_GLOBAL_LOGGER_INIT(tag_name, logger)\ 207 {\ 208 return logger_type(BOOST_PP_SEQ_ENUM(args));\ 209 } 210 211 } // namespace sources 212 213 BOOST_LOG_CLOSE_NAMESPACE // namespace log 214 215 } // namespace boost 216 217 #include <boost/log/detail/footer.hpp> 218 219 #endif // BOOST_LOG_SOURCES_GLOBAL_LOGGER_STORAGE_HPP_INCLUDED_ 220