• 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   record_ostream.hpp
9  * \author Andrey Semashev
10  * \date   09.03.2009
11  *
12  * This header contains a wrapper class around a logging record that allows to compose the
13  * record message with a streaming expression.
14  */
15 
16 #ifndef BOOST_LOG_SOURCES_RECORD_OSTREAM_HPP_INCLUDED_
17 #define BOOST_LOG_SOURCES_RECORD_OSTREAM_HPP_INCLUDED_
18 
19 #include <string>
20 #include <iosfwd>
21 #include <ostream>
22 #include <boost/assert.hpp>
23 #include <boost/move/core.hpp>
24 #include <boost/move/utility_core.hpp>
25 #include <boost/type_traits/is_enum.hpp>
26 #include <boost/type_traits/is_scalar.hpp>
27 #include <boost/type_traits/remove_cv.hpp>
28 #include <boost/core/addressof.hpp>
29 #include <boost/core/enable_if.hpp>
30 #include <boost/core/explicit_operator_bool.hpp>
31 #include <boost/core/uncaught_exceptions.hpp>
32 #include <boost/log/detail/config.hpp>
33 #include <boost/log/detail/native_typeof.hpp>
34 #include <boost/log/core/record.hpp>
35 #include <boost/log/utility/unique_identifier_name.hpp>
36 #include <boost/log/utility/formatting_ostream.hpp>
37 #include <boost/log/detail/header.hpp>
38 
39 #ifdef BOOST_HAS_PRAGMA_ONCE
40 #pragma once
41 #endif
42 
43 namespace boost {
44 
45 BOOST_LOG_OPEN_NAMESPACE
46 
47 template< typename CharT >
48 class basic_record_ostream;
49 
50 namespace aux {
51 
52 template< typename StreamT, typename T, bool ByValueV, typename R >
53 struct enable_record_ostream_generic_operator {};
54 
55 template< typename CharT, typename T, typename R >
56 struct enable_record_ostream_generic_operator< basic_record_ostream< CharT >, T, false, R > :
57     public boost::disable_if_c< boost::is_scalar< typename boost::remove_cv< T >::type >::value, R >
58 {
59 };
60 
61 template< typename CharT, typename T, typename R >
62 struct enable_record_ostream_generic_operator< basic_record_ostream< CharT >, T, true, R > :
63     public boost::enable_if_c< boost::is_enum< typename boost::remove_cv< T >::type >::value, R >
64 {
65 };
66 
67 template< typename CharT, typename T, typename R >
68 struct enable_record_ostream_generic_operator< basic_record_ostream< CharT >, T*, true, R > :
69     public disable_if_streamable_char_type< typename boost::remove_cv< T >::type, R >
70 {
71 };
72 
73 } // namespace aux
74 
75 /*!
76  * \brief Logging record adapter with a streaming capability
77  *
78  * This class allows to compose the logging record message by streaming operations. It
79  * aggregates the log record and provides the standard output stream interface.
80  */
81 template< typename CharT >
82 class basic_record_ostream :
83     public basic_formatting_ostream< CharT >
84 {
85     //! Self type
86     typedef basic_record_ostream< CharT > this_type;
87     //! Base stream class
88     typedef basic_formatting_ostream< CharT > base_type;
89 
90 public:
91     //! Character type
92     typedef CharT char_type;
93     //! String type to be used as a message text holder
94     typedef std::basic_string< char_type > string_type;
95     //! Stream type
96     typedef std::basic_ostream< char_type > stream_type;
97     //! Character traits
98     typedef typename base_type::traits_type traits_type;
99 
100 private:
101     //! Log record
102     record* m_record;
103 
104 public:
105     /*!
106      * Default constructor. Creates an empty record that is equivalent to the invalid record handle.
107      * The stream capability is not available after construction.
108      *
109      * \post <tt>!*this == true</tt>
110      */
basic_record_ostream()111     basic_record_ostream() BOOST_NOEXCEPT : m_record(NULL) {}
112 
113     /*!
114      * Constructor from a record object. Attaches to the provided record.
115      *
116      * \pre <tt>!!rec == true</tt>
117      * \post <tt>&this->get_record() == &rec</tt>
118      * \param rec The record handle being attached to
119      */
basic_record_ostream(record & rec)120     explicit basic_record_ostream(record& rec)
121     {
122         BOOST_ASSERT_MSG(!!rec, "Boost.Log: basic_record_ostream should only be attached to a valid record");
123         m_record = &rec;
124         init_stream();
125     }
126 
127     /*!
128      * Destructor. Destroys the record, releases any sinks and attribute values that were involved in processing this record.
129      */
~basic_record_ostream()130     ~basic_record_ostream() BOOST_NOEXCEPT
131     {
132         detach_from_record();
133     }
134 
135     /*!
136      * Conversion to an unspecified boolean type
137      *
138      * \return \c true, if stream is valid and ready for formatting, \c false, if the stream is not valid. The latter also applies to
139      *         the case when the stream is not attached to a log record.
140      */
141     BOOST_EXPLICIT_OPERATOR_BOOL_NOEXCEPT()
142 
143     /*!
144      * Inverted conversion to an unspecified boolean type
145      *
146      * \return \c false, if stream is valid and ready for formatting, \c true, if the stream is not valid. The latter also applies to
147      *         the case when the stream is not attached to a log record.
148      */
149     bool operator! () const BOOST_NOEXCEPT
150     {
151         return (!m_record || base_type::fail());
152     }
153 
154     /*!
155      * Flushes internal buffers to complete all pending formatting operations and returns the aggregated log record
156      *
157      * \return The aggregated record object
158      */
get_record()159     record& get_record()
160     {
161         BOOST_ASSERT(m_record != NULL);
162         this->flush();
163         return *m_record;
164     }
165 
166     /*!
167      * Flushes internal buffers to complete all pending formatting operations and returns the aggregated log record
168      *
169      * \return The aggregated record object
170      */
get_record() const171     record const& get_record() const
172     {
173         BOOST_ASSERT(m_record != NULL);
174         const_cast< this_type* >(this)->flush();
175         return *m_record;
176     }
177 
178     /*!
179      * If the stream is attached to a log record, flushes internal buffers to complete all pending formatting operations.
180      * Then reattaches the stream to another log record.
181      *
182      * \param rec New log record to attach to
183      */
attach_record(record & rec)184     void attach_record(record& rec)
185     {
186         BOOST_ASSERT_MSG(!!rec, "Boost.Log: basic_record_ostream should only be attached to a valid record");
187         detach_from_record();
188         m_record = &rec;
189         init_stream();
190     }
191 
192     //! The function resets the stream into a detached (default initialized) state
193     BOOST_LOG_API void detach_from_record() BOOST_NOEXCEPT;
194 
operator <<(typename base_type::ios_base_manip manip)195     basic_record_ostream& operator<< (typename base_type::ios_base_manip manip)
196     {
197         static_cast< base_type& >(*this) << manip;
198         return *this;
199     }
operator <<(typename base_type::basic_ios_manip manip)200     basic_record_ostream& operator<< (typename base_type::basic_ios_manip manip)
201     {
202         static_cast< base_type& >(*this) << manip;
203         return *this;
204     }
operator <<(typename base_type::stream_manip manip)205     basic_record_ostream& operator<< (typename base_type::stream_manip manip)
206     {
207         static_cast< base_type& >(*this) << manip;
208         return *this;
209     }
210 
operator <<(char c)211     basic_record_ostream& operator<< (char c)
212     {
213         static_cast< base_type& >(*this) << c;
214         return *this;
215     }
operator <<(const char * p)216     basic_record_ostream& operator<< (const char* p)
217     {
218         static_cast< base_type& >(*this) << p;
219         return *this;
220     }
221 
222     // When no native character type is supported, the following overloads are disabled as they have ambiguous meaning.
223     // Use basic_string_view or basic_string to explicitly indicate that the data is a string.
224 #if !defined(BOOST_NO_INTRINSIC_WCHAR_T)
operator <<(wchar_t c)225     basic_record_ostream& operator<< (wchar_t c)
226     {
227         static_cast< base_type& >(*this) << c;
228         return *this;
229     }
operator <<(const wchar_t * p)230     basic_record_ostream& operator<< (const wchar_t* p)
231     {
232         static_cast< base_type& >(*this) << p;
233         return *this;
234     }
235 #endif
236 #if !defined(BOOST_LOG_NO_CXX11_CODECVT_FACETS)
237 #if !defined(BOOST_NO_CXX11_CHAR16_T)
operator <<(char16_t c)238     basic_record_ostream& operator<< (char16_t c)
239     {
240         static_cast< base_type& >(*this) << c;
241         return *this;
242     }
operator <<(const char16_t * p)243     basic_record_ostream& operator<< (const char16_t* p)
244     {
245         static_cast< base_type& >(*this) << p;
246         return *this;
247     }
248 #endif
249 #if !defined(BOOST_NO_CXX11_CHAR32_T)
operator <<(char32_t c)250     basic_record_ostream& operator<< (char32_t c)
251     {
252         static_cast< base_type& >(*this) << c;
253         return *this;
254     }
operator <<(const char32_t * p)255     basic_record_ostream& operator<< (const char32_t* p)
256     {
257         static_cast< base_type& >(*this) << p;
258         return *this;
259     }
260 #endif
261 #endif
262 
operator <<(bool value)263     basic_record_ostream& operator<< (bool value)
264     {
265         static_cast< base_type& >(*this) << value;
266         return *this;
267     }
operator <<(signed char value)268     basic_record_ostream& operator<< (signed char value)
269     {
270         static_cast< base_type& >(*this) << value;
271         return *this;
272     }
operator <<(unsigned char value)273     basic_record_ostream& operator<< (unsigned char value)
274     {
275         static_cast< base_type& >(*this) << value;
276         return *this;
277     }
operator <<(short value)278     basic_record_ostream& operator<< (short value)
279     {
280         static_cast< base_type& >(*this) << value;
281         return *this;
282     }
operator <<(unsigned short value)283     basic_record_ostream& operator<< (unsigned short value)
284     {
285         static_cast< base_type& >(*this) << value;
286         return *this;
287     }
operator <<(int value)288     basic_record_ostream& operator<< (int value)
289     {
290         static_cast< base_type& >(*this) << value;
291         return *this;
292     }
operator <<(unsigned int value)293     basic_record_ostream& operator<< (unsigned int value)
294     {
295         static_cast< base_type& >(*this) << value;
296         return *this;
297     }
operator <<(long value)298     basic_record_ostream& operator<< (long value)
299     {
300         static_cast< base_type& >(*this) << value;
301         return *this;
302     }
operator <<(unsigned long value)303     basic_record_ostream& operator<< (unsigned long value)
304     {
305         static_cast< base_type& >(*this) << value;
306         return *this;
307     }
308 #if !defined(BOOST_NO_LONG_LONG)
operator <<(long long value)309     basic_record_ostream& operator<< (long long value)
310     {
311         static_cast< base_type& >(*this) << value;
312         return *this;
313     }
operator <<(unsigned long long value)314     basic_record_ostream& operator<< (unsigned long long value)
315     {
316         static_cast< base_type& >(*this) << value;
317         return *this;
318     }
319 #endif
320 
operator <<(float value)321     basic_record_ostream& operator<< (float value)
322     {
323         static_cast< base_type& >(*this) << value;
324         return *this;
325     }
operator <<(double value)326     basic_record_ostream& operator<< (double value)
327     {
328         static_cast< base_type& >(*this) << value;
329         return *this;
330     }
operator <<(long double value)331     basic_record_ostream& operator<< (long double value)
332     {
333         static_cast< base_type& >(*this) << value;
334         return *this;
335     }
336 
operator <<(std::basic_streambuf<char_type,traits_type> * buf)337     basic_record_ostream& operator<< (std::basic_streambuf< char_type, traits_type >* buf)
338     {
339         static_cast< base_type& >(*this) << buf;
340         return *this;
341     }
342 
343 private:
344     //! The function initializes the stream and the stream buffer
345     BOOST_LOG_API void init_stream();
346 
347     //  Copy and assignment are closed
348     BOOST_DELETED_FUNCTION(basic_record_ostream(basic_record_ostream const&))
349     BOOST_DELETED_FUNCTION(basic_record_ostream& operator= (basic_record_ostream const&))
350 };
351 
352 
353 #ifdef BOOST_LOG_USE_CHAR
354 typedef basic_record_ostream< char > record_ostream;        //!< Convenience typedef for narrow-character logging
355 #endif
356 #ifdef BOOST_LOG_USE_WCHAR_T
357 typedef basic_record_ostream< wchar_t > wrecord_ostream;    //!< Convenience typedef for wide-character logging
358 #endif
359 
360 // Implementation note: these operators below should be the least attractive for the compiler
361 // so that user's overloads are chosen, when present. We use function template partial ordering for this purpose.
362 // We also don't use perfect forwarding for the right hand argument because in ths case the generic overload
363 // would be more preferred than the typical one written by users:
364 //
365 // record_ostream& operator<< (record_ostream& strm, my_type const& arg);
366 //
367 // This is because my_type rvalues require adding const to the type, which counts as a conversion that is not required
368 // if there is a perfect forwarding overload.
369 template< typename StreamT, typename T >
370 inline typename boost::log::aux::enable_record_ostream_generic_operator< StreamT, T, true, StreamT& >::type
operator <<(StreamT & strm,T value)371 operator<< (StreamT& strm, T value)
372 {
373     typedef basic_formatting_ostream< typename StreamT::char_type > formatting_ostream_type;
374     static_cast< formatting_ostream_type& >(strm) << value;
375     return strm;
376 }
377 
378 template< typename StreamT, typename T >
379 inline typename boost::log::aux::enable_record_ostream_generic_operator< StreamT, T, false, StreamT& >::type
operator <<(StreamT & strm,T const & value)380 operator<< (StreamT& strm, T const& value)
381 {
382     typedef basic_formatting_ostream< typename StreamT::char_type > formatting_ostream_type;
383     static_cast< formatting_ostream_type& >(strm) << value;
384     return strm;
385 }
386 
387 template< typename StreamT, typename T >
388 inline typename boost::log::aux::enable_record_ostream_generic_operator< StreamT, T, false, StreamT& >::type
operator <<(StreamT & strm,T & value)389 operator<< (StreamT& strm, T& value)
390 {
391     typedef basic_formatting_ostream< typename StreamT::char_type > formatting_ostream_type;
392     static_cast< formatting_ostream_type& >(strm) << value;
393     return strm;
394 }
395 
396 #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
397 
398 template< typename StreamT, typename T >
399 inline typename boost::log::aux::enable_record_ostream_generic_operator< StreamT, T, true, StreamT& >::type
operator <<(StreamT && strm,T value)400 operator<< (StreamT&& strm, T value)
401 {
402     typedef basic_formatting_ostream< typename StreamT::char_type > formatting_ostream_type;
403     static_cast< formatting_ostream_type& >(strm) << value;
404     return strm;
405 }
406 
407 template< typename StreamT, typename T >
408 inline typename boost::log::aux::enable_record_ostream_generic_operator< StreamT, T, false, StreamT& >::type
operator <<(StreamT && strm,T const & value)409 operator<< (StreamT&& strm, T const& value)
410 {
411     typedef basic_formatting_ostream< typename StreamT::char_type > formatting_ostream_type;
412     static_cast< formatting_ostream_type& >(strm) << value;
413     return strm;
414 }
415 
416 template< typename StreamT, typename T >
417 inline typename boost::log::aux::enable_record_ostream_generic_operator< StreamT, T, false, StreamT& >::type
operator <<(StreamT && strm,T & value)418 operator<< (StreamT&& strm, T& value)
419 {
420     typedef basic_formatting_ostream< typename StreamT::char_type > formatting_ostream_type;
421     static_cast< formatting_ostream_type& >(strm) << value;
422     return strm;
423 }
424 
425 #endif // !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
426 
427 namespace aux {
428 
429 //! Internal class that provides formatting streams for record pumps
430 template< typename CharT >
431 struct stream_provider
432 {
433     //! Character type
434     typedef CharT char_type;
435 
436     //! Formatting stream compound
437     struct stream_compound
438     {
439         stream_compound* next;
440 
441         //! Log record stream adapter
442         basic_record_ostream< char_type > stream;
443 
444         //! Initializing constructor
stream_compoundboost::aux::stream_provider::stream_compound445         explicit stream_compound(record& rec) : next(NULL), stream(rec) {}
446     };
447 
448     //! The method returns an allocated stream compound
449     BOOST_LOG_API static stream_compound* allocate_compound(record& rec);
450     //! The method releases a compound
451     BOOST_LOG_API static void release_compound(stream_compound* compound) BOOST_NOEXCEPT;
452 
453     //  Non-constructible, non-copyable, non-assignable
454     BOOST_DELETED_FUNCTION(stream_provider())
455     BOOST_DELETED_FUNCTION(stream_provider(stream_provider const&))
456     BOOST_DELETED_FUNCTION(stream_provider& operator= (stream_provider const&))
457 };
458 
459 
460 /*!
461  * \brief Logging record pump implementation
462  *
463  * The pump is used to format the logging record message text and then
464  * push it to the logging core. It is constructed on each attempt to write
465  * a log record and destroyed afterwards.
466  *
467  * The pump class template is instantiated on the logger type.
468  */
469 template< typename LoggerT >
470 class record_pump
471 {
472     BOOST_MOVABLE_BUT_NOT_COPYABLE(record_pump)
473 
474 private:
475     //! Logger type
476     typedef LoggerT logger_type;
477     //! Character type
478     typedef typename logger_type::char_type char_type;
479     //! Stream compound provider
480     typedef stream_provider< char_type > stream_provider_type;
481     //! Stream compound type
482     typedef typename stream_provider_type::stream_compound stream_compound;
483 
484     //! Stream compound release guard
485     class auto_release;
486     friend class auto_release;
487     class auto_release
488     {
489         stream_compound* m_pCompound;
490 
491     public:
auto_release(stream_compound * p)492         explicit auto_release(stream_compound* p) BOOST_NOEXCEPT : m_pCompound(p) {}
~auto_release()493         ~auto_release() BOOST_NOEXCEPT { stream_provider_type::release_compound(m_pCompound); }
494     };
495 
496 protected:
497     //! A reference to the logger
498     logger_type* m_pLogger;
499     //! Stream compound
500     stream_compound* m_pStreamCompound;
501     //! Exception state
502     const unsigned int m_ExceptionCount;
503 
504 public:
505     //! Constructor
record_pump(logger_type & lg,record & rec)506     explicit record_pump(logger_type& lg, record& rec) :
507         m_pLogger(boost::addressof(lg)),
508         m_pStreamCompound(stream_provider_type::allocate_compound(rec)),
509         m_ExceptionCount(boost::core::uncaught_exceptions())
510     {
511     }
512     //! Move constructor
record_pump(BOOST_RV_REF (record_pump)that)513     record_pump(BOOST_RV_REF(record_pump) that) BOOST_NOEXCEPT :
514         m_pLogger(that.m_pLogger),
515         m_pStreamCompound(that.m_pStreamCompound),
516         m_ExceptionCount(that.m_ExceptionCount)
517     {
518         that.m_pLogger = 0;
519         that.m_pStreamCompound = 0;
520     }
521     //! Destructor. Pushes the composed message to log.
BOOST_NOEXCEPT_IF(false)522     ~record_pump() BOOST_NOEXCEPT_IF(false)
523     {
524         if (m_pLogger)
525         {
526             auto_release cleanup(m_pStreamCompound); // destructor doesn't throw
527             // Only push the record if no exception has been thrown in the streaming expression (if possible)
528             if (m_ExceptionCount >= boost::core::uncaught_exceptions())
529                 m_pLogger->push_record(boost::move(m_pStreamCompound->stream.get_record()));
530         }
531     }
532 
533     //! Returns the stream to be used for message text formatting
stream() const534     basic_record_ostream< char_type >& stream() const BOOST_NOEXCEPT
535     {
536         BOOST_ASSERT(m_pStreamCompound != 0);
537         return m_pStreamCompound->stream;
538     }
539 };
540 
541 template< typename LoggerT >
make_record_pump(LoggerT & lg,record & rec)542 BOOST_FORCEINLINE record_pump< LoggerT > make_record_pump(LoggerT& lg, record& rec)
543 {
544     return record_pump< LoggerT >(lg, rec);
545 }
546 
547 } // namespace aux
548 
549 #ifndef BOOST_LOG_DOXYGEN_PASS
550 
551 #define BOOST_LOG_STREAM_INTERNAL(logger, rec_var)\
552     for (::boost::log::record rec_var = (logger).open_record(); !!rec_var;)\
553         ::boost::log::aux::make_record_pump((logger), rec_var).stream()
554 
555 #define BOOST_LOG_STREAM_WITH_PARAMS_INTERNAL(logger, rec_var, params_seq)\
556     for (::boost::log::record rec_var = (logger).open_record((BOOST_PP_SEQ_ENUM(params_seq))); !!rec_var;)\
557         ::boost::log::aux::make_record_pump((logger), rec_var).stream()
558 
559 #endif // BOOST_LOG_DOXYGEN_PASS
560 
561 //! The macro writes a record to the log
562 #define BOOST_LOG_STREAM(logger)\
563     BOOST_LOG_STREAM_INTERNAL(logger, BOOST_LOG_UNIQUE_IDENTIFIER_NAME(_boost_log_record_))
564 
565 //! The macro writes a record to the log and allows to pass additional named arguments to the logger
566 #define BOOST_LOG_STREAM_WITH_PARAMS(logger, params_seq)\
567     BOOST_LOG_STREAM_WITH_PARAMS_INTERNAL(logger, BOOST_LOG_UNIQUE_IDENTIFIER_NAME(_boost_log_record_), params_seq)
568 
569 #ifndef BOOST_LOG_NO_SHORTHAND_NAMES
570 
571 //! An equivalent to BOOST_LOG_STREAM(logger)
572 #define BOOST_LOG(logger) BOOST_LOG_STREAM(logger)
573 
574 //! An equivalent to BOOST_LOG_STREAM_WITH_PARAMS(logger, params_seq)
575 #define BOOST_LOG_WITH_PARAMS(logger, params_seq) BOOST_LOG_STREAM_WITH_PARAMS(logger, params_seq)
576 
577 #endif // BOOST_LOG_NO_SHORTHAND_NAMES
578 
579 BOOST_LOG_CLOSE_NAMESPACE // namespace log
580 
581 } // namespace boost
582 
583 #include <boost/log/detail/footer.hpp>
584 
585 #endif // BOOST_LOG_SOURCES_RECORD_OSTREAM_HPP_INCLUDED_
586