• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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