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 event_log_backend.hpp 9 * \author Andrey Semashev 10 * \date 07.11.2008 11 * 12 * The header contains a logging sink backend that uses Windows NT event log API 13 * for signaling application events. 14 */ 15 16 #ifndef BOOST_LOG_SINKS_EVENT_LOG_BACKEND_HPP_INCLUDED_ 17 #define BOOST_LOG_SINKS_EVENT_LOG_BACKEND_HPP_INCLUDED_ 18 19 #include <boost/log/detail/config.hpp> 20 21 #ifdef BOOST_HAS_PRAGMA_ONCE 22 #pragma once 23 #endif 24 25 #ifndef BOOST_LOG_WITHOUT_EVENT_LOG 26 27 #include <map> 28 #include <vector> 29 #include <string> 30 #include <iosfwd> 31 #include <boost/filesystem/path.hpp> 32 #include <boost/log/detail/light_function.hpp> 33 #include <boost/log/detail/parameter_tools.hpp> 34 #include <boost/log/attributes/attribute_value_set.hpp> 35 #include <boost/log/keywords/message_file.hpp> 36 #include <boost/log/keywords/log_name.hpp> 37 #include <boost/log/keywords/log_source.hpp> 38 #include <boost/log/keywords/registration.hpp> 39 #include <boost/log/keywords/target.hpp> 40 #include <boost/log/sinks/basic_sink_backend.hpp> 41 #include <boost/log/sinks/frontend_requirements.hpp> 42 #include <boost/log/sinks/attribute_mapping.hpp> 43 #include <boost/log/sinks/event_log_constants.hpp> 44 #include <boost/log/core/record_view.hpp> 45 #include <boost/log/expressions/formatter.hpp> 46 #include <boost/log/detail/header.hpp> 47 48 namespace boost { 49 50 BOOST_LOG_OPEN_NAMESPACE 51 52 namespace sinks { 53 54 namespace event_log { 55 56 //! Event log source registration modes 57 enum registration_mode 58 { 59 never, //!< Never register event source, even if it's not registered 60 on_demand, //!< Register if the source is not registered yet 61 forced //!< Register always, event if the source is already registered 62 }; 63 64 /*! 65 * \brief Straightforward event type mapping 66 * 67 * This type of mapping assumes that attribute with a particular name always 68 * provides values that map directly onto the native event types. The mapping 69 * simply returns the extracted attribute value converted to the native event type. 70 */ 71 template< typename AttributeValueT = int > 72 class direct_event_type_mapping : 73 public basic_direct_mapping< event_type, AttributeValueT > 74 { 75 //! Base type 76 typedef basic_direct_mapping< event_type, AttributeValueT > base_type; 77 78 public: 79 /*! 80 * Constructor 81 * 82 * \param name Attribute name 83 */ direct_event_type_mapping(attribute_name const & name)84 explicit direct_event_type_mapping(attribute_name const& name) : 85 base_type(name, info) 86 { 87 } 88 }; 89 90 /*! 91 * \brief Customizable event type mapping 92 * 93 * The class allows to setup a custom mapping between an attribute and native event types. 94 * The mapping should be initialized similarly to the standard \c map container, by using 95 * indexing operator and assignment. 96 */ 97 template< typename AttributeValueT = int > 98 class custom_event_type_mapping : 99 public basic_custom_mapping< event_type, AttributeValueT > 100 { 101 //! Base type 102 typedef basic_custom_mapping< event_type, AttributeValueT > base_type; 103 104 public: 105 /*! 106 * Constructor 107 * 108 * \param name Attribute name 109 */ custom_event_type_mapping(attribute_name const & name)110 explicit custom_event_type_mapping(attribute_name const& name) : 111 base_type(name, info) 112 { 113 } 114 }; 115 116 /*! 117 * \brief Straightforward event ID mapping 118 * 119 * This type of mapping assumes that attribute with a particular name always 120 * provides values that map directly onto the event identifiers. The mapping 121 * simply returns the extracted attribute value converted to the event ID. 122 */ 123 template< typename AttributeValueT = int > 124 class direct_event_id_mapping : 125 public basic_direct_mapping< event_id, AttributeValueT > 126 { 127 //! Base type 128 typedef basic_direct_mapping< event_id, AttributeValueT > base_type; 129 130 public: 131 /*! 132 * Constructor 133 * 134 * \param name Attribute name 135 */ direct_event_id_mapping(attribute_name const & name)136 explicit direct_event_id_mapping(attribute_name const& name) : 137 base_type(name, make_event_id(0)) 138 { 139 } 140 }; 141 142 /*! 143 * \brief Customizable event ID mapping 144 * 145 * The class allows to setup a custom mapping between an attribute and event identifiers. 146 * The mapping should be initialized similarly to the standard \c map container, by using 147 * indexing operator and assignment. 148 */ 149 template< typename AttributeValueT = int > 150 class custom_event_id_mapping : 151 public basic_custom_mapping< event_id, AttributeValueT > 152 { 153 //! Base type 154 typedef basic_custom_mapping< event_id, AttributeValueT > base_type; 155 156 public: 157 /*! 158 * Constructor 159 * 160 * \param name Attribute name 161 */ custom_event_id_mapping(attribute_name const & name)162 explicit custom_event_id_mapping(attribute_name const& name) : 163 base_type(name, make_event_id(0)) 164 { 165 } 166 }; 167 168 /*! 169 * \brief Straightforward event category mapping 170 * 171 * This type of mapping assumes that attribute with a particular name always 172 * provides values that map directly onto the event categories. The mapping 173 * simply returns the extracted attribute value converted to the event category. 174 */ 175 template< typename AttributeValueT = int > 176 class direct_event_category_mapping : 177 public basic_direct_mapping< event_category, AttributeValueT > 178 { 179 //! Base type 180 typedef basic_direct_mapping< event_category, AttributeValueT > base_type; 181 182 public: 183 /*! 184 * Constructor 185 * 186 * \param name Attribute name 187 */ direct_event_category_mapping(attribute_name const & name)188 explicit direct_event_category_mapping(attribute_name const& name) : 189 base_type(name, make_event_category(0)) 190 { 191 } 192 }; 193 194 /*! 195 * \brief Customizable event category mapping 196 * 197 * The class allows to setup a custom mapping between an attribute and event categories. 198 * The mapping should be initialized similarly to the standard \c map container, by using 199 * indexing operator and assignment. 200 */ 201 template< typename AttributeValueT = int > 202 class custom_event_category_mapping : 203 public basic_custom_mapping< event_category, AttributeValueT > 204 { 205 //! Base type 206 typedef basic_custom_mapping< event_category, AttributeValueT > base_type; 207 208 public: 209 /*! 210 * Constructor 211 * 212 * \param name Attribute name 213 */ custom_event_category_mapping(attribute_name const & name)214 explicit custom_event_category_mapping(attribute_name const& name) : 215 base_type(name, make_event_category(0)) 216 { 217 } 218 }; 219 220 /*! 221 * \brief An event composer 222 * 223 * This class is a function object that extracts event identifier from the attribute values set 224 * and formats insertion strings for the particular event. Each insertion string is formatted with 225 * a distinct formatter, which can be created just like regular sinks formatters. 226 * 227 * Before using, the composer must be initialized with the following information: 228 * \li Event identifier extraction logic. One can use \c basic_direct_event_id_mapping or 229 * \c basic_custom_event_id_mapping classes in order to create such extractor and pass it 230 * to the composer constructor. 231 * \li Event identifiers and insertion string formatters. The composer provides the following 232 * syntax to provide this information: 233 * 234 * \code 235 * event_composer comp; 236 * comp[MY_EVENT_ID1] % formatter1 % ... % formatterN; 237 * comp[MY_EVENT_ID2] % formatter1 % ... % formatterN; 238 * ... 239 * \endcode 240 * 241 * The event identifiers in square brackets are provided by the message compiler generated 242 * header (the actual names are specified in the .mc file). The formatters represent 243 * the insertion strings that will be used to replace placeholders in event messages, 244 * thus the number and the order of the formatters must correspond to the message definition. 245 */ 246 template< typename CharT > 247 class BOOST_LOG_API basic_event_composer 248 { 249 public: 250 //! Character type 251 typedef CharT char_type; 252 //! String type to be used as a message text holder 253 typedef std::basic_string< char_type > string_type; 254 255 //! Event identifier mapper type 256 typedef boost::log::aux::light_function< event_id (record_view const&) > event_id_mapper_type; 257 258 //! Type of an insertion composer (a formatter) 259 typedef basic_formatter< char_type > formatter_type; 260 //! Type of the composed insertions list 261 typedef std::vector< string_type > insertion_list; 262 263 private: 264 //! \cond 265 266 //! The class that implements formatting of insertion strings 267 class insertion_composer; 268 269 //! Type of the events map 270 typedef std::map< event_id, insertion_composer > event_map; 271 272 //! A smart reference that puts formatters into the composer 273 class event_map_reference; 274 friend class event_map_reference; 275 class event_map_reference 276 { 277 private: 278 //! Event identifier 279 event_id m_ID; 280 //! A reference to the object that created the reference 281 basic_event_composer< char_type >& m_Owner; 282 //! A hint for the owner to optimize insertion 283 insertion_composer* m_Composer; 284 285 public: 286 //! Initializing constructor event_map_reference(event_id id,basic_event_composer<char_type> & owner)287 explicit event_map_reference(event_id id, basic_event_composer< char_type >& owner) : 288 m_ID(id), 289 m_Owner(owner), 290 m_Composer(0) 291 { 292 } 293 //! The operator puts the formatter into the composer 294 template< typename FormatterT > operator %(FormatterT const & fmt)295 event_map_reference& operator% (FormatterT const& fmt) 296 { 297 m_Composer = m_Owner.add_formatter(m_ID, m_Composer, formatter_type(fmt)); 298 return *this; 299 } 300 }; 301 302 //! \endcond 303 304 private: 305 //! The mapper that will extract the event identifier 306 event_id_mapper_type m_EventIDMapper; 307 //! The map of event identifiers and their insertion composers 308 event_map m_EventMap; 309 310 public: 311 /*! 312 * Default constructor. Creates an empty map of events. 313 * 314 * \param id_mapper An event identifier mapping function that will be used to extract event ID from attribute values 315 */ 316 explicit basic_event_composer(event_id_mapper_type const& id_mapper); 317 /*! 318 * Copy constructor. Performs a deep copy of the object. 319 */ 320 basic_event_composer(basic_event_composer const& that); 321 /*! 322 * Destructor 323 */ 324 ~basic_event_composer(); 325 326 /*! 327 * Assignment. Provides strong exception guarantee. 328 */ 329 basic_event_composer& operator= (basic_event_composer that); 330 /*! 331 * Swaps \c *this and \c that objects. 332 */ 333 void swap(basic_event_composer& that); 334 /*! 335 * Initiates creation of a new event description. The result of the operator can be used to 336 * add formatters for insertion strings construction. The returned reference type is implementation detail. 337 * 338 * \param id Event identifier. 339 */ 340 event_map_reference operator[] (event_id id); 341 /*! 342 * Initiates creation of a new event description. The result of the operator can be used to 343 * add formatters for insertion strings construction. The returned reference type is implementation detail. 344 * 345 * \param id Event identifier. 346 */ 347 event_map_reference operator[] (int id); 348 /*! 349 * Event composition operator. Extracts an event identifier from the attribute values by calling event ID mapper. 350 * Then runs all formatters that were registered for the event with the extracted ID. The results of formatting 351 * are returned in the \a insertions parameter. 352 * 353 * \param rec Log record view 354 * \param insertions A sequence of formatted insertion strings 355 * \return An event identifier that was extracted from \c attributes 356 */ 357 event_id operator() (record_view const& rec, insertion_list& insertions) const; 358 359 private: 360 #ifndef BOOST_LOG_DOXYGEN_PASS 361 //! Adds a formatter to the insertion composers list 362 insertion_composer* add_formatter(event_id id, insertion_composer* composer, formatter_type const& fmt); 363 #endif // BOOST_LOG_DOXYGEN_PASS 364 }; 365 366 #ifdef BOOST_LOG_USE_CHAR 367 typedef basic_event_composer< char > event_composer; //!< Convenience typedef for narrow-character logging 368 #endif 369 #ifdef BOOST_LOG_USE_WCHAR_T 370 typedef basic_event_composer< wchar_t > wevent_composer; //!< Convenience typedef for wide-character logging 371 #endif 372 373 } // namespace event_log 374 375 /*! 376 * \brief An implementation of a simple logging sink backend that emits events into Windows NT event log 377 * 378 * The sink uses Windows NT 5 (Windows 2000) and later event log API to emit events 379 * to an event log. The sink acts as an event source in terms of the API, it implements all needed resources 380 * and source registration in the Windows registry that is needed for the event delivery. 381 * 382 * The backend performs message text formatting. The composed text is then passed as the first 383 * and only string parameter of the event. The resource embedded into the backend describes the event 384 * so that the parameter is inserted into the event description text, thus making it visible 385 * in the event log. 386 * 387 * The backend allows to customize mapping of application severity levels to the native Windows event types. 388 * This allows to write portable code even if OS-specific sinks, such as this one, are used. 389 * 390 * \note Since the backend registers itself into Windows registry as the resource file that contains 391 * event description, it is important to keep the library binary in a stable place of the filesystem. 392 * Otherwise Windows might not be able to load event resources from the library and display 393 * events correctly. 394 * 395 * \note It is known that Windows is not able to find event resources in the application executable, 396 * which is linked against the static build of the library. Users are advised to use dynamic 397 * builds of the library to solve this problem. 398 */ 399 template< typename CharT > 400 class basic_simple_event_log_backend : 401 public basic_formatted_sink_backend< CharT, concurrent_feeding > 402 { 403 //! Base type 404 typedef basic_formatted_sink_backend< CharT, concurrent_feeding > base_type; 405 //! Implementation type 406 struct implementation; 407 408 public: 409 //! Character type 410 typedef typename base_type::char_type char_type; 411 //! String type to be used as a message text holder 412 typedef typename base_type::string_type string_type; 413 414 //! Mapper type for the event type 415 typedef boost::log::aux::light_function< event_log::event_type (record_view const&) > event_type_mapper_type; 416 417 private: 418 //! Pointer to the backend implementation that hides various types from windows.h 419 implementation* m_pImpl; 420 421 public: 422 /*! 423 * Default constructor. Registers event source with name based on the application 424 * executable file name in the Application log. If such a registration is already 425 * present, it is not overridden. 426 */ 427 BOOST_LOG_API basic_simple_event_log_backend(); 428 /*! 429 * Constructor. Registers event log source with the specified parameters. 430 * The following named parameters are supported: 431 * 432 * \li \c target - Specifies an UNC path to the remote server which log records should be sent to. 433 * The local machine will be used to process log records, if not specified. 434 * \li \c log_name - Specifies the log in which the source should be registered. 435 * The result of \c get_default_log_name is used, if the parameter is not specified. 436 * \li \c log_source - Specifies the source name. The result of \c get_default_source_name 437 * is used, if the parameter is not specified. 438 * \li \c registration - Specifies the event source registration mode in the Windows registry. 439 * Can have values of the \c registration_mode enum. Default value: \c on_demand. 440 * 441 * \param args A set of named parameters. 442 */ 443 #ifndef BOOST_LOG_DOXYGEN_PASS 444 BOOST_LOG_PARAMETRIZED_CONSTRUCTORS_CALL(basic_simple_event_log_backend, construct) 445 #else 446 template< typename... ArgsT > 447 explicit basic_simple_event_log_backend(ArgsT... const& args); 448 #endif 449 450 /*! 451 * Destructor. Unregisters event source. The log source description is not removed from the Windows registry. 452 */ 453 BOOST_LOG_API ~basic_simple_event_log_backend(); 454 455 /*! 456 * The method installs the function object that maps application severity levels to WinAPI event types 457 */ 458 BOOST_LOG_API void set_event_type_mapper(event_type_mapper_type const& mapper); 459 460 /*! 461 * \returns Default log name: Application 462 */ 463 BOOST_LOG_API static string_type get_default_log_name(); 464 /*! 465 * \returns Default log source name that is based on the application executable file name and the sink name 466 */ 467 BOOST_LOG_API static string_type get_default_source_name(); 468 469 /*! 470 * The method puts the formatted message to the event log 471 */ 472 BOOST_LOG_API void consume(record_view const& rec, string_type const& formatted_message); 473 474 private: 475 #ifndef BOOST_LOG_DOXYGEN_PASS 476 //! Constructs backend implementation 477 template< typename ArgsT > construct(ArgsT const & args)478 void construct(ArgsT const& args) 479 { 480 construct( 481 args[keywords::target | string_type()], 482 args[keywords::log_name || &basic_simple_event_log_backend::get_default_log_name], 483 args[keywords::log_source || &basic_simple_event_log_backend::get_default_source_name], 484 args[keywords::registration | event_log::on_demand]); 485 } 486 BOOST_LOG_API void construct( 487 string_type const& target, 488 string_type const& log_name, 489 string_type const& source_name, 490 event_log::registration_mode reg_mode); 491 #endif // BOOST_LOG_DOXYGEN_PASS 492 }; 493 494 /*! 495 * \brief An implementation of a logging sink backend that emits events into Windows NT event log 496 * 497 * The sink uses Windows NT 5 (Windows 2000) and later event log API to emit events 498 * to an event log. The sink acts as an event source. Unlike \c basic_simple_event_log_backend, 499 * this sink backend allows users to specify the custom event message file and supports 500 * mapping attribute values onto several insertion strings. Although it requires considerably 501 * more scaffolding than the simple backend, this allows to support localizable event descriptions. 502 * 503 * Besides the file name of the module with event resources, the backend provides the following 504 * customizations: 505 * \li Remote server UNC address, log name and source name. These parameters have similar meaning 506 * to \c basic_simple_event_log_backend. 507 * \li Event type and category mappings. These are function object that allow to map attribute 508 * values to the according event parameters. One can use mappings in the \c event_log namespace. 509 * \li Event composer. This function object extracts event identifier and formats string insertions, 510 * that will be used by the API to compose the final event message text. 511 */ 512 template< typename CharT > 513 class basic_event_log_backend : 514 public basic_sink_backend< synchronized_feeding > 515 { 516 //! Base type 517 typedef basic_sink_backend< synchronized_feeding > base_type; 518 //! Implementation type 519 struct implementation; 520 521 public: 522 //! Character type 523 typedef CharT char_type; 524 //! String type 525 typedef std::basic_string< char_type > string_type; 526 //! Type of the composed insertions list 527 typedef std::vector< string_type > insertion_list; 528 529 //! Mapper type for the event type 530 typedef boost::log::aux::light_function< event_log::event_type (record_view const&) > event_type_mapper_type; 531 //! Mapper type for the event category 532 typedef boost::log::aux::light_function< event_log::event_category (record_view const&) > event_category_mapper_type; 533 //! Event composer type 534 typedef boost::log::aux::light_function< event_log::event_id (record_view const&, insertion_list&) > event_composer_type; 535 536 private: 537 //! Pointer to the backend implementation that hides various types from windows.h 538 implementation* m_pImpl; 539 540 public: 541 /*! 542 * Constructor. Registers event source with name based on the application 543 * executable file name in the Application log. If such a registration is already 544 * present, it is not overridden. 545 */ 546 template< typename T > basic_event_log_backend(std::basic_string<T> const & message_file_name)547 explicit basic_event_log_backend(std::basic_string< T > const& message_file_name) 548 { 549 construct(keywords::message_file = message_file_name); 550 } 551 /*! 552 * Constructor. Registers event source with name based on the application 553 * executable file name in the Application log. If such a registration is already 554 * present, it is not overridden. 555 */ basic_event_log_backend(filesystem::path const & message_file_name)556 explicit basic_event_log_backend(filesystem::path const& message_file_name) 557 { 558 construct(keywords::message_file = message_file_name); 559 } 560 /*! 561 * Constructor. Registers event log source with the specified parameters. 562 * The following named parameters are supported: 563 * 564 * \li \c message_file - Specifies the file name that contains resources that 565 * describe events and categories. This parameter is mandatory unless \c registration is \c never. 566 * \li \c target - Specifies an UNC path to the remote server to which log records should be sent to. 567 * The local machine will be used to process log records, if not specified. 568 * \li \c log_name - Specifies the log in which the source should be registered. 569 * The result of \c get_default_log_name is used, if the parameter is not specified. 570 * \li \c log_source - Specifies the source name. The result of \c get_default_source_name 571 * is used, if the parameter is not specified. 572 * \li \c registration - Specifies the event source registration mode in the Windows registry. 573 * Can have values of the \c registration_mode enum. Default value: \c on_demand. 574 * 575 * \param args A set of named parameters. 576 */ 577 #ifndef BOOST_LOG_DOXYGEN_PASS 578 BOOST_LOG_PARAMETRIZED_CONSTRUCTORS_CALL(basic_event_log_backend, construct) 579 #else 580 template< typename... ArgsT > 581 explicit basic_event_log_backend(ArgsT... const& args); 582 #endif 583 584 /*! 585 * Destructor. Unregisters event source. The log source description is not removed from the Windows registry. 586 */ 587 BOOST_LOG_API ~basic_event_log_backend(); 588 589 /*! 590 * The method creates an event in the event log 591 * 592 * \param rec Log record to consume 593 */ 594 BOOST_LOG_API void consume(record_view const& rec); 595 596 /*! 597 * The method installs the function object that maps application severity levels to WinAPI event types 598 */ 599 BOOST_LOG_API void set_event_type_mapper(event_type_mapper_type const& mapper); 600 601 /*! 602 * The method installs the function object that extracts event category from attribute values 603 */ 604 BOOST_LOG_API void set_event_category_mapper(event_category_mapper_type const& mapper); 605 606 /*! 607 * The method installs the function object that extracts event identifier from the attributes and creates 608 * insertion strings that will replace placeholders in the event message. 609 */ 610 BOOST_LOG_API void set_event_composer(event_composer_type const& composer); 611 612 /*! 613 * \returns Default log name: Application 614 */ 615 BOOST_LOG_API static string_type get_default_log_name(); 616 /*! 617 * \returns Default log source name that is based on the application executable file name and the sink name 618 */ 619 BOOST_LOG_API static string_type get_default_source_name(); 620 621 private: 622 #ifndef BOOST_LOG_DOXYGEN_PASS 623 //! Constructs backend implementation 624 template< typename ArgsT > construct(ArgsT const & args)625 void construct(ArgsT const& args) 626 { 627 construct( 628 filesystem::path(args[keywords::message_file | filesystem::path()]), 629 args[keywords::target | string_type()], 630 args[keywords::log_name || &basic_event_log_backend::get_default_log_name], 631 args[keywords::log_source || &basic_event_log_backend::get_default_source_name], 632 args[keywords::registration | event_log::on_demand]); 633 } 634 BOOST_LOG_API void construct( 635 filesystem::path const& message_file_name, 636 string_type const& target, 637 string_type const& log_name, 638 string_type const& source_name, 639 event_log::registration_mode reg_mode); 640 #endif // BOOST_LOG_DOXYGEN_PASS 641 }; 642 643 #ifdef BOOST_LOG_USE_CHAR 644 typedef basic_simple_event_log_backend< char > simple_event_log_backend; //!< Convenience typedef for narrow-character logging 645 typedef basic_event_log_backend< char > event_log_backend; //!< Convenience typedef for narrow-character logging 646 #endif 647 #ifdef BOOST_LOG_USE_WCHAR_T 648 typedef basic_simple_event_log_backend< wchar_t > wsimple_event_log_backend; //!< Convenience typedef for wide-character logging 649 typedef basic_event_log_backend< wchar_t > wevent_log_backend; //!< Convenience typedef for wide-character logging 650 #endif 651 652 } // namespace sinks 653 654 BOOST_LOG_CLOSE_NAMESPACE // namespace log 655 656 } // namespace boost 657 658 #include <boost/log/detail/footer.hpp> 659 660 #endif // BOOST_LOG_WITHOUT_EVENT_LOG 661 662 #endif // BOOST_LOG_SINKS_EVENT_LOG_BACKEND_HPP_INCLUDED_ 663