PageRenderTime 52ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 0ms

/hpx/util/logging/format.hpp

https://github.com/hkaiser/hpx
C++ Header | 610 lines | 314 code | 84 blank | 212 comment | 28 complexity | bea9464363b42ffe2d8856d986689a1c MD5 | raw file
  1. // format.hpp
  2. // Boost Logging library
  3. //
  4. // Author: John Torjo, www.torjo.com
  5. //
  6. // Copyright (C) 2007 John Torjo (see www.torjo.com for email)
  7. //
  8. // Distributed under the Boost Software License, Version 1.0.
  9. // (See accompanying file LICENSE_1_0.txt or copy at
  10. // http://www.boost.org/LICENSE_1_0.txt)
  11. //
  12. // See http://www.boost.org for updates, documentation, and revision history.
  13. // See http://www.torjo.com/log2/ for more details
  14. // this is fixed!
  15. #ifndef JT28092007_format_HPP_DEFINED
  16. #define JT28092007_format_HPP_DEFINED
  17. #if defined(_MSC_VER) && (_MSC_VER >= 1020)
  18. # pragma once
  19. #endif
  20. #include <hpx/util/assert.hpp>
  21. #include <hpx/util/logging/detail/fwd.hpp>
  22. #include <hpx/util/logging/detail/forward_constructor.hpp>
  23. #include <hpx/util/logging/detail/manipulator.hpp>
  24. #include <hpx/util/logging/format_fwd.hpp>
  25. #include <hpx/util/logging/format/op_equal.hpp>
  26. #include <hpx/util/logging/format/array.hpp>
  27. #include <vector>
  28. #include <set>
  29. #include <boost/shared_ptr.hpp>
  30. #include <boost/type_traits/is_base_of.hpp>
  31. namespace hpx { namespace util { namespace logging {
  32. /**
  33. @file hpx/util/logging/format.hpp
  34. Include this file when you're using @ref manipulator "formatters and destinations",
  35. and you want to define the logger classes, in a source file
  36. (using HPX_DEFINE_LOG)
  37. */
  38. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  39. // Format and write
  40. //
  41. /**
  42. @brief The @c %format_and_write classes know how to call the formatter and destination @c objects.
  43. Usually you'll be happy with the
  44. format_and_write::simple class - which simply calls @c operator() on the formatters , and @c operator() on the destinations.
  45. Note that usually the formatter and destination class just have an @c operator(), which when called, formats the message
  46. or writes it to a destination. In case your formatters/destinations are more complex than that (for instance, more than
  47. a member function needs to be called), you'll have to implement your own %format_and_write class.
  48. */
  49. namespace format_and_write {
  50. /**
  51. @brief This uses a cache, when calling formatters/destinations - for writing a given message
  52. When a formatter is called, it caches its info. If it's called again, reuses that.
  53. */
  54. template<class formatter_base, class destination_base, class msg_type>
  55. struct use_cache {
  56. use_cache( msg_type & msg) : m_msg(msg) {}
  57. typedef typename formatter_base::ptr_type formatter_ptr;
  58. typedef typename destination_base::ptr_type destination_ptr;
  59. typedef std::set<formatter_ptr> format_set;
  60. void format(formatter_ptr const &fmt) {
  61. if ( m_formats.find( fmt) == m_formats.end()) {
  62. m_formats.insert( fmt);
  63. (*fmt)(m_msg);
  64. m_msg.set_last_id( fmt);
  65. }
  66. else
  67. m_msg.reuse( fmt);
  68. }
  69. void write(destination_ptr const & dest) {
  70. (*dest)(m_msg);
  71. }
  72. void clear_format() {
  73. m_msg.restart();
  74. }
  75. private:
  76. msg_type &m_msg;
  77. format_set m_formats;
  78. };
  79. /**
  80. @brief Formats the message, and writes it to destinations - calls @c operator() on the formatters , and @c operator() on the destinations. Ignores @c clear_format() commands.
  81. @param msg_type The message to pass to the formatter. This is the type that is passed to the formatter objects and to the destination objects.
  82. Thus, it needs to be convertible to the argument to be sent to the formatter objects and to the argument to be sent to the destination objects.
  83. Usually, it's the argument you pass on to your destination classes.
  84. If you derive from @c destination::base, this type can be @c destination::base::raw_param (see below).
  85. Example:
  86. @code
  87. typedef destination::base<const std::string &> dest_base;
  88. // in this case : msg_type = std::string = dest_base::raw_param
  89. struct write_to_cout : dest_base {
  90. void operator()(param msg) const {
  91. std::cout << msg ;
  92. }
  93. };
  94. typedef destination::base<const std::string &> dest_base;
  95. // in this case : msg_type = cache_string = dest_base::raw_param
  96. struct write_to_file : dest_base, ... {
  97. void operator()(param msg) const {
  98. context() << msg ;
  99. }
  100. };
  101. @endcode
  102. */
  103. template<class msg_type>
  104. struct simple {
  105. simple ( msg_type & msg) : m_msg(msg) {}
  106. template<class formatter_ptr> void format(const formatter_ptr & fmt) {
  107. (*fmt)(m_msg);
  108. }
  109. template<class destination_ptr> void write(const destination_ptr & dest) {
  110. (*dest)(m_msg);
  111. }
  112. void clear_format() {}
  113. protected:
  114. msg_type &m_msg;
  115. };
  116. /**
  117. @brief Formats the message, and writes it to destinations - calls @c operator() on the formatters , and @c operator() on the destinations.
  118. Cares for the @c clear_format() commands.
  119. @param msg_type The message to pass to the formatter. This is the type that is passed to the formatter objects and to the destination objects.
  120. Thus, it needs to be convertible to the argument to be sent to the formatter objects and to the argument to be sent to the destination objects.
  121. Usually, it's the argument you pass on to your destination classes.
  122. If you derive from @c destination::base, this type can be @c destination::base::raw_param (see below).
  123. @param string_type [optional] A class that can hold a string (that is, a copy of the message)
  124. Example:
  125. @code
  126. typedef destination::base<const std::string &> dest_base;
  127. // in this case : msg_type = std::string = dest_base::raw_param
  128. struct write_to_cout : dest_base {
  129. void operator()(param msg) const {
  130. std::cout << msg ;
  131. }
  132. };
  133. typedef destination::base<const std::string &> dest_base;
  134. // in this case : msg_type = cache_string = dest_base::raw_param
  135. struct write_to_file : dest_base, ... {
  136. void operator()(param msg) const {
  137. context() << msg ;
  138. }
  139. };
  140. @endcode
  141. */
  142. template<class msg_type, class string_type = hold_string_type>
  143. struct simple_care_for_clear_format : simple<msg_type> {
  144. typedef simple<msg_type> simple_base_type;
  145. simple_care_for_clear_format( msg_type & msg) : simple_base_type(msg), m_original_msg( msg ) {}
  146. void clear_format() {
  147. simple_base_type::m_msg = m_original_msg;
  148. }
  149. private:
  150. msg_type m_original_msg;
  151. };
  152. } // namespace format_and_write
  153. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  154. // Message routing
  155. //
  156. /**
  157. @brief Specifies the route : how formatting and writing to destinations take place.
  158. Classes in this namespace specify when formatters and destinations are to be called.
  159. @sa msg_route::simple, msg_route::with_route
  160. */
  161. namespace msg_route {
  162. /**
  163. @brief Recomended base class for message routers that need access to the underlying formatter and/or destination array.
  164. */
  165. template<class formatter_array, class destination_array>
  166. struct formatter_and_destination_array_holder {
  167. protected:
  168. formatter_and_destination_array_holder (const formatter_array & formats_,
  169. const destination_array & destinations_)
  170. : m_formats(formats_), m_destinations(destinations_) {}
  171. const formatter_array & formats() const { return m_formats; }
  172. const destination_array & destinations() const { return m_destinations; }
  173. private:
  174. const formatter_array & m_formats;
  175. const destination_array & m_destinations;
  176. };
  177. /**
  178. @brief Represents a simple router - first calls all formatters - in the order they were added, then all destinations - in the order they were added
  179. Example:
  180. @code
  181. typedef logger< gather::ostream_like::return_str<> , format_write<...> > logger_type;
  182. HPX_DEFINE_LOG_FILTER(g_log_filter, filter::no_ts )
  183. HPX_DEFINE_LOG(g_l, logger_type)
  184. #define L_ HPX_LOG_USE_LOG_IF_FILTER(g_l(), g_log_filter()->is_enabled() )
  185. // add formatters : [idx] [time] message [enter]
  186. g_l()->writer().add_formatter( write_idx() );
  187. g_l()->writer().add_formatter( write_time() );
  188. g_l()->writer().add_formatter( append_newline() );
  189. // write to cout and file
  190. g_l()->writer().add_destination( write_to_cout() );
  191. g_l()->writer().add_destination( write_to_file("out.txt") );
  192. // usage
  193. int i = 1;
  194. L_ << "testing " << i << i+1 << i+2;
  195. @endcode
  196. In the above case:
  197. - First, the formatters are called: @c write_idx() is called, then @c write_time(), then @c append_newline().
  198. - Then, the destinations are called: @c write_to_cout(), and then @c write_to_file().
  199. @param format_base The base class for all formatter classes from your application. See manipulator.
  200. @param destination_base The base class for all destination classes from your application. See manipulator.
  201. @param lock_resource_type What class you use to do allow thread-safe access to an instance of this clas (used internally).
  202. */
  203. template<
  204. class formatter_base,
  205. class destination_base,
  206. class lock_resource = default_ >
  207. struct simple {
  208. typedef typename formatter_base::ptr_type formatter_ptr;
  209. typedef typename destination_base::ptr_type destination_ptr;
  210. typedef typename detail::to_override<formatter_base>::type override_;
  211. typedef typename use_default<lock_resource, typename hpx::util::logging::types<override_>::lock_resource > ::type lock_resource_type;
  212. typedef std::vector<formatter_ptr> f_array;
  213. typedef std::vector<destination_ptr> d_array;
  214. struct write_info {
  215. f_array formats;
  216. d_array destinations;
  217. };
  218. typedef typename lock_resource_type::template finder<write_info>::type data;
  219. template<class formatter_array, class destination_array> simple(const formatter_array&, const destination_array&) {}
  220. void append_formatter(formatter_ptr fmt) {
  221. typename data::write to_write(m_to_write);
  222. to_write->formats.push_back(fmt);
  223. }
  224. void del_formatter(formatter_ptr fmt) {
  225. typename data::write to_write(m_to_write);
  226. typename f_array::iterator del = std::remove(to_write->formats.begin(), to_write->formats.end(), fmt);
  227. to_write->formats.erase(del, to_write->formats.end());
  228. }
  229. void append_destination(destination_ptr dest) {
  230. typename data::write to_write(m_to_write);
  231. to_write->destinations.push_back(dest);
  232. }
  233. void del_destination(destination_ptr dest) {
  234. typename data::write to_write(m_to_write);
  235. typename d_array::iterator del = std::remove(to_write->destinations.begin(), to_write->destinations.end(), dest);
  236. to_write->destinations.erase(del, to_write->destinations.end());
  237. }
  238. template<class format_and_write, class msg_type> void write(msg_type & msg) const {
  239. format_and_write m(msg);
  240. // note: here, we're reading (data::read)!
  241. typename data::read to_write(m_to_write);
  242. for ( typename f_array::const_iterator b_f = to_write->formats.begin(), e_f = to_write->formats.end(); b_f != e_f; ++b_f)
  243. m.format(*b_f);
  244. for ( typename d_array::const_iterator b_d = to_write->destinations.begin(), e_d = to_write->destinations.end(); b_d != e_d; ++b_d)
  245. m.write(*b_d);
  246. }
  247. private:
  248. data m_to_write;
  249. };
  250. /**
  251. @brief. Represents a router - by default, first calls all formatters, then all destinations. However you can overwrite this route
  252. You can append a route - with append_route(), or set the route with set_route().
  253. Example:
  254. @code
  255. typedef logger< default_,
  256. writer::format_write< format_base, destination_base, format_and_write::simple<cache_string>,
  257. msg_route::with_route<format_base,destination_base> > > logger_type;
  258. logger_type g_l();
  259. g_l()->writer().router().set_route()
  260. .fmt( formatter::time() )
  261. .fmt( formatter::append_newline() )
  262. .dest( destination::dbg_window() )
  263. .fmt( formatter::write_idx() )
  264. .dest( destination::cout() )
  265. .clear()
  266. .fmt( formatter::write_idx() )
  267. .fmt( formatter::append_newline() )
  268. .fmt( formatter::write_to_file())
  269. ;
  270. @endcode
  271. @param format_base The base class for all formatter classes from your application. See manipulator.
  272. @param destination_base The base class for all destination classes from your application. See manipulator.
  273. @remarks In the router - we don't own the objects - the array holder does that
  274. */
  275. template<
  276. class formatter_base,
  277. class destination_base,
  278. class lock_resource = default_ ,
  279. // note: we're counting on these defaults in format_find_writer
  280. class formatter_array = hpx::util::logging::array::shared_ptr_holder<formatter_base>,
  281. class destination_array = hpx::util::logging::array::shared_ptr_holder<destination_base>
  282. >
  283. class with_route : protected formatter_and_destination_array_holder<formatter_array, destination_array> {
  284. typedef typename formatter_base::ptr_type formatter_ptr;
  285. typedef typename destination_base::ptr_type destination_ptr;
  286. typedef typename detail::to_override<formatter_base>::type override_;
  287. typedef typename use_default<lock_resource, typename hpx::util::logging::types<override_>::lock_resource > ::type lock_resource_type;
  288. typedef formatter_and_destination_array_holder<formatter_array, destination_array> holder_base_type;
  289. typedef with_route<formatter_base, destination_base, lock_resource_type, formatter_array, destination_array> self_type;
  290. typedef std::vector<formatter_ptr> f_array;
  291. typedef std::vector<destination_ptr> d_array;
  292. struct write_once {
  293. write_once() : do_clear_afterwards(false) {}
  294. f_array formats;
  295. d_array destinations;
  296. // if true, will execute clear_format() after calling all of the above
  297. bool do_clear_afterwards;
  298. };
  299. typedef std::vector<write_once> write_array;
  300. typedef typename lock_resource_type::template finder<write_array>::type data;
  301. public:
  302. with_route(const formatter_array& formatters, const destination_array & destinations) : holder_base_type(formatters, destinations) {}
  303. class route;
  304. friend class route;
  305. /**
  306. represents a formatter/destination route to be added/set.
  307. */
  308. class route {
  309. friend class with_route;
  310. enum type {
  311. is_fmt, is_dest, is_clear
  312. };
  313. struct item {
  314. item() : m_fmt(0), m_dest(0), m_type(is_clear) {}
  315. item& fmt(formatter_ptr f) {
  316. HPX_ASSERT(f);
  317. m_fmt = f; m_type = is_fmt; return *this;
  318. }
  319. item &dest(destination_ptr d) {
  320. HPX_ASSERT(d);
  321. m_dest = d; m_type = is_dest; return *this;
  322. }
  323. formatter_ptr m_fmt;
  324. destination_ptr m_dest;
  325. type m_type;
  326. };
  327. typedef std::vector<item> array;
  328. protected:
  329. route(self_type & self) : m_self(self) {}
  330. public:
  331. template<class formatter> route & fmt(formatter f) {
  332. fmt_impl(f, boost::is_base_of<hpx::util::logging::manipulator::is_generic,formatter>() );
  333. return *this;
  334. }
  335. template<class destination> route & dest(destination d) {
  336. dest_impl(d, boost::is_base_of<hpx::util::logging::manipulator::is_generic,destination>() );
  337. return *this;
  338. }
  339. route & clear() {
  340. m_items.push_back( item() );
  341. return *this;
  342. }
  343. private:
  344. // not generic
  345. template<class formatter> void fmt_impl(formatter f, const boost::false_type& ) {
  346. m_items.push_back( item().fmt( m_self.formats().get_ptr(f) )) ;
  347. }
  348. // not generic
  349. template<class destination> void dest_impl(destination d, const boost::false_type&) {
  350. m_items.push_back( item().dest( m_self.destinations().get_ptr(d) ));
  351. }
  352. // generic
  353. template<class formatter> void fmt_impl(formatter f, const boost::true_type& ) {
  354. typedef hpx::util::logging::manipulator::detail::generic_holder<formatter,formatter_base> holder;
  355. fmt_impl( holder(f) , boost::false_type() );
  356. }
  357. // generic
  358. template<class destination> void dest_impl(destination d, const boost::true_type&) {
  359. typedef hpx::util::logging::manipulator::detail::generic_holder<destination,destination_base> holder;
  360. dest_impl( holder(d) , boost::false_type() );
  361. }
  362. protected:
  363. self_type & m_self;
  364. array m_items;
  365. };
  366. struct route_do_set;
  367. friend struct route_do_set;
  368. struct route_do_set : route {
  369. route_do_set(self_type &self) : route(self) {}
  370. ~route_do_set() {
  371. route::m_self.do_set_route( *this);
  372. }
  373. };
  374. struct route_do_append;
  375. friend struct route_do_append;
  376. struct route_do_append : route {
  377. route_do_append(self_type &self) : route(self) {}
  378. ~route_do_append() {
  379. route::m_self.do_append_route( *this);
  380. }
  381. };
  382. /**
  383. sets this as the route for logging
  384. */
  385. route_do_set set_route() { return route_do_set(*this); }
  386. /**
  387. appends this route
  388. */
  389. route_do_append append_route() { return route_do_append(*this); }
  390. void append_formatter(formatter_ptr fmt) {
  391. typename data::write to_write(m_to_write);
  392. if ( to_write->empty() )
  393. to_write->push_back( write_once() );
  394. // we need to add it a the end; if there are any destinations,
  395. // we need to add it after those
  396. bool can_append_to_back = to_write->back().destinations.empty();
  397. if ( !can_append_to_back)
  398. to_write->push_back( write_once() );
  399. to_write->back().formats.push_back(fmt);
  400. }
  401. void del_formatter(formatter_ptr fmt) {
  402. typename data::write to_write(m_to_write);
  403. for ( typename write_array::const_iterator b = to_write->begin(), e = to_write->end(); b != e; ++b) {
  404. typename f_array::iterator del = std::remove( b->formats.begin(), b->formats.end(), fmt); //-V807
  405. b->formats.erase(del, b->formats.end());
  406. }
  407. }
  408. void append_destination(destination_ptr dest) {
  409. typename data::write to_write(m_to_write);
  410. if ( to_write->empty() )
  411. to_write->push_back( write_once() );
  412. if ( to_write->back().do_clear_afterwards)
  413. // after clear, always start a new write
  414. to_write->push_back( write_once() );
  415. to_write->back().destinations.push_back(dest);
  416. }
  417. void del_destination(destination_ptr dest) {
  418. typename data::write to_write(m_to_write);
  419. for ( typename write_array::const_iterator b = to_write->begin(), e = to_write->end(); b != e; ++b) {
  420. typename d_array::iterator del = std::remove( b->destinations.begin(), b->destinations.end(), dest); //-V807
  421. b->destinations.erase(del, b->destinations.end());
  422. // if from a write_once - all destinations are gone, don't clear_afterwards
  423. if ( b->destinations.empty() )
  424. b->do_clear_afterwards = false;
  425. }
  426. }
  427. void append_clear_format() {
  428. typename data::write to_write(m_to_write);
  429. if ( to_write->empty() )
  430. to_write->push_back( write_once() );
  431. to_write->back().do_clear_afterwards = true;
  432. to_write->push_back( write_once() );
  433. }
  434. template<class format_and_write, class msg_type> void write(msg_type & msg) const {
  435. format_and_write m(msg);
  436. // note: here, we're reading (data::read)!
  437. typename data::read to_write(m_to_write);
  438. for ( typename write_array::const_iterator b = to_write->begin(), e = to_write->end(); b != e; ++b) {
  439. for ( typename f_array::const_iterator b_f = b->formats.begin(), e_f = b->formats.end(); b_f != e_f; ++b_f)
  440. m.format(*b_f);
  441. for ( typename d_array::const_iterator b_d = b->destinations.begin(), e_d = b->destinations.end(); b_d != e_d; ++b_d)
  442. m.write(*b_d);
  443. if ( b->do_clear_afterwards)
  444. m.clear_format();
  445. }
  446. }
  447. private:
  448. void do_append_route(const route & r) {
  449. if ( r.m_items.empty() )
  450. return; // no route to add
  451. typedef typename route::array array;
  452. for ( typename array::const_iterator b = r.m_items.begin(), e = r.m_items.end(); b != e; ++b) {
  453. switch ( b->m_type) {
  454. case route::is_fmt: append_formatter( b->m_fmt); break;
  455. case route::is_dest: append_destination( b->m_dest); break;
  456. break;
  457. case route::is_clear: append_clear_format(); break;
  458. break;
  459. }
  460. }
  461. }
  462. void do_set_route(const route & r) {
  463. {
  464. typename data::write to_write(m_to_write);
  465. to_write->clear();
  466. }
  467. do_append_route(r);
  468. }
  469. private:
  470. data m_to_write;
  471. };
  472. } // namespace msg_route
  473. }}}
  474. #include <hpx/util/logging/detail/manipulator.hpp>
  475. #include <hpx/util/logging/detail/format_write_detail.hpp>
  476. #include <hpx/util/logging/format/formatter/defaults.hpp>
  477. #include <hpx/util/logging/format/destination/defaults.hpp>
  478. #include <hpx/util/logging/gather/ostream_like.hpp>
  479. #if !defined(HPX_LOG_NO_TS)
  480. #include <hpx/util/logging/writer/ts_write.hpp>
  481. #endif
  482. #endif