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