]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
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 | ||
49 | 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 | ||
65 | 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) | |
72 | 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 | |
117 | static logger_type& get() | |
118 | { | |
119 | return base_type::get()->m_Logger; | |
120 | } | |
121 | ||
122 | //! Initializes the logger instance (called only once) | |
123 | 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 | |
149 | 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_ |