| 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 severity_feature.hpp |
| 9 | * \author Andrey Semashev |
| 10 | * \date 08.03.2007 |
| 11 | * |
| 12 | * The header contains implementation of a severity level support feature. |
| 13 | */ |
| 14 | |
| 15 | #ifndef BOOST_LOG_SOURCES_SEVERITY_FEATURE_HPP_INCLUDED_ |
| 16 | #define BOOST_LOG_SOURCES_SEVERITY_FEATURE_HPP_INCLUDED_ |
| 17 | |
| 18 | #include <boost/cstdint.hpp> |
| 19 | #include <boost/core/invoke_swap.hpp> |
| 20 | #include <boost/smart_ptr/intrusive_ptr.hpp> |
| 21 | #include <boost/move/core.hpp> |
| 22 | #include <boost/move/utility_core.hpp> |
| 23 | #include <boost/type_traits/is_nothrow_move_constructible.hpp> |
| 24 | #include <boost/log/detail/config.hpp> |
| 25 | #include <boost/log/detail/locks.hpp> |
| 26 | #include <boost/log/detail/default_attribute_names.hpp> |
| 27 | #include <boost/log/attributes/attribute.hpp> |
| 28 | #include <boost/log/attributes/attribute_cast.hpp> |
| 29 | #include <boost/log/attributes/attribute_value_impl.hpp> |
| 30 | #include <boost/log/utility/strictest_lock.hpp> |
| 31 | #include <boost/log/utility/type_dispatch/type_dispatcher.hpp> |
| 32 | #include <boost/log/keywords/severity.hpp> |
| 33 | #include <boost/log/core/record.hpp> |
| 34 | #include <boost/log/detail/header.hpp> |
| 35 | |
| 36 | #ifdef BOOST_HAS_PRAGMA_ONCE |
| 37 | #pragma once |
| 38 | #endif |
| 39 | |
| 40 | namespace boost { |
| 41 | |
| 42 | BOOST_LOG_OPEN_NAMESPACE |
| 43 | |
| 44 | namespace sources { |
| 45 | |
| 46 | namespace aux { |
| 47 | |
| 48 | //! The method returns the storage for severity level for the current thread |
| 49 | BOOST_LOG_API uintmax_t& get_severity_level(); |
| 50 | |
| 51 | //! Severity level attribute implementation |
| 52 | template< typename LevelT > |
| 53 | class severity_level : |
| 54 | public attribute |
| 55 | { |
| 56 | typedef severity_level this_type; |
| 57 | BOOST_COPYABLE_AND_MOVABLE(this_type) |
| 58 | |
| 59 | public: |
| 60 | //! Stored level type |
| 61 | typedef LevelT value_type; |
| 62 | static_assert(sizeof(value_type) <= sizeof(uintmax_t), "Boost.Log: Unsupported severity level type, the severity level must fit into uintmax_t" ); |
| 63 | |
| 64 | protected: |
| 65 | //! Factory implementation |
| 66 | class BOOST_SYMBOL_VISIBLE impl : |
| 67 | public attribute_value::impl |
| 68 | { |
| 69 | public: |
| 70 | //! The method dispatches the value to the given object |
| 71 | bool dispatch(type_dispatcher& dispatcher) BOOST_OVERRIDE |
| 72 | { |
| 73 | type_dispatcher::callback< value_type > callback = dispatcher.get_callback< value_type >(); |
| 74 | if (callback) |
| 75 | { |
| 76 | callback(reinterpret_cast< value_type const& >(get_severity_level())); |
| 77 | return true; |
| 78 | } |
| 79 | else |
| 80 | return false; |
| 81 | } |
| 82 | |
| 83 | //! The method is called when the attribute value is passed to another thread |
| 84 | intrusive_ptr< attribute_value::impl > detach_from_thread() BOOST_OVERRIDE |
| 85 | { |
| 86 | #if !defined(BOOST_LOG_NO_THREADS) |
| 87 | return new attributes::attribute_value_impl< value_type >( |
| 88 | reinterpret_cast< value_type const& >(get_severity_level())); |
| 89 | #else |
| 90 | // With multithreading disabled we may safely return this here. This method will not be called anyway. |
| 91 | return this; |
| 92 | #endif |
| 93 | } |
| 94 | }; |
| 95 | |
| 96 | public: |
| 97 | //! Default constructor |
| 98 | severity_level() : attribute(new impl()) |
| 99 | { |
| 100 | } |
| 101 | //! Copy constructor |
| 102 | severity_level(severity_level const& that) BOOST_NOEXCEPT : attribute(static_cast< attribute const& >(that)) |
| 103 | { |
| 104 | } |
| 105 | //! Move constructor |
| 106 | severity_level(BOOST_RV_REF(severity_level) that) BOOST_NOEXCEPT : attribute(boost::move(t&: static_cast< attribute& >(that))) |
| 107 | { |
| 108 | } |
| 109 | //! Constructor for casting support |
| 110 | explicit severity_level(attributes::cast_source const& source) : |
| 111 | attribute(source.as< impl >()) |
| 112 | { |
| 113 | } |
| 114 | |
| 115 | /*! |
| 116 | * Copy assignment |
| 117 | */ |
| 118 | severity_level& operator= (BOOST_COPY_ASSIGN_REF(severity_level) that) BOOST_NOEXCEPT |
| 119 | { |
| 120 | attribute::operator= (static_cast< attribute const& >(that)); |
| 121 | return *this; |
| 122 | } |
| 123 | |
| 124 | /*! |
| 125 | * Move assignment |
| 126 | */ |
| 127 | severity_level& operator= (BOOST_RV_REF(severity_level) that) BOOST_NOEXCEPT |
| 128 | { |
| 129 | this->swap(that); |
| 130 | return *this; |
| 131 | } |
| 132 | |
| 133 | //! The method sets the actual level |
| 134 | void set_value(value_type level) |
| 135 | { |
| 136 | reinterpret_cast< value_type& >(get_severity_level()) = level; |
| 137 | } |
| 138 | }; |
| 139 | |
| 140 | } // namespace aux |
| 141 | |
| 142 | /*! |
| 143 | * \brief Severity level feature implementation |
| 144 | */ |
| 145 | template< typename BaseT, typename LevelT = int > |
| 146 | class basic_severity_logger : |
| 147 | public BaseT |
| 148 | { |
| 149 | //! Base type |
| 150 | typedef BaseT base_type; |
| 151 | typedef basic_severity_logger this_type; |
| 152 | BOOST_COPYABLE_AND_MOVABLE_ALT(this_type) |
| 153 | |
| 154 | public: |
| 155 | //! Character type |
| 156 | typedef typename base_type::char_type char_type; |
| 157 | //! Final type |
| 158 | typedef typename base_type::final_type final_type; |
| 159 | //! Threading model being used |
| 160 | typedef typename base_type::threading_model threading_model; |
| 161 | |
| 162 | //! Severity level type |
| 163 | typedef LevelT severity_level; |
| 164 | //! Severity attribute type |
| 165 | typedef aux::severity_level< severity_level > severity_attribute; |
| 166 | |
| 167 | #if defined(BOOST_LOG_DOXYGEN_PASS) |
| 168 | //! Lock requirement for the \c open_record_unlocked method |
| 169 | typedef typename strictest_lock< |
| 170 | typename base_type::open_record_lock, |
| 171 | no_lock< threading_model > |
| 172 | >::type open_record_lock; |
| 173 | #endif // defined(BOOST_LOG_DOXYGEN_PASS) |
| 174 | |
| 175 | //! Lock requirement for the \c swap_unlocked method |
| 176 | typedef typename strictest_lock< |
| 177 | typename base_type::swap_lock, |
| 178 | #ifndef BOOST_LOG_NO_THREADS |
| 179 | boost::log::aux::multiple_unique_lock2< threading_model, threading_model > |
| 180 | #else |
| 181 | no_lock< threading_model > |
| 182 | #endif // !defined(BOOST_LOG_NO_THREADS) |
| 183 | >::type swap_lock; |
| 184 | |
| 185 | private: |
| 186 | //! Default severity |
| 187 | severity_level m_DefaultSeverity; |
| 188 | //! Severity attribute |
| 189 | severity_attribute m_SeverityAttr; |
| 190 | |
| 191 | public: |
| 192 | /*! |
| 193 | * Default constructor. The constructed logger will have a severity attribute registered. |
| 194 | * The default level for log records will be 0. |
| 195 | */ |
| 196 | basic_severity_logger() : |
| 197 | base_type(), |
| 198 | m_DefaultSeverity(static_cast< severity_level >(0)) |
| 199 | { |
| 200 | base_type::add_attribute_unlocked(boost::log::aux::default_attribute_names::severity(), m_SeverityAttr); |
| 201 | } |
| 202 | /*! |
| 203 | * Copy constructor |
| 204 | */ |
| 205 | basic_severity_logger(basic_severity_logger const& that) : |
| 206 | base_type(static_cast< base_type const& >(that)), |
| 207 | m_DefaultSeverity(that.m_DefaultSeverity), |
| 208 | m_SeverityAttr(that.m_SeverityAttr) |
| 209 | { |
| 210 | // Our attributes must refer to our severity attribute |
| 211 | base_type::attributes()[boost::log::aux::default_attribute_names::severity()] = m_SeverityAttr; |
| 212 | } |
| 213 | /*! |
| 214 | * Move constructor |
| 215 | */ |
| 216 | basic_severity_logger(BOOST_RV_REF(basic_severity_logger) that) BOOST_NOEXCEPT_IF(boost::is_nothrow_move_constructible< base_type >::value && |
| 217 | boost::is_nothrow_move_constructible< severity_level >::value && |
| 218 | boost::is_nothrow_move_constructible< severity_attribute >::value) : |
| 219 | base_type(boost::move(static_cast< base_type& >(that))), |
| 220 | m_DefaultSeverity(boost::move(that.m_DefaultSeverity)), |
| 221 | m_SeverityAttr(boost::move(that.m_SeverityAttr)) |
| 222 | { |
| 223 | } |
| 224 | /*! |
| 225 | * Constructor with named arguments. Allows to setup the default level for log records. |
| 226 | * |
| 227 | * \param args A set of named arguments. The following arguments are supported: |
| 228 | * \li \c severity - default severity value |
| 229 | */ |
| 230 | template< typename ArgsT > |
| 231 | explicit basic_severity_logger(ArgsT const& args) : |
| 232 | base_type(args), |
| 233 | m_DefaultSeverity(args[keywords::severity | severity_level()]) |
| 234 | { |
| 235 | base_type::add_attribute_unlocked(boost::log::aux::default_attribute_names::severity(), m_SeverityAttr); |
| 236 | } |
| 237 | |
| 238 | /*! |
| 239 | * Default severity value getter |
| 240 | */ |
| 241 | severity_level default_severity() const { return m_DefaultSeverity; } |
| 242 | |
| 243 | protected: |
| 244 | /*! |
| 245 | * Severity attribute accessor |
| 246 | */ |
| 247 | severity_attribute const& get_severity_attribute() const { return m_SeverityAttr; } |
| 248 | |
| 249 | /*! |
| 250 | * Unlocked \c open_record |
| 251 | */ |
| 252 | template< typename ArgsT > |
| 253 | record open_record_unlocked(ArgsT const& args) |
| 254 | { |
| 255 | m_SeverityAttr.set_value(args[keywords::severity | m_DefaultSeverity]); |
| 256 | return base_type::open_record_unlocked(args); |
| 257 | } |
| 258 | |
| 259 | //! Unlocked \c swap |
| 260 | void swap_unlocked(basic_severity_logger& that) |
| 261 | { |
| 262 | base_type::swap_unlocked(static_cast< base_type& >(that)); |
| 263 | boost::core::invoke_swap(m_DefaultSeverity, that.m_DefaultSeverity); |
| 264 | m_SeverityAttr.swap(that.m_SeverityAttr); |
| 265 | } |
| 266 | }; |
| 267 | |
| 268 | /*! |
| 269 | * \brief Severity level support feature |
| 270 | * |
| 271 | * The logger with this feature registers a special attribute with an integral value type on construction. |
| 272 | * This attribute will provide severity level for each log record being made through the logger. |
| 273 | * The severity level can be omitted on logging record construction, in which case the default |
| 274 | * level will be used. The default level can also be customized by passing it to the logger constructor. |
| 275 | * |
| 276 | * The type of the severity level attribute can be specified as a template parameter for the feature |
| 277 | * template. By default, \c int will be used. |
| 278 | */ |
| 279 | template< typename LevelT = int > |
| 280 | struct severity |
| 281 | { |
| 282 | template< typename BaseT > |
| 283 | struct apply |
| 284 | { |
| 285 | typedef basic_severity_logger< |
| 286 | BaseT, |
| 287 | LevelT |
| 288 | > type; |
| 289 | }; |
| 290 | }; |
| 291 | |
| 292 | } // namespace sources |
| 293 | |
| 294 | BOOST_LOG_CLOSE_NAMESPACE // namespace log |
| 295 | |
| 296 | } // namespace boost |
| 297 | |
| 298 | //! The macro allows to put a record with a specific severity level into log |
| 299 | #define BOOST_LOG_STREAM_SEV(logger, lvl)\ |
| 300 | BOOST_LOG_STREAM_WITH_PARAMS((logger), (::boost::log::keywords::severity = (lvl))) |
| 301 | |
| 302 | #ifndef BOOST_LOG_NO_SHORTHAND_NAMES |
| 303 | |
| 304 | //! An equivalent to BOOST_LOG_STREAM_SEV(logger, lvl) |
| 305 | #define BOOST_LOG_SEV(logger, lvl) BOOST_LOG_STREAM_SEV(logger, lvl) |
| 306 | |
| 307 | #endif // BOOST_LOG_NO_SHORTHAND_NAMES |
| 308 | |
| 309 | #include <boost/log/detail/footer.hpp> |
| 310 | |
| 311 | #endif // BOOST_LOG_SOURCES_SEVERITY_FEATURE_HPP_INCLUDED_ |
| 312 | |