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   scoped_attribute.hpp
9  * \author Andrey Semashev
10  * \date   13.05.2007
11  *
12  * The header contains definition of facilities to define scoped attributes.
13  */
14 
15 #ifndef BOOST_LOG_ATTRIBUTES_SCOPED_ATTRIBUTE_HPP_INCLUDED_
16 #define BOOST_LOG_ATTRIBUTES_SCOPED_ATTRIBUTE_HPP_INCLUDED_
17 
18 #include <utility>
19 #include <boost/move/core.hpp>
20 #include <boost/move/utility.hpp>
21 #include <boost/utility/addressof.hpp>
22 #include <boost/log/detail/config.hpp>
23 #include <boost/log/core/core.hpp>
24 #include <boost/log/sources/basic_logger.hpp>
25 #include <boost/log/attributes/attribute.hpp>
26 #include <boost/log/attributes/attribute_set.hpp>
27 #include <boost/log/attributes/attribute_name.hpp>
28 #include <boost/log/attributes/constant.hpp>
29 #include <boost/log/utility/unused_variable.hpp>
30 #include <boost/log/utility/unique_identifier_name.hpp>
31 #include <boost/log/detail/header.hpp>
32 
33 #ifdef BOOST_HAS_PRAGMA_ONCE
34 #pragma once
35 #endif
36 
37 namespace boost {
38 
39 BOOST_LOG_OPEN_NAMESPACE
40 
41 namespace aux {
42 
43 //! A base class for all scoped attribute guards
44 class attribute_scope_guard
45 {
46 };
47 
48 } // namespace aux
49 
50 //! Scoped attribute guard type
51 typedef aux::attribute_scope_guard const& scoped_attribute;
52 
53 namespace aux {
54 
55 //! A scoped logger attribute guard
56 template< typename LoggerT >
57 class scoped_logger_attribute :
58     public attribute_scope_guard
59 {
60     BOOST_COPYABLE_AND_MOVABLE_ALT(scoped_logger_attribute)
61 
62 private:
63     //! Logger type
64     typedef LoggerT logger_type;
65 
66 private:
67     //! A reference to the logger
68     logger_type* m_pLogger;
69     //! An iterator to the added attribute
70     attribute_set::iterator m_itAttribute;
71 
72 public:
73     //! Constructor
scoped_logger_attribute(logger_type & l,attribute_name const & name,attribute const & attr)74     scoped_logger_attribute(logger_type& l, attribute_name const& name, attribute const& attr) :
75         m_pLogger(boost::addressof(l))
76     {
77         std::pair<
78             attribute_set::iterator,
79             bool
80         > res = l.add_attribute(name, attr);
81         if (res.second)
82             m_itAttribute = res.first;
83         else
84             m_pLogger = 0; // if there already is a same-named attribute, don't register anything
85     }
86     //! Move constructor
scoped_logger_attribute(BOOST_RV_REF (scoped_logger_attribute)that)87     scoped_logger_attribute(BOOST_RV_REF(scoped_logger_attribute) that) :
88         m_pLogger(that.m_pLogger),
89         m_itAttribute(that.m_itAttribute)
90     {
91         that.m_pLogger = 0;
92     }
93 
94     //! Destructor
~scoped_logger_attribute()95     ~scoped_logger_attribute()
96     {
97         if (m_pLogger)
98             m_pLogger->remove_attribute(m_itAttribute);
99     }
100 
101 #ifndef BOOST_LOG_BROKEN_REFERENCE_FROM_RVALUE_INIT
102     BOOST_DELETED_FUNCTION(scoped_logger_attribute(scoped_logger_attribute const&))
103 #else // BOOST_LOG_BROKEN_REFERENCE_FROM_RVALUE_INIT
104     scoped_logger_attribute(scoped_logger_attribute const& that) : m_pLogger(that.m_pLogger), m_itAttribute(that.m_itAttribute)
105     {
106         const_cast< scoped_logger_attribute& >(that).m_pLogger = 0;
107     }
108 #endif // BOOST_LOG_BROKEN_REFERENCE_FROM_RVALUE_INIT
109 
110     BOOST_DELETED_FUNCTION(scoped_logger_attribute& operator= (scoped_logger_attribute const&))
111 };
112 
113 } // namespace aux
114 
115 //  Generator helper functions
116 /*!
117  * Registers an attribute in the logger
118  *
119  * \param l Logger to register the attribute in
120  * \param name Attribute name
121  * \param attr The attribute. Must not be NULL.
122  * \return An unspecified guard object which may be used to initialize a \c scoped_attribute variable.
123  */
124 template< typename LoggerT >
add_scoped_logger_attribute(LoggerT & l,attribute_name const & name,attribute const & attr)125 BOOST_FORCEINLINE aux::scoped_logger_attribute< LoggerT > add_scoped_logger_attribute(LoggerT& l, attribute_name const& name, attribute const& attr)
126 {
127 #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
128     return aux::scoped_logger_attribute< LoggerT >(l, name, attr);
129 #else
130     aux::scoped_logger_attribute< LoggerT > guard(l, name, attr);
131     return boost::move(guard);
132 #endif
133 }
134 
135 #ifndef BOOST_LOG_DOXYGEN_PASS
136 
137 #define BOOST_LOG_SCOPED_LOGGER_ATTR_INTERNAL(logger, attr_name, attr, sentry_var_name)\
138     BOOST_LOG_UNUSED_VARIABLE(::boost::log::scoped_attribute, sentry_var_name,\
139         = ::boost::log::add_scoped_logger_attribute(logger, attr_name, (attr)));
140 
141 #endif // BOOST_LOG_DOXYGEN_PASS
142 
143 //! The macro sets a scoped logger-wide attribute in a more compact way
144 #define BOOST_LOG_SCOPED_LOGGER_ATTR(logger, attr_name, attr)\
145     BOOST_LOG_SCOPED_LOGGER_ATTR_INTERNAL(\
146         logger,\
147         attr_name,\
148         attr,\
149         BOOST_LOG_UNIQUE_IDENTIFIER_NAME(_boost_log_scoped_logger_attr_sentry_))
150 
151 //! The macro sets a scoped logger-wide tag in a more compact way
152 #define BOOST_LOG_SCOPED_LOGGER_TAG(logger, attr_name, attr_value)\
153     BOOST_LOG_SCOPED_LOGGER_ATTR(logger, attr_name, ::boost::log::attributes::make_constant(attr_value))
154 
155 namespace aux {
156 
157 //! A scoped thread-specific attribute guard
158 class scoped_thread_attribute :
159     public attribute_scope_guard
160 {
161     BOOST_COPYABLE_AND_MOVABLE_ALT(scoped_thread_attribute)
162 
163 private:
164     //! A pointer to the logging core
165     core_ptr m_pCore;
166     //! An iterator to the added attribute
167     attribute_set::iterator m_itAttribute;
168 
169 public:
170     //! Constructor
scoped_thread_attribute(attribute_name const & name,attribute const & attr)171     scoped_thread_attribute(attribute_name const& name, attribute const& attr) :
172         m_pCore(core::get())
173     {
174         std::pair<
175             attribute_set::iterator,
176             bool
177         > res = m_pCore->add_thread_attribute(name, attr);
178         if (res.second)
179             m_itAttribute = res.first;
180         else
181             m_pCore.reset(); // if there already is a same-named attribute, don't register anything
182     }
183     //! Move constructor
scoped_thread_attribute(BOOST_RV_REF (scoped_thread_attribute)that)184     scoped_thread_attribute(BOOST_RV_REF(scoped_thread_attribute) that) : m_itAttribute(that.m_itAttribute)
185     {
186         m_pCore.swap(that.m_pCore);
187     }
188 
189     //! Destructor
~scoped_thread_attribute()190     ~scoped_thread_attribute()
191     {
192         if (!!m_pCore)
193             m_pCore->remove_thread_attribute(m_itAttribute);
194     }
195 
196 #ifndef BOOST_LOG_BROKEN_REFERENCE_FROM_RVALUE_INIT
197     BOOST_DELETED_FUNCTION(scoped_thread_attribute(scoped_thread_attribute const&))
198 #else // BOOST_LOG_BROKEN_REFERENCE_FROM_RVALUE_INIT
199     scoped_thread_attribute(scoped_thread_attribute const& that) : m_itAttribute(that.m_itAttribute)
200     {
201         m_pCore.swap(const_cast< scoped_thread_attribute& >(that).m_pCore);
202     }
203 #endif // BOOST_LOG_BROKEN_REFERENCE_FROM_RVALUE_INIT
204 
205     BOOST_DELETED_FUNCTION(scoped_thread_attribute& operator= (scoped_thread_attribute const&))
206 };
207 
208 } // namespace aux
209 
210 //  Generator helper functions
211 /*!
212  * Registers a thread-specific attribute
213  *
214  * \param name Attribute name
215  * \param attr The attribute. Must not be NULL.
216  * \return An unspecified guard object which may be used to initialize a \c scoped_attribute variable.
217  */
add_scoped_thread_attribute(attribute_name const & name,attribute const & attr)218 BOOST_FORCEINLINE aux::scoped_thread_attribute add_scoped_thread_attribute(attribute_name const& name, attribute const& attr)
219 {
220 #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
221     return aux::scoped_thread_attribute(name, attr);
222 #else
223     aux::scoped_thread_attribute guard(name, attr);
224     return boost::move(guard);
225 #endif
226 }
227 
228 #ifndef BOOST_LOG_DOXYGEN_PASS
229 
230 #define BOOST_LOG_SCOPED_THREAD_ATTR_INTERNAL(attr_name, attr, sentry_var_name)\
231     BOOST_LOG_UNUSED_VARIABLE(::boost::log::scoped_attribute, sentry_var_name,\
232         = ::boost::log::add_scoped_thread_attribute(attr_name, (attr)));
233 
234 #endif // BOOST_LOG_DOXYGEN_PASS
235 
236 //! The macro sets a scoped thread-wide attribute in a more compact way
237 #define BOOST_LOG_SCOPED_THREAD_ATTR(attr_name, attr)\
238     BOOST_LOG_SCOPED_THREAD_ATTR_INTERNAL(\
239         attr_name,\
240         attr,\
241         BOOST_LOG_UNIQUE_IDENTIFIER_NAME(_boost_log_scoped_thread_attr_sentry_))
242 
243 //! The macro sets a scoped thread-wide tag in a more compact way
244 #define BOOST_LOG_SCOPED_THREAD_TAG(attr_name, attr_value)\
245     BOOST_LOG_SCOPED_THREAD_ATTR(attr_name, ::boost::log::attributes::make_constant(attr_value))
246 
247 BOOST_LOG_CLOSE_NAMESPACE // namespace log
248 
249 } // namespace boost
250 
251 #include <boost/log/detail/footer.hpp>
252 
253 #endif // BOOST_LOG_ATTRIBUTES_SCOPED_ATTRIBUTE_HPP_INCLUDED_
254