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