record_ostream.hpp 19 KB

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