• 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   basic_logger.hpp
9  * \author Andrey Semashev
10  * \date   08.03.2007
11  *
12  * The header contains implementation of a base class for loggers. Convenience macros
13  * for defining custom loggers are also provided.
14  */
15 
16 #ifndef BOOST_LOG_SOURCES_BASIC_LOGGER_HPP_INCLUDED_
17 #define BOOST_LOG_SOURCES_BASIC_LOGGER_HPP_INCLUDED_
18 
19 #include <exception>
20 #include <utility>
21 #include <ostream>
22 #include <boost/assert.hpp>
23 #include <boost/move/core.hpp>
24 #include <boost/move/utility_core.hpp>
25 #include <boost/core/addressof.hpp>
26 #include <boost/type_traits/is_nothrow_swappable.hpp>
27 #include <boost/type_traits/is_nothrow_move_constructible.hpp>
28 #include <boost/preprocessor/facilities/empty.hpp>
29 #include <boost/preprocessor/facilities/identity.hpp>
30 #include <boost/preprocessor/repetition/enum_params.hpp>
31 #include <boost/preprocessor/repetition/enum_binary_params.hpp>
32 #include <boost/preprocessor/repetition/repeat_from_to.hpp>
33 #include <boost/preprocessor/seq/enum.hpp>
34 #include <boost/log/detail/config.hpp>
35 #include <boost/log/detail/parameter_tools.hpp>
36 #include <boost/log/attributes/attribute_set.hpp>
37 #include <boost/log/attributes/attribute_name.hpp>
38 #include <boost/log/attributes/attribute.hpp>
39 #include <boost/log/core/core.hpp>
40 #include <boost/log/core/record.hpp>
41 #include <boost/log/sources/features.hpp>
42 #include <boost/log/sources/threading_models.hpp>
43 #include <boost/log/detail/header.hpp>
44 
45 #ifdef BOOST_HAS_PRAGMA_ONCE
46 #pragma once
47 #endif
48 
49 namespace boost {
50 
51 BOOST_LOG_OPEN_NAMESPACE
52 
53 namespace sources {
54 
55 /*!
56  * \brief Basic logger class
57  *
58  * The \c basic_logger class template serves as a base class for all loggers
59  * provided by the library. It can also be used as a base for user-defined
60  * loggers. The template parameters are:
61  *
62  * \li \c CharT - logging character type
63  * \li \c FinalT - final type of the logger that eventually derives from
64  *     the \c basic_logger. There may be other classes in the hierarchy
65  *     between the final class and \c basic_logger.
66  * \li \c ThreadingModelT - threading model policy. Must provide methods
67  *     of the Boost.Thread locking concept used in \c basic_logger class
68  *     and all its derivatives in the hierarchy up to the \c FinalT class.
69  *     The \c basic_logger class itself requires methods of the
70  *     SharedLockable concept. The threading model policy must also be
71  *     default and copy-constructible and support member function \c swap.
72  *     There are currently two policies provided: \c single_thread_model
73  *     and \c multi_thread_model.
74  *
75  * The logger implements fundamental facilities of loggers, such as storing
76  * source-specific attribute set and formatting log record messages. The basic
77  * logger interacts with the logging core in order to apply filtering and
78  * pass records to sinks.
79  */
80 template< typename CharT, typename FinalT, typename ThreadingModelT >
81 class basic_logger :
82     public ThreadingModelT
83 {
84     typedef basic_logger this_type;
85     BOOST_COPYABLE_AND_MOVABLE_ALT(this_type)
86 
87 public:
88     //! Character type
89     typedef CharT char_type;
90     //! Final logger type
91     typedef FinalT final_type;
92     //! Threading model type
93     typedef ThreadingModelT threading_model;
94 
95 #if !defined(BOOST_LOG_NO_THREADS)
96     //! Lock requirement for the swap_unlocked method
97     typedef boost::log::aux::multiple_unique_lock2< threading_model, threading_model > swap_lock;
98     //! Lock requirement for the add_attribute_unlocked method
99     typedef boost::log::aux::exclusive_lock_guard< threading_model > add_attribute_lock;
100     //! Lock requirement for the remove_attribute_unlocked method
101     typedef boost::log::aux::exclusive_lock_guard< threading_model > remove_attribute_lock;
102     //! Lock requirement for the remove_all_attributes_unlocked method
103     typedef boost::log::aux::exclusive_lock_guard< threading_model > remove_all_attributes_lock;
104     //! Lock requirement for the get_attributes method
105     typedef boost::log::aux::shared_lock_guard< const threading_model > get_attributes_lock;
106     //! Lock requirement for the open_record_unlocked method
107     typedef boost::log::aux::shared_lock_guard< threading_model > open_record_lock;
108     //! Lock requirement for the set_attributes method
109     typedef boost::log::aux::exclusive_lock_guard< threading_model > set_attributes_lock;
110 #else
111     typedef no_lock< threading_model > swap_lock;
112     typedef no_lock< threading_model > add_attribute_lock;
113     typedef no_lock< threading_model > remove_attribute_lock;
114     typedef no_lock< threading_model > remove_all_attributes_lock;
115     typedef no_lock< const threading_model > get_attributes_lock;
116     typedef no_lock< threading_model > open_record_lock;
117     typedef no_lock< threading_model > set_attributes_lock;
118 #endif
119 
120     //! Lock requirement for the push_record_unlocked method
121     typedef no_lock< threading_model > push_record_lock;
122 
123 private:
124     //! A pointer to the logging system
125     core_ptr m_pCore;
126 
127     //! Logger-specific attribute set
128     attribute_set m_Attributes;
129 
130 public:
131     /*!
132      * Constructor. Initializes internal data structures of the basic logger class,
133      * acquires reference to the logging core.
134      */
basic_logger()135     basic_logger() :
136         threading_model(),
137         m_pCore(core::get())
138     {
139     }
140     /*!
141      * Copy constructor. Copies all attributes from the source logger.
142      *
143      * \note Not thread-safe. The source logger must be locked in the final class before copying.
144      *
145      * \param that Source logger
146      */
basic_logger(basic_logger const & that)147     basic_logger(basic_logger const& that) :
148         threading_model(static_cast< threading_model const& >(that)),
149         m_pCore(that.m_pCore),
150         m_Attributes(that.m_Attributes)
151     {
152     }
153     /*!
154      * Move constructor. Moves all attributes from the source logger.
155      *
156      * \note Not thread-safe. The source logger must be locked in the final class before copying.
157      *
158      * \param that Source logger
159      */
BOOST_NOEXCEPT_IF(boost::is_nothrow_move_constructible<threading_model>::value && boost::is_nothrow_move_constructible<core_ptr>::value && boost::is_nothrow_move_constructible<attribute_set>::value)160     basic_logger(BOOST_RV_REF(basic_logger) that) BOOST_NOEXCEPT_IF(boost::is_nothrow_move_constructible< threading_model >::value &&
161                                                                     boost::is_nothrow_move_constructible< core_ptr >::value &&
162                                                                     boost::is_nothrow_move_constructible< attribute_set >::value) :
163         threading_model(boost::move(static_cast< threading_model& >(that))),
164         m_pCore(boost::move(that.m_pCore)),
165         m_Attributes(boost::move(that.m_Attributes))
166     {
167     }
168     /*!
169      * Constructor with named arguments. The constructor ignores all arguments. The result of
170      * construction is equivalent to default construction.
171      */
172     template< typename ArgsT >
basic_logger(ArgsT const &)173     explicit basic_logger(ArgsT const&) :
174         threading_model(),
175         m_pCore(core::get())
176     {
177     }
178 
179 protected:
180     /*!
181      * An accessor to the logging system pointer
182      */
core() const183     core_ptr const& core() const { return m_pCore; }
184     /*!
185      * An accessor to the logger attributes
186      */
attributes()187     attribute_set& attributes() { return m_Attributes; }
188     /*!
189      * An accessor to the logger attributes
190      */
attributes() const191     attribute_set const& attributes() const { return m_Attributes; }
192     /*!
193      * An accessor to the threading model base
194      */
get_threading_model()195     threading_model& get_threading_model() BOOST_NOEXCEPT { return *this; }
196     /*!
197      * An accessor to the threading model base
198      */
get_threading_model() const199     threading_model const& get_threading_model() const BOOST_NOEXCEPT { return *this; }
200     /*!
201      * An accessor to the final logger
202      */
final_this()203     final_type* final_this() BOOST_NOEXCEPT
204     {
205         BOOST_LOG_ASSUME(this != NULL);
206         return static_cast< final_type* >(this);
207     }
208     /*!
209      * An accessor to the final logger
210      */
final_this() const211     final_type const* final_this() const BOOST_NOEXCEPT
212     {
213         BOOST_LOG_ASSUME(this != NULL);
214         return static_cast< final_type const* >(this);
215     }
216 
217     /*!
218      * Unlocked \c swap
219      */
swap_unlocked(basic_logger & that)220     void swap_unlocked(basic_logger& that)
221     {
222         get_threading_model().swap(that.get_threading_model());
223         m_Attributes.swap(that.m_Attributes);
224     }
225 
226     /*!
227      * Unlocked \c add_attribute
228      */
add_attribute_unlocked(attribute_name const & name,attribute const & attr)229     std::pair< attribute_set::iterator, bool > add_attribute_unlocked(attribute_name const& name, attribute const& attr)
230     {
231         return m_Attributes.insert(name, attr);
232     }
233 
234     /*!
235      * Unlocked \c remove_attribute
236      */
remove_attribute_unlocked(attribute_set::iterator it)237     void remove_attribute_unlocked(attribute_set::iterator it)
238     {
239         m_Attributes.erase(it);
240     }
241 
242     /*!
243      * Unlocked \c remove_all_attributes
244      */
remove_all_attributes_unlocked()245     void remove_all_attributes_unlocked()
246     {
247         m_Attributes.clear();
248     }
249 
250     /*!
251      * Unlocked \c open_record
252      */
open_record_unlocked()253     record open_record_unlocked()
254     {
255         return m_pCore->open_record(m_Attributes);
256     }
257     /*!
258      * Unlocked \c open_record
259      */
260     template< typename ArgsT >
open_record_unlocked(ArgsT const &)261     record open_record_unlocked(ArgsT const&)
262     {
263         return m_pCore->open_record(m_Attributes);
264     }
265 
266     /*!
267      * Unlocked \c push_record
268      */
push_record_unlocked(BOOST_RV_REF (record)rec)269     void push_record_unlocked(BOOST_RV_REF(record) rec)
270     {
271         m_pCore->push_record(boost::move(rec));
272     }
273 
274     /*!
275      * Unlocked \c get_attributes
276      */
get_attributes_unlocked() const277     attribute_set get_attributes_unlocked() const
278     {
279         return m_Attributes;
280     }
281 
282     /*!
283      * Unlocked \c set_attributes
284      */
set_attributes_unlocked(attribute_set const & attrs)285     void set_attributes_unlocked(attribute_set const& attrs)
286     {
287         m_Attributes = attrs;
288     }
289 
290     //! Assignment is closed (should be implemented through copy and swap in the final class)
291     BOOST_DELETED_FUNCTION(basic_logger& operator= (basic_logger const&))
292 };
293 
294 /*!
295  * Free-standing swap for all loggers
296  */
297 template< typename CharT, typename FinalT, typename ThreadingModelT >
swap(basic_logger<CharT,FinalT,ThreadingModelT> & left,basic_logger<CharT,FinalT,ThreadingModelT> & right)298 inline void swap(
299     basic_logger< CharT, FinalT, ThreadingModelT >& left,
300     basic_logger< CharT, FinalT, ThreadingModelT >& right) BOOST_NOEXCEPT_IF(boost::is_nothrow_swappable< FinalT >::value)
301 {
302     static_cast< FinalT& >(left).swap(static_cast< FinalT& >(right));
303 }
304 
305 /*!
306  * \brief A composite logger that inherits a number of features
307  *
308  * The composite logger is a helper class that simplifies feature composition into the final logger.
309  * The user's logger class is expected to derive from the composite logger class, instantiated with
310  * the character type, the user's logger class, the threading model and the list of the required features.
311  * The former three parameters are passed to the \c basic_logger class template. The feature list
312  * must be an MPL type sequence, where each element is a unary MPL metafunction class, that upon
313  * applying on its argument results in a logging feature class that derives from the argument.
314  * Every logger feature provided by the library can participate in the feature list.
315  */
316 template< typename CharT, typename FinalT, typename ThreadingModelT, typename FeaturesT >
317 class basic_composite_logger :
318     public boost::log::sources::aux::inherit_features<
319         basic_logger< CharT, FinalT, ThreadingModelT >,
320         FeaturesT
321     >::type
322 {
323 private:
324     //! Base type (the hierarchy of features)
325     typedef typename boost::log::sources::aux::inherit_features<
326         basic_logger< CharT, FinalT, ThreadingModelT >,
327         FeaturesT
328     >::type base_type;
329 
330 protected:
331     //! The composite logger type (for use in the user's logger class)
332     typedef basic_composite_logger logger_base;
333     BOOST_COPYABLE_AND_MOVABLE_ALT(logger_base)
334 
335 public:
336     //! Threading model being used
337     typedef typename base_type::threading_model threading_model;
338 
339     //! Lock requirement for the swap_unlocked method
340     typedef typename base_type::swap_lock swap_lock;
341 
342 #if !defined(BOOST_LOG_NO_THREADS)
343 
344 public:
345     /*!
346      * Default constructor (default-constructs all features)
347      */
basic_composite_logger()348     basic_composite_logger() {}
349     /*!
350      * Copy constructor
351      */
basic_composite_logger(basic_composite_logger const & that)352     basic_composite_logger(basic_composite_logger const& that) :
353         base_type
354         ((
355             boost::log::aux::shared_lock_guard< const threading_model >(that.get_threading_model()),
356             static_cast< base_type const& >(that)
357         ))
358     {
359     }
360     /*!
361      * Move constructor
362      */
BOOST_NOEXCEPT_IF(boost::is_nothrow_move_constructible<base_type>::value)363     basic_composite_logger(BOOST_RV_REF(logger_base) that) BOOST_NOEXCEPT_IF(boost::is_nothrow_move_constructible< base_type >::value) :
364         base_type(boost::move(static_cast< base_type& >(that)))
365     {
366     }
367     /*!
368      * Constructor with named parameters
369      */
370     template< typename ArgsT >
basic_composite_logger(ArgsT const & args)371     explicit basic_composite_logger(ArgsT const& args) : base_type(args)
372     {
373     }
374 
375     /*!
376      * The method adds an attribute to the source-specific attribute set. The attribute will be implicitly added to
377      * every log record made with the current logger.
378      *
379      * \param name The attribute name.
380      * \param attr The attribute factory.
381      * \return A pair of values. If the second member is \c true, then the attribute is added and the first member points to the
382      *         attribute. Otherwise the attribute was not added and the first member points to the attribute that prevents
383      *         addition.
384      */
add_attribute(attribute_name const & name,attribute const & attr)385     std::pair< attribute_set::iterator, bool > add_attribute(attribute_name const& name, attribute const& attr)
386     {
387         typename base_type::add_attribute_lock lock(base_type::get_threading_model());
388         return base_type::add_attribute_unlocked(name, attr);
389     }
390     /*!
391      * The method removes an attribute from the source-specific attribute set.
392      *
393      * \pre The attribute was added with the add_attribute call for this instance of the logger.
394      * \post The attribute is no longer registered as a source-specific attribute for this logger. The iterator is invalidated after removal.
395      *
396      * \param it Iterator to the previously added attribute.
397      */
remove_attribute(attribute_set::iterator it)398     void remove_attribute(attribute_set::iterator it)
399     {
400         typename base_type::remove_attribute_lock lock(base_type::get_threading_model());
401         base_type::remove_attribute_unlocked(it);
402     }
403 
404     /*!
405      * The method removes all attributes from the logger. All iterators and references to the removed attributes are invalidated.
406      */
remove_all_attributes()407     void remove_all_attributes()
408     {
409         typename base_type::remove_all_attributes_lock lock(base_type::get_threading_model());
410         base_type::remove_all_attributes_unlocked();
411     }
412 
413     /*!
414      * The method retrieves a copy of a set with all attributes from the logger.
415      *
416      * \return The copy of the attribute set. Attributes are shallow-copied.
417      */
get_attributes() const418     attribute_set get_attributes() const
419     {
420         typename base_type::get_attributes_lock lock(base_type::get_threading_model());
421         return base_type::get_attributes_unlocked();
422     }
423 
424     /*!
425      * The method installs the whole attribute set into the logger. All iterators and references to elements of
426      * the previous set are invalidated. Iterators to the \a attrs set are not valid to be used with the logger (that is,
427      * the logger owns a copy of \a attrs after completion).
428      *
429      * \param attrs The set of attributes to install into the logger. Attributes are shallow-copied.
430      */
set_attributes(attribute_set const & attrs)431     void set_attributes(attribute_set const& attrs)
432     {
433         typename base_type::set_attributes_lock lock(base_type::get_threading_model());
434         base_type::set_attributes_unlocked(attrs);
435     }
436 
437     /*!
438      * The method opens a new log record in the logging core.
439      *
440      * \return A valid record handle if the logging record is opened successfully, an invalid handle otherwise.
441      */
open_record()442     record open_record()
443     {
444         // Perform a quick check first
445         if (this->core()->get_logging_enabled())
446         {
447             typename base_type::open_record_lock lock(base_type::get_threading_model());
448             return base_type::open_record_unlocked(boost::log::aux::empty_arg_list());
449         }
450         else
451             return record();
452     }
453     /*!
454      * The method opens a new log record in the logging core.
455      *
456      * \param args A set of additional named arguments. The parameter is ignored.
457      * \return A valid record handle if the logging record is opened successfully, an invalid handle otherwise.
458      */
459     template< typename ArgsT >
open_record(ArgsT const & args)460     record open_record(ArgsT const& args)
461     {
462         // Perform a quick check first
463         if (this->core()->get_logging_enabled())
464         {
465             typename base_type::open_record_lock lock(base_type::get_threading_model());
466             return base_type::open_record_unlocked(args);
467         }
468         else
469             return record();
470     }
471     /*!
472      * The method pushes the constructed message to the logging core
473      *
474      * \param rec The log record with the formatted message
475      */
push_record(BOOST_RV_REF (record)rec)476     void push_record(BOOST_RV_REF(record) rec)
477     {
478         typename base_type::push_record_lock lock(base_type::get_threading_model());
479         base_type::push_record_unlocked(boost::move(rec));
480     }
481     /*!
482      * Thread-safe implementation of swap
483      */
swap(basic_composite_logger & that)484     void swap(basic_composite_logger& that)
485     {
486         swap_lock lock(base_type::get_threading_model(), that.get_threading_model());
487         base_type::swap_unlocked(static_cast< base_type& >(that));
488     }
489 
490 protected:
491     /*!
492      * Assignment for the final class. Threadsafe, provides strong exception guarantee.
493      */
assign(FinalT const & that)494     FinalT& assign(FinalT const& that)
495     {
496         BOOST_LOG_ASSUME(this != NULL);
497         if (static_cast< FinalT* >(this) != boost::addressof(that))
498         {
499             // We'll have to explicitly create the copy in order to make sure it's unlocked when we attempt to lock *this
500             FinalT tmp(that);
501             boost::log::aux::exclusive_lock_guard< threading_model > lock(base_type::get_threading_model());
502             base_type::swap_unlocked(tmp);
503         }
504         return static_cast< FinalT& >(*this);
505     }
506 };
507 
508 //! An optimized composite logger version with no multithreading support
509 template< typename CharT, typename FinalT, typename FeaturesT >
510 class basic_composite_logger< CharT, FinalT, single_thread_model, FeaturesT > :
511     public boost::log::sources::aux::inherit_features<
512         basic_logger< CharT, FinalT, single_thread_model >,
513         FeaturesT
514     >::type
515 {
516 private:
517     typedef typename boost::log::sources::aux::inherit_features<
518         basic_logger< CharT, FinalT, single_thread_model >,
519         FeaturesT
520     >::type base_type;
521 
522 protected:
523     typedef basic_composite_logger logger_base;
524     BOOST_COPYABLE_AND_MOVABLE_ALT(logger_base)
525 
526 public:
527     typedef typename base_type::threading_model threading_model;
528 
529 #endif // !defined(BOOST_LOG_NO_THREADS)
530 
531 public:
basic_composite_logger()532     basic_composite_logger() {}
basic_composite_logger(basic_composite_logger const & that)533     basic_composite_logger(basic_composite_logger const& that) :
534         base_type(static_cast< base_type const& >(that))
535     {
536     }
BOOST_NOEXCEPT_IF(boost::is_nothrow_move_constructible<base_type>::value)537     basic_composite_logger(BOOST_RV_REF(logger_base) that) BOOST_NOEXCEPT_IF(boost::is_nothrow_move_constructible< base_type >::value) :
538         base_type(boost::move(static_cast< base_type& >(that)))
539     {
540     }
541     template< typename ArgsT >
basic_composite_logger(ArgsT const & args)542     explicit basic_composite_logger(ArgsT const& args) : base_type(args)
543     {
544     }
545 
add_attribute(attribute_name const & name,attribute const & attr)546     std::pair< attribute_set::iterator, bool > add_attribute(attribute_name const& name, attribute const& attr)
547     {
548         return base_type::add_attribute_unlocked(name, attr);
549     }
remove_attribute(attribute_set::iterator it)550     void remove_attribute(attribute_set::iterator it)
551     {
552         base_type::remove_attribute_unlocked(it);
553     }
remove_all_attributes()554     void remove_all_attributes()
555     {
556         base_type::remove_all_attributes_unlocked();
557     }
get_attributes() const558     attribute_set get_attributes() const
559     {
560         return base_type::get_attributes_unlocked();
561     }
set_attributes(attribute_set const & attrs)562     void set_attributes(attribute_set const& attrs)
563     {
564         base_type::set_attributes_unlocked(attrs);
565     }
open_record()566     record open_record()
567     {
568         // Perform a quick check first
569         if (this->core()->get_logging_enabled())
570             return base_type::open_record_unlocked(boost::log::aux::empty_arg_list());
571         else
572             return record();
573     }
574     template< typename ArgsT >
open_record(ArgsT const & args)575     record open_record(ArgsT const& args)
576     {
577         // Perform a quick check first
578         if (this->core()->get_logging_enabled())
579             return base_type::open_record_unlocked(args);
580         else
581             return record();
582     }
push_record(BOOST_RV_REF (record)rec)583     void push_record(BOOST_RV_REF(record) rec)
584     {
585         base_type::push_record_unlocked(boost::move(rec));
586     }
swap(basic_composite_logger & that)587     void swap(basic_composite_logger& that)
588     {
589         base_type::swap_unlocked(static_cast< base_type& >(that));
590     }
591 
592 protected:
assign(FinalT that)593     FinalT& assign(FinalT that)
594     {
595         base_type::swap_unlocked(that);
596         return static_cast< FinalT& >(*this);
597     }
598 };
599 
600 
601 #ifndef BOOST_LOG_DOXYGEN_PASS
602 
603 #define BOOST_LOG_FORWARD_LOGGER_CONSTRUCTORS_IMPL(class_type, typename_keyword)\
604     public:\
605         BOOST_DEFAULTED_FUNCTION(class_type(), {})\
606         class_type(class_type const& that) : class_type::logger_base(\
607             static_cast< typename_keyword() class_type::logger_base const& >(that)) {}\
608         class_type(BOOST_RV_REF(class_type) that) BOOST_NOEXCEPT_IF(boost::is_nothrow_move_constructible< typename_keyword() class_type::logger_base >::value) : class_type::logger_base(\
609             ::boost::move(static_cast< typename_keyword() class_type::logger_base& >(that))) {}\
610         BOOST_LOG_PARAMETRIZED_CONSTRUCTORS_FORWARD(class_type, class_type::logger_base)\
611 
612 #endif // BOOST_LOG_DOXYGEN_PASS
613 
614 #define BOOST_LOG_FORWARD_LOGGER_CONSTRUCTORS(class_type)\
615     BOOST_LOG_FORWARD_LOGGER_CONSTRUCTORS_IMPL(class_type, BOOST_PP_EMPTY)
616 
617 #define BOOST_LOG_FORWARD_LOGGER_CONSTRUCTORS_TEMPLATE(class_type)\
618     BOOST_LOG_FORWARD_LOGGER_CONSTRUCTORS_IMPL(class_type, BOOST_PP_IDENTITY(typename))
619 
620 #define BOOST_LOG_FORWARD_LOGGER_ASSIGNMENT(class_type)\
621     public:\
622         class_type& operator= (BOOST_COPY_ASSIGN_REF(class_type) that)\
623         {\
624             return class_type::logger_base::assign(static_cast< class_type const& >(that));\
625         }\
626         class_type& operator= (BOOST_RV_REF(class_type) that)\
627         {\
628             BOOST_LOG_EXPR_IF_MT(::boost::log::aux::exclusive_lock_guard< class_type::threading_model > lock(this->get_threading_model());)\
629             this->swap_unlocked(that);\
630             return *this;\
631         }
632 
633 #define BOOST_LOG_FORWARD_LOGGER_ASSIGNMENT_TEMPLATE(class_type)\
634     public:\
635         class_type& operator= (BOOST_COPY_ASSIGN_REF(class_type) that)\
636         {\
637             return class_type::logger_base::assign(static_cast< class_type const& >(that));\
638         }\
639         class_type& operator= (BOOST_RV_REF(class_type) that)\
640         {\
641             BOOST_LOG_EXPR_IF_MT(::boost::log::aux::exclusive_lock_guard< typename class_type::threading_model > lock(this->get_threading_model());)\
642             this->swap_unlocked(that);\
643             return *this;\
644         }
645 
646 #define BOOST_LOG_FORWARD_LOGGER_MEMBERS(class_type)\
647     BOOST_COPYABLE_AND_MOVABLE(class_type)\
648     BOOST_LOG_FORWARD_LOGGER_CONSTRUCTORS(class_type)\
649     BOOST_LOG_FORWARD_LOGGER_ASSIGNMENT(class_type)
650 
651 #define BOOST_LOG_FORWARD_LOGGER_MEMBERS_TEMPLATE(class_type)\
652     BOOST_COPYABLE_AND_MOVABLE(class_type)\
653     BOOST_LOG_FORWARD_LOGGER_CONSTRUCTORS_TEMPLATE(class_type)\
654     BOOST_LOG_FORWARD_LOGGER_ASSIGNMENT_TEMPLATE(class_type)
655 
656 } // namespace sources
657 
658 BOOST_LOG_CLOSE_NAMESPACE // namespace log
659 
660 } // namespace boost
661 
662 /*!
663  *  \brief The macro declares a logger class that inherits a number of base classes
664  *
665  *  \param type_name The name of the logger class to declare
666  *  \param char_type The character type of the logger. Either char or wchar_t expected.
667  *  \param base_seq A Boost.Preprocessor sequence of type identifiers of the base classes templates
668  *  \param threading A threading model class
669  */
670 #define BOOST_LOG_DECLARE_LOGGER_TYPE(type_name, char_type, base_seq, threading)\
671     class type_name :\
672         public ::boost::log::sources::basic_composite_logger<\
673             char_type,\
674             type_name,\
675             threading,\
676             ::boost::log::sources::features< BOOST_PP_SEQ_ENUM(base_seq) >\
677         >\
678     {\
679         BOOST_LOG_FORWARD_LOGGER_MEMBERS(type_name)\
680     }
681 
682 
683 
684 #ifdef BOOST_LOG_USE_CHAR
685 
686 /*!
687  *  \brief The macro declares a narrow-char logger class that inherits a number of base classes
688  *
689  *  Equivalent to BOOST_LOG_DECLARE_LOGGER_TYPE(type_name, char, base_seq, single_thread_model)
690  *
691  *  \param type_name The name of the logger class to declare
692  *  \param base_seq A Boost.Preprocessor sequence of type identifiers of the base classes templates
693  */
694 #define BOOST_LOG_DECLARE_LOGGER(type_name, base_seq)\
695     BOOST_LOG_DECLARE_LOGGER_TYPE(type_name, char, base_seq, ::boost::log::sources::single_thread_model)
696 
697 #if !defined(BOOST_LOG_NO_THREADS)
698 
699 /*!
700  *  \brief The macro declares a narrow-char thread-safe logger class that inherits a number of base classes
701  *
702  *  Equivalent to <tt>BOOST_LOG_DECLARE_LOGGER_TYPE(type_name, char, base_seq, multi_thread_model< shared_mutex >)</tt>
703  *
704  *  \param type_name The name of the logger class to declare
705  *  \param base_seq A Boost.Preprocessor sequence of type identifiers of the base classes templates
706  */
707 #define BOOST_LOG_DECLARE_LOGGER_MT(type_name, base_seq)\
708     BOOST_LOG_DECLARE_LOGGER_TYPE(type_name, char, base_seq,\
709         ::boost::log::sources::multi_thread_model< ::boost::shared_mutex >)
710 
711 #endif // !defined(BOOST_LOG_NO_THREADS)
712 #endif // BOOST_LOG_USE_CHAR
713 
714 #ifdef BOOST_LOG_USE_WCHAR_T
715 
716 /*!
717  *  \brief The macro declares a wide-char logger class that inherits a number of base classes
718  *
719  *  Equivalent to BOOST_LOG_DECLARE_LOGGER_TYPE(type_name, wchar_t, base_seq, single_thread_model)
720  *
721  *  \param type_name The name of the logger class to declare
722  *  \param base_seq A Boost.Preprocessor sequence of type identifiers of the base classes templates
723  */
724 #define BOOST_LOG_DECLARE_WLOGGER(type_name, base_seq)\
725     BOOST_LOG_DECLARE_LOGGER_TYPE(type_name, wchar_t, base_seq, ::boost::log::sources::single_thread_model)
726 
727 #if !defined(BOOST_LOG_NO_THREADS)
728 
729 /*!
730  *  \brief The macro declares a wide-char thread-safe logger class that inherits a number of base classes
731  *
732  *  Equivalent to <tt>BOOST_LOG_DECLARE_LOGGER_TYPE(type_name, wchar_t, base_seq, multi_thread_model< shared_mutex >)</tt>
733  *
734  *  \param type_name The name of the logger class to declare
735  *  \param base_seq A Boost.Preprocessor sequence of type identifiers of the base classes templates
736  */
737 #define BOOST_LOG_DECLARE_WLOGGER_MT(type_name, base_seq)\
738     BOOST_LOG_DECLARE_LOGGER_TYPE(type_name, wchar_t, base_seq,\
739         ::boost::log::sources::multi_thread_model< ::boost::shared_mutex >)
740 
741 #endif // !defined(BOOST_LOG_NO_THREADS)
742 #endif // BOOST_LOG_USE_WCHAR_T
743 
744 #include <boost/log/detail/footer.hpp>
745 
746 #endif // BOOST_LOG_SOURCES_BASIC_LOGGER_HPP_INCLUDED_
747