• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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