global_logger_storage.hpp 7.6 KB

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