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)
8 * \file record_ostream.hpp
9 * \author Andrey Semashev
12 * This header contains a wrapper class around a logging record that allows to compose the
13 * record message with a streaming expression.
16 #ifndef BOOST_LOG_SOURCES_RECORD_OSTREAM_HPP_INCLUDED_
17 #define BOOST_LOG_SOURCES_RECORD_OSTREAM_HPP_INCLUDED_
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>
39 #ifdef BOOST_HAS_PRAGMA_ONCE
45 BOOST_LOG_OPEN_NAMESPACE
47 template< typename CharT >
48 class basic_record_ostream;
52 template< typename StreamT, typename T, bool ByValueV, typename R >
53 struct enable_record_ostream_generic_operator {};
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 >
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 >
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 >
76 * \brief Logging record adapter with a streaming capability
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.
81 template< typename CharT >
82 class basic_record_ostream :
83 public basic_formatting_ostream< CharT >
86 typedef basic_record_ostream< CharT > this_type;
88 typedef basic_formatting_ostream< CharT > base_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;
96 typedef std::basic_ostream< char_type > stream_type;
98 typedef typename base_type::traits_type traits_type;
106 * Default constructor. Creates an empty record that is equivalent to the invalid record handle.
107 * The stream capability is not available after construction.
109 * \post <tt>!*this == true</tt>
111 basic_record_ostream() BOOST_NOEXCEPT : m_record(NULL) {}
114 * Constructor from a record object. Attaches to the provided record.
116 * \pre <tt>!!rec == true</tt>
117 * \post <tt>&this->get_record() == &rec</tt>
118 * \param rec The record handle being attached to
120 explicit basic_record_ostream(record& rec)
122 BOOST_ASSERT_MSG(!!rec, "Boost.Log: basic_record_ostream should only be attached to a valid record");
128 * Destructor. Destroys the record, releases any sinks and attribute values that were involved in processing this record.
130 ~basic_record_ostream() BOOST_NOEXCEPT
132 detach_from_record();
136 * Conversion to an unspecified boolean type
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.
141 BOOST_EXPLICIT_OPERATOR_BOOL_NOEXCEPT()
144 * Inverted conversion to an unspecified boolean type
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.
149 bool operator! () const BOOST_NOEXCEPT
151 return (!m_record || base_type::fail());
155 * Flushes internal buffers to complete all pending formatting operations and returns the aggregated log record
157 * \return The aggregated record object
161 BOOST_ASSERT(m_record != NULL);
167 * Flushes internal buffers to complete all pending formatting operations and returns the aggregated log record
169 * \return The aggregated record object
171 record const& get_record() const
173 BOOST_ASSERT(m_record != NULL);
174 const_cast< this_type* >(this)->flush();
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.
182 * \param rec New log record to attach to
184 void attach_record(record& rec)
186 BOOST_ASSERT_MSG(!!rec, "Boost.Log: basic_record_ostream should only be attached to a valid record");
187 detach_from_record();
192 //! The function resets the stream into a detached (default initialized) state
193 BOOST_LOG_API void detach_from_record() BOOST_NOEXCEPT;
195 basic_record_ostream& operator<< (typename base_type::ios_base_manip manip)
197 static_cast< base_type& >(*this) << manip;
200 basic_record_ostream& operator<< (typename base_type::basic_ios_manip manip)
202 static_cast< base_type& >(*this) << manip;
205 basic_record_ostream& operator<< (typename base_type::stream_manip manip)
207 static_cast< base_type& >(*this) << manip;
211 basic_record_ostream& operator<< (char c)
213 static_cast< base_type& >(*this) << c;
216 basic_record_ostream& operator<< (const char* p)
218 static_cast< base_type& >(*this) << p;
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)
225 basic_record_ostream& operator<< (wchar_t c)
227 static_cast< base_type& >(*this) << c;
230 basic_record_ostream& operator<< (const wchar_t* p)
232 static_cast< base_type& >(*this) << p;
236 #if !defined(BOOST_LOG_NO_CXX11_CODECVT_FACETS)
237 #if !defined(BOOST_NO_CXX11_CHAR16_T)
238 basic_record_ostream& operator<< (char16_t c)
240 static_cast< base_type& >(*this) << c;
243 basic_record_ostream& operator<< (const char16_t* p)
245 static_cast< base_type& >(*this) << p;
249 #if !defined(BOOST_NO_CXX11_CHAR32_T)
250 basic_record_ostream& operator<< (char32_t c)
252 static_cast< base_type& >(*this) << c;
255 basic_record_ostream& operator<< (const char32_t* p)
257 static_cast< base_type& >(*this) << p;
263 basic_record_ostream& operator<< (bool value)
265 static_cast< base_type& >(*this) << value;
268 basic_record_ostream& operator<< (signed char value)
270 static_cast< base_type& >(*this) << value;
273 basic_record_ostream& operator<< (unsigned char value)
275 static_cast< base_type& >(*this) << value;
278 basic_record_ostream& operator<< (short value)
280 static_cast< base_type& >(*this) << value;
283 basic_record_ostream& operator<< (unsigned short value)
285 static_cast< base_type& >(*this) << value;
288 basic_record_ostream& operator<< (int value)
290 static_cast< base_type& >(*this) << value;
293 basic_record_ostream& operator<< (unsigned int value)
295 static_cast< base_type& >(*this) << value;
298 basic_record_ostream& operator<< (long value)
300 static_cast< base_type& >(*this) << value;
303 basic_record_ostream& operator<< (unsigned long value)
305 static_cast< base_type& >(*this) << value;
308 #if !defined(BOOST_NO_LONG_LONG)
309 basic_record_ostream& operator<< (long long value)
311 static_cast< base_type& >(*this) << value;
314 basic_record_ostream& operator<< (unsigned long long value)
316 static_cast< base_type& >(*this) << value;
321 basic_record_ostream& operator<< (float value)
323 static_cast< base_type& >(*this) << value;
326 basic_record_ostream& operator<< (double value)
328 static_cast< base_type& >(*this) << value;
331 basic_record_ostream& operator<< (long double value)
333 static_cast< base_type& >(*this) << value;
337 basic_record_ostream& operator<< (std::basic_streambuf< char_type, traits_type >* buf)
339 static_cast< base_type& >(*this) << buf;
344 //! The function initializes the stream and the stream buffer
345 BOOST_LOG_API void init_stream();
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&))
353 #ifdef BOOST_LOG_USE_CHAR
354 typedef basic_record_ostream< char > record_ostream; //!< Convenience typedef for narrow-character logging
356 #ifdef BOOST_LOG_USE_WCHAR_T
357 typedef basic_record_ostream< wchar_t > wrecord_ostream; //!< Convenience typedef for wide-character logging
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:
365 // record_ostream& operator<< (record_ostream& strm, my_type const& arg);
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
371 operator<< (StreamT& strm, T value)
373 typedef basic_formatting_ostream< typename StreamT::char_type > formatting_ostream_type;
374 static_cast< formatting_ostream_type& >(strm) << value;
378 template< typename StreamT, typename T >
379 inline typename boost::log::aux::enable_record_ostream_generic_operator< StreamT, T, false, StreamT& >::type
380 operator<< (StreamT& strm, T const& value)
382 typedef basic_formatting_ostream< typename StreamT::char_type > formatting_ostream_type;
383 static_cast< formatting_ostream_type& >(strm) << value;
387 template< typename StreamT, typename T >
388 inline typename boost::log::aux::enable_record_ostream_generic_operator< StreamT, T, false, StreamT& >::type
389 operator<< (StreamT& strm, T& value)
391 typedef basic_formatting_ostream< typename StreamT::char_type > formatting_ostream_type;
392 static_cast< formatting_ostream_type& >(strm) << value;
396 #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
398 template< typename StreamT, typename T >
399 inline typename boost::log::aux::enable_record_ostream_generic_operator< StreamT, T, true, StreamT& >::type
400 operator<< (StreamT&& strm, T value)
402 typedef basic_formatting_ostream< typename StreamT::char_type > formatting_ostream_type;
403 static_cast< formatting_ostream_type& >(strm) << value;
407 template< typename StreamT, typename T >
408 inline typename boost::log::aux::enable_record_ostream_generic_operator< StreamT, T, false, StreamT& >::type
409 operator<< (StreamT&& strm, T const& value)
411 typedef basic_formatting_ostream< typename StreamT::char_type > formatting_ostream_type;
412 static_cast< formatting_ostream_type& >(strm) << value;
416 template< typename StreamT, typename T >
417 inline typename boost::log::aux::enable_record_ostream_generic_operator< StreamT, T, false, StreamT& >::type
418 operator<< (StreamT&& strm, T& value)
420 typedef basic_formatting_ostream< typename StreamT::char_type > formatting_ostream_type;
421 static_cast< formatting_ostream_type& >(strm) << value;
425 #endif // !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
429 //! Internal class that provides formatting streams for record pumps
430 template< typename CharT >
431 struct stream_provider
434 typedef CharT char_type;
436 //! Formatting stream compound
437 struct stream_compound
439 stream_compound* next;
441 //! Log record stream adapter
442 basic_record_ostream< char_type > stream;
444 //! Initializing constructor
445 explicit stream_compound(record& rec) : next(NULL), stream(rec) {}
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;
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&))
461 * \brief Logging record pump implementation
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.
467 * The pump class template is instantiated on the logger type.
469 template< typename LoggerT >
472 BOOST_MOVABLE_BUT_NOT_COPYABLE(record_pump)
476 typedef LoggerT logger_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;
484 //! Stream compound release guard
486 friend class auto_release;
489 stream_compound* m_pCompound;
492 explicit auto_release(stream_compound* p) BOOST_NOEXCEPT : m_pCompound(p) {}
493 ~auto_release() BOOST_NOEXCEPT { stream_provider_type::release_compound(m_pCompound); }
497 //! A reference to the logger
498 logger_type* m_pLogger;
500 stream_compound* m_pStreamCompound;
502 const unsigned int m_ExceptionCount;
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())
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)
519 that.m_pStreamCompound = 0;
521 //! Destructor. Pushes the composed message to log.
522 ~record_pump() BOOST_NOEXCEPT_IF(false)
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()));
533 //! Returns the stream to be used for message text formatting
534 basic_record_ostream< char_type >& stream() const BOOST_NOEXCEPT
536 BOOST_ASSERT(m_pStreamCompound != 0);
537 return m_pStreamCompound->stream;
541 template< typename LoggerT >
542 BOOST_FORCEINLINE record_pump< LoggerT > make_record_pump(LoggerT& lg, record& rec)
544 return record_pump< LoggerT >(lg, rec);
549 #ifndef BOOST_LOG_DOXYGEN_PASS
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()
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()
559 #endif // BOOST_LOG_DOXYGEN_PASS
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_))
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)
569 #ifndef BOOST_LOG_NO_SHORTHAND_NAMES
571 //! An equivalent to BOOST_LOG_STREAM(logger)
572 #define BOOST_LOG(logger) BOOST_LOG_STREAM(logger)
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)
577 #endif // BOOST_LOG_NO_SHORTHAND_NAMES
579 BOOST_LOG_CLOSE_NAMESPACE // namespace log
583 #include <boost/log/detail/footer.hpp>
585 #endif // BOOST_LOG_SOURCES_RECORD_OSTREAM_HPP_INCLUDED_