Imported Upstream version 1.72.0
[platform/upstream/boost.git] / libs / log / src / setup / init_from_settings.cpp
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   init_from_settings.cpp
9  * \author Andrey Semashev
10  * \date   11.10.2009
11  *
12  * \brief  This header is the Boost.Log library implementation, see the library documentation
13  *         at http://www.boost.org/doc/libs/release/libs/log/doc/html/index.html.
14  */
15
16 #ifndef BOOST_LOG_WITHOUT_SETTINGS_PARSERS
17
18 #if defined(__GNUC__) && !(defined(__INTEL_COMPILER) || defined(__ICL) || defined(__ICC) || defined(__ECC)) \
19     && (__GNUC__ * 100 + __GNUC_MINOR__) >= 407
20 // This warning is caused by a compiler bug which is exposed when boost::optional is used: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=47679
21 // It has to be disabled here, before any code is included, since otherwise it doesn't help and the warning is still emitted.
22 // '*((void*)& foo +2)' may be used uninitialized in this function
23 #pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
24 #endif
25
26 #include <boost/log/detail/setup_config.hpp>
27 #include <cstddef>
28 #include <ios>
29 #include <map>
30 #include <vector>
31 #include <string>
32 #include <utility>
33 #include <iostream>
34 #include <typeinfo>
35 #include <stdexcept>
36 #include <algorithm>
37 #include <boost/type.hpp>
38 #include <boost/bind.hpp>
39 #include <boost/limits.hpp>
40 #include <boost/cstdint.hpp>
41 #include <boost/smart_ptr/make_shared_object.hpp>
42 #include <boost/core/null_deleter.hpp>
43 #include <boost/optional/optional.hpp>
44 #include <boost/filesystem/path.hpp>
45 #include <boost/date_time/date_defs.hpp>
46 #include <boost/property_tree/ptree.hpp>
47 #include <boost/mpl/if.hpp>
48 #include <boost/type_traits/is_unsigned.hpp>
49 #include <boost/spirit/home/qi/numeric/numeric_utils.hpp>
50 #include <boost/log/detail/code_conversion.hpp>
51 #include <boost/log/detail/singleton.hpp>
52 #include <boost/log/detail/default_attribute_names.hpp>
53 #include <boost/log/core.hpp>
54 #include <boost/log/sinks.hpp>
55 #include <boost/log/exceptions.hpp>
56 #include <boost/log/sinks/auto_newline_mode.hpp>
57 #include <boost/log/sinks/frontend_requirements.hpp>
58 #include <boost/log/expressions/filter.hpp>
59 #include <boost/log/expressions/formatter.hpp>
60 #include <boost/log/utility/string_literal.hpp>
61 #include <boost/log/utility/functional/nop.hpp>
62 #include <boost/log/utility/setup/from_settings.hpp>
63 #include <boost/log/utility/setup/filter_parser.hpp>
64 #include <boost/log/utility/setup/formatter_parser.hpp>
65 #if !defined(BOOST_LOG_NO_ASIO)
66 #include <boost/asio/ip/address.hpp>
67 #endif
68 #if !defined(BOOST_LOG_NO_THREADS)
69 #include <boost/log/detail/locks.hpp>
70 #include <boost/log/detail/light_rw_mutex.hpp>
71 #endif
72 #include "parser_utils.hpp"
73 #include "spirit_encoding.hpp"
74 #include <boost/log/detail/header.hpp>
75
76 namespace qi = boost::spirit::qi;
77
78 namespace boost {
79
80 BOOST_LOG_OPEN_NAMESPACE
81
82 BOOST_LOG_ANONYMOUS_NAMESPACE {
83
84 //! Throws an exception when a parameter value is not valid
85 BOOST_LOG_NORETURN void throw_invalid_value(const char* param_name)
86 {
87     std::string descr = std::string("Invalid parameter \"")
88                         + param_name
89                         + "\" value";
90     BOOST_LOG_THROW_DESCR(invalid_value, descr);
91 }
92
93 //! Extracts an integral value from parameter value
94 template< typename IntT, typename CharT >
95 inline IntT param_cast_to_int(const char* param_name, std::basic_string< CharT > const& value)
96 {
97     IntT res = 0;
98     typedef typename mpl::if_<
99         is_unsigned< IntT >,
100         qi::extract_uint< IntT, 10, 1, -1 >,
101         qi::extract_int< IntT, 10, 1, -1 >
102     >::type extract;
103     const CharT* begin = value.c_str(), *end = begin + value.size();
104     if (extract::call(begin, end, res) && begin == end)
105         return res;
106     else
107         throw_invalid_value(param_name);
108 }
109
110 //! Case-insensitive character comparison predicate
111 struct is_case_insensitive_equal
112 {
113     typedef bool result_type;
114
115     template< typename CharT >
116     result_type operator() (CharT left, CharT right) const BOOST_NOEXCEPT
117     {
118         typedef typename boost::log::aux::encoding< CharT >::type encoding;
119         return encoding::tolower(left) == encoding::tolower(right);
120     }
121 };
122
123 //! Extracts a boolean value from parameter value
124 template< typename CharT >
125 inline bool param_cast_to_bool(const char* param_name, std::basic_string< CharT > const& value)
126 {
127     typedef CharT char_type;
128     typedef boost::log::aux::char_constants< char_type > constants;
129     typedef boost::log::basic_string_literal< char_type > literal_type;
130
131     const char_type* begin = value.c_str(), *end = begin + value.size();
132     std::size_t len = end - begin;
133
134     literal_type keyword = constants::true_keyword();
135     if (keyword.size() == len && std::equal(begin, end, keyword.c_str(), is_case_insensitive_equal()))
136     {
137         return true;
138     }
139     else
140     {
141         keyword = constants::false_keyword();
142         if (keyword.size() == len && std::equal(begin, end, keyword.c_str(), is_case_insensitive_equal()))
143         {
144             return false;
145         }
146         else
147         {
148             return param_cast_to_int< unsigned int >(param_name, value) != 0;
149         }
150     }
151 }
152
153 //! Extracts an \c auto_newline_mode value from parameter value
154 template< typename CharT >
155 inline sinks::auto_newline_mode param_cast_to_auto_newline_mode(const char* param_name, std::basic_string< CharT > const& value)
156 {
157     typedef CharT char_type;
158     typedef boost::log::aux::char_constants< char_type > constants;
159
160     if (value == constants::auto_newline_mode_disabled())
161         return sinks::disabled_auto_newline;
162     else if (value == constants::auto_newline_mode_always_insert())
163         return sinks::always_insert;
164     else if (value == constants::auto_newline_mode_insert_if_missing())
165         return sinks::insert_if_missing;
166     else
167     {
168         BOOST_LOG_THROW_DESCR(invalid_value,
169             "Auto newline mode \"" + boost::log::aux::to_narrow(value) + "\" is not supported");
170     }
171 }
172
173 #if !defined(BOOST_LOG_NO_ASIO)
174 //! Extracts a network address from parameter value
175 template< typename CharT >
176 inline std::string param_cast_to_address(const char* param_name, std::basic_string< CharT > const& value)
177 {
178     return log::aux::to_narrow(value);
179 }
180 #endif // !defined(BOOST_LOG_NO_ASIO)
181
182 template< typename CharT >
183 inline bool is_weekday(const CharT* str, std::size_t len, boost::log::basic_string_literal< CharT > const& weekday, boost::log::basic_string_literal< CharT > const& short_weekday)
184 {
185     return (len == weekday.size() && std::equal(weekday.begin(), weekday.end(), str)) ||
186         (len == short_weekday.size() && std::equal(short_weekday.begin(), short_weekday.end(), str));
187 }
188
189 //! The function extracts the file rotation time point predicate from the parameter
190 template< typename CharT >
191 sinks::file::rotation_at_time_point param_cast_to_rotation_time_point(const char* param_name, std::basic_string< CharT > const& value)
192 {
193     typedef CharT char_type;
194     typedef boost::log::aux::char_constants< char_type > constants;
195     typedef typename boost::log::aux::encoding< char_type >::type encoding;
196     typedef qi::extract_uint< unsigned short, 10, 1, 2 > day_extract;
197     typedef qi::extract_uint< unsigned char, 10, 2, 2 > time_component_extract;
198
199     const char_type colon = static_cast< char_type >(':');
200     optional< date_time::weekdays > weekday;
201     optional< unsigned short > day;
202     unsigned char hour = 0, minute = 0, second = 0;
203     const char_type* begin = value.c_str(), *end = begin + value.size();
204
205     if (!encoding::isalnum(*begin)) // begin is null-terminated, so we also check that the string is not empty here
206         throw_invalid_value(param_name);
207
208     const char_type* p = begin + 1;
209     if (encoding::isalpha(*begin))
210     {
211         // This must be a weekday
212         while (encoding::isalpha(*p))
213             ++p;
214
215         std::size_t len = p - begin;
216         if (is_weekday(begin, len, constants::monday_keyword(), constants::short_monday_keyword()))
217             weekday = date_time::Monday;
218         else if (is_weekday(begin, len, constants::tuesday_keyword(), constants::short_tuesday_keyword()))
219             weekday = date_time::Tuesday;
220         else if (is_weekday(begin, len, constants::wednesday_keyword(), constants::short_wednesday_keyword()))
221             weekday = date_time::Wednesday;
222         else if (is_weekday(begin, len, constants::thursday_keyword(), constants::short_thursday_keyword()))
223             weekday = date_time::Thursday;
224         else if (is_weekday(begin, len, constants::friday_keyword(), constants::short_friday_keyword()))
225             weekday = date_time::Friday;
226         else if (is_weekday(begin, len, constants::saturday_keyword(), constants::short_saturday_keyword()))
227             weekday = date_time::Saturday;
228         else if (is_weekday(begin, len, constants::sunday_keyword(), constants::short_sunday_keyword()))
229             weekday = date_time::Sunday;
230         else
231             throw_invalid_value(param_name);
232     }
233     else
234     {
235         // This may be either a month day or an hour
236         while (encoding::isdigit(*p))
237             ++p;
238
239         if (encoding::isspace(*p))
240         {
241             // This is a month day
242             unsigned short mday = 0;
243             const char_type* b = begin;
244             if (!day_extract::call(b, p, mday) || b != p)
245                 throw_invalid_value(param_name);
246
247             day = mday;
248         }
249         else if (*p == colon)
250         {
251             // This is an hour, reset the pointer
252             p = begin;
253         }
254         else
255             throw_invalid_value(param_name);
256     }
257
258     // Skip spaces
259     while (encoding::isspace(*p))
260         ++p;
261
262     // Parse hour
263     if (!time_component_extract::call(p, end, hour) || *p != colon)
264         throw_invalid_value(param_name);
265     ++p;
266
267     // Parse minute
268     if (!time_component_extract::call(p, end, minute) || *p != colon)
269         throw_invalid_value(param_name);
270     ++p;
271
272     // Parse second
273     if (!time_component_extract::call(p, end, second) || p != end)
274         throw_invalid_value(param_name);
275
276     // Construct the predicate
277     if (weekday)
278         return sinks::file::rotation_at_time_point(weekday.get(), hour, minute, second);
279     else if (day)
280         return sinks::file::rotation_at_time_point(gregorian::greg_day(day.get()), hour, minute, second);
281     else
282         return sinks::file::rotation_at_time_point(hour, minute, second);
283 }
284
285 //! Base class for default sink factories
286 template< typename CharT >
287 class basic_default_sink_factory :
288     public sink_factory< CharT >
289 {
290 public:
291     typedef sink_factory< CharT > base_type;
292     typedef typename base_type::char_type char_type;
293     typedef typename base_type::string_type string_type;
294     typedef typename base_type::settings_section settings_section;
295     typedef boost::log::aux::char_constants< char_type > constants;
296
297 protected:
298     //! Sink backend character selection function
299     template< typename InitializerT >
300     static shared_ptr< sinks::sink > select_backend_character_type(settings_section const& params, InitializerT initializer)
301     {
302 #if defined(BOOST_LOG_USE_CHAR) && defined(BOOST_LOG_USE_WCHAR_T)
303         if (optional< string_type > wide_param = params["Wide"])
304         {
305             if (param_cast_to_bool("Wide", wide_param.get()))
306                 return initializer(params, type< wchar_t >());
307         }
308
309         return initializer(params, type< char >());
310 #elif defined(BOOST_LOG_USE_CHAR)
311         return initializer(params, type< char >());
312 #elif defined(BOOST_LOG_USE_WCHAR_T)
313         return initializer(params, type< wchar_t >());
314 #endif
315     }
316
317     //! The function initializes common parameters of a formatting sink and returns the constructed sink
318     template< typename BackendT >
319     static shared_ptr< sinks::sink > init_sink(shared_ptr< BackendT > const& backend, settings_section const& params)
320     {
321         typedef BackendT backend_t;
322         typedef typename sinks::has_requirement<
323             typename backend_t::frontend_requirements,
324             sinks::formatted_records
325         >::type is_formatting_t;
326
327         // Filter
328         filter filt;
329         if (optional< string_type > filter_param = params["Filter"])
330         {
331             filt = parse_filter(filter_param.get());
332         }
333
334         shared_ptr< sinks::basic_sink_frontend > p;
335
336 #if !defined(BOOST_LOG_NO_THREADS)
337         // Asynchronous. TODO: make it more flexible.
338         bool async = false;
339         if (optional< string_type > async_param = params["Asynchronous"])
340         {
341             async = param_cast_to_bool("Asynchronous", async_param.get());
342         }
343
344         // Construct the frontend, considering Asynchronous parameter
345         if (!async)
346         {
347             p = init_formatter(boost::make_shared< sinks::synchronous_sink< backend_t > >(backend), params, is_formatting_t());
348         }
349         else
350         {
351             p = init_formatter(boost::make_shared< sinks::asynchronous_sink< backend_t > >(backend), params, is_formatting_t());
352
353             // https://svn.boost.org/trac/boost/ticket/10638
354             // The user doesn't have a way to process excaptions from the dedicated thread anyway, so just suppress them instead of
355             // terminating the application.
356             p->set_exception_handler(nop());
357         }
358 #else
359         // When multithreading is disabled we always use the unlocked sink frontend
360         p = init_formatter(boost::make_shared< sinks::unlocked_sink< backend_t > >(backend), params, is_formatting_t());
361 #endif
362
363         p->set_filter(filt);
364
365         return p;
366     }
367
368 private:
369     //! The function initializes formatter for the sinks that support formatting
370     template< typename SinkT >
371     static shared_ptr< SinkT > init_formatter(shared_ptr< SinkT > const& sink, settings_section const& params, mpl::true_)
372     {
373         // Formatter
374         if (optional< string_type > format_param = params["Format"])
375         {
376             typedef typename SinkT::char_type sink_char_type;
377             std::basic_string< sink_char_type > format_str;
378             log::aux::code_convert(format_param.get(), format_str);
379             sink->set_formatter(parse_formatter(format_str));
380         }
381         return sink;
382     }
383     template< typename SinkT >
384     static shared_ptr< SinkT > init_formatter(shared_ptr< SinkT > const& sink, settings_section const& params, mpl::false_)
385     {
386         return sink;
387     }
388 };
389
390 //! Default console sink factory
391 template< typename CharT >
392 class default_console_sink_factory :
393     public basic_default_sink_factory< CharT >
394 {
395 public:
396     typedef basic_default_sink_factory< CharT > base_type;
397     typedef typename base_type::char_type char_type;
398     typedef typename base_type::string_type string_type;
399     typedef typename base_type::settings_section settings_section;
400     typedef typename base_type::constants constants;
401
402 private:
403     struct impl;
404     friend struct impl;
405     struct impl
406     {
407         typedef shared_ptr< sinks::sink > result_type;
408
409         template< typename BackendCharT >
410         result_type operator() (settings_section const& params, type< BackendCharT >) const
411         {
412             // Construct the backend
413             typedef boost::log::aux::char_constants< BackendCharT > constants;
414             typedef sinks::basic_text_ostream_backend< BackendCharT > backend_t;
415             shared_ptr< backend_t > backend = boost::make_shared< backend_t >();
416             backend->add_stream(shared_ptr< typename backend_t::stream_type >(&constants::get_console_log_stream(), boost::null_deleter()));
417
418             // Auto newline mode
419             if (optional< string_type > auto_newline_param = params["AutoNewline"])
420             {
421                 backend->set_auto_newline_mode(param_cast_to_auto_newline_mode("AutoNewline", auto_newline_param.get()));
422             }
423
424             // Auto flush
425             if (optional< string_type > auto_flush_param = params["AutoFlush"])
426             {
427                 backend->auto_flush(param_cast_to_bool("AutoFlush", auto_flush_param.get()));
428             }
429
430             return base_type::init_sink(backend, params);
431         }
432     };
433
434 public:
435     //! The function constructs a sink that writes log records to the console
436     shared_ptr< sinks::sink > create_sink(settings_section const& params)
437     {
438         return base_type::select_backend_character_type(params, impl());
439     }
440 };
441
442 //! Default text file sink factory
443 template< typename CharT >
444 class default_text_file_sink_factory :
445     public basic_default_sink_factory< CharT >
446 {
447 public:
448     typedef basic_default_sink_factory< CharT > base_type;
449     typedef typename base_type::char_type char_type;
450     typedef typename base_type::string_type string_type;
451     typedef typename base_type::settings_section settings_section;
452     typedef typename base_type::constants constants;
453
454 public:
455     //! The function constructs a sink that writes log records to a text file
456     shared_ptr< sinks::sink > create_sink(settings_section const& params)
457     {
458         typedef sinks::text_file_backend backend_t;
459         shared_ptr< backend_t > backend = boost::make_shared< backend_t >();
460
461         // FileName
462         if (optional< string_type > file_name_param = params["FileName"])
463         {
464             backend->set_file_name_pattern(filesystem::path(file_name_param.get()));
465         }
466         else
467             BOOST_LOG_THROW_DESCR(missing_value, "File name is not specified");
468
469         // Target file name
470         if (optional< string_type > target_file_name_param = params["TargetFileName"])
471         {
472             backend->set_target_file_name_pattern(filesystem::path(target_file_name_param.get()));
473         }
474
475         // File rotation size
476         if (optional< string_type > rotation_size_param = params["RotationSize"])
477         {
478             backend->set_rotation_size(param_cast_to_int< uintmax_t >("RotationSize", rotation_size_param.get()));
479         }
480
481         // File rotation interval
482         if (optional< string_type > rotation_interval_param = params["RotationInterval"])
483         {
484             backend->set_time_based_rotation(sinks::file::rotation_at_time_interval(
485                 posix_time::seconds(param_cast_to_int< unsigned int >("RotationInterval", rotation_interval_param.get()))));
486         }
487         else if (optional< string_type > rotation_time_point_param = params["RotationTimePoint"])
488         {
489             // File rotation time point
490             backend->set_time_based_rotation(param_cast_to_rotation_time_point("RotationTimePoint", rotation_time_point_param.get()));
491         }
492
493         // Final rotation
494         if (optional< string_type > enable_final_rotation_param = params["EnableFinalRotation"])
495         {
496             backend->enable_final_rotation(param_cast_to_bool("EnableFinalRotation", enable_final_rotation_param.get()));
497         }
498
499         // Auto newline mode
500         if (optional< string_type > auto_newline_param = params["AutoNewline"])
501         {
502             backend->set_auto_newline_mode(param_cast_to_auto_newline_mode("AutoNewline", auto_newline_param.get()));
503         }
504
505         // Auto flush
506         if (optional< string_type > auto_flush_param = params["AutoFlush"])
507         {
508             backend->auto_flush(param_cast_to_bool("AutoFlush", auto_flush_param.get()));
509         }
510
511         // Append
512         if (optional< string_type > append_param = params["Append"])
513         {
514             if (param_cast_to_bool("Append", append_param.get()))
515                 backend->set_open_mode(std::ios_base::out | std::ios_base::app);
516         }
517
518         // File collector parameters
519         // Target directory
520         if (optional< string_type > target_param = params["Target"])
521         {
522             filesystem::path target_dir(target_param.get());
523
524             // Max total size
525             uintmax_t max_size = (std::numeric_limits< uintmax_t >::max)();
526             if (optional< string_type > max_size_param = params["MaxSize"])
527                 max_size = param_cast_to_int< uintmax_t >("MaxSize", max_size_param.get());
528
529             // Min free space
530             uintmax_t space = 0;
531             if (optional< string_type > min_space_param = params["MinFreeSpace"])
532                 space = param_cast_to_int< uintmax_t >("MinFreeSpace", min_space_param.get());
533
534             // Max number of files
535             uintmax_t max_files = (std::numeric_limits< uintmax_t >::max)();
536             if (optional< string_type > max_files_param = params["MaxFiles"])
537                 max_files = param_cast_to_int< uintmax_t >("MaxFiles", max_files_param.get());
538
539             backend->set_file_collector(sinks::file::make_collector(
540                 keywords::target = target_dir,
541                 keywords::max_size = max_size,
542                 keywords::min_free_space = space,
543                 keywords::max_files = max_files));
544
545             // Scan for log files
546             if (optional< string_type > scan_param = params["ScanForFiles"])
547             {
548                 string_type const& value = scan_param.get();
549                 if (value == constants::scan_method_all())
550                     backend->scan_for_files(sinks::file::scan_all);
551                 else if (value == constants::scan_method_matching())
552                     backend->scan_for_files(sinks::file::scan_matching);
553                 else
554                 {
555                     BOOST_LOG_THROW_DESCR(invalid_value,
556                         "File scan method \"" + boost::log::aux::to_narrow(value) + "\" is not supported");
557                 }
558             }
559         }
560
561         return base_type::init_sink(backend, params);
562     }
563 };
564
565 #ifndef BOOST_LOG_WITHOUT_SYSLOG
566
567 //! Default syslog sink factory
568 template< typename CharT >
569 class default_syslog_sink_factory :
570     public basic_default_sink_factory< CharT >
571 {
572 public:
573     typedef basic_default_sink_factory< CharT > base_type;
574     typedef typename base_type::char_type char_type;
575     typedef typename base_type::string_type string_type;
576     typedef typename base_type::settings_section settings_section;
577     typedef typename base_type::constants constants;
578
579 public:
580     //! The function constructs a sink that writes log records to syslog
581     shared_ptr< sinks::sink > create_sink(settings_section const& params)
582     {
583         // Construct the backend
584         typedef sinks::syslog_backend backend_t;
585         shared_ptr< backend_t > backend = boost::make_shared< backend_t >();
586
587         // For now we use only the default level mapping. Will add support for configuration later.
588         backend->set_severity_mapper(sinks::syslog::direct_severity_mapping< >(log::aux::default_attribute_names::severity()));
589
590 #if !defined(BOOST_LOG_NO_ASIO)
591         // Setup local and remote addresses
592         if (optional< string_type > local_address_param = params["LocalAddress"])
593             backend->set_local_address(param_cast_to_address("LocalAddress", local_address_param.get()));
594
595         if (optional< string_type > target_address_param = params["TargetAddress"])
596             backend->set_target_address(param_cast_to_address("TargetAddress", target_address_param.get()));
597 #endif // !defined(BOOST_LOG_NO_ASIO)
598
599         return base_type::init_sink(backend, params);
600     }
601 };
602
603 #endif // !defined(BOOST_LOG_WITHOUT_SYSLOG)
604
605 #ifndef BOOST_LOG_WITHOUT_DEBUG_OUTPUT
606
607 //! Default debugger sink factory
608 template< typename CharT >
609 class default_debugger_sink_factory :
610     public basic_default_sink_factory< CharT >
611 {
612 public:
613     typedef basic_default_sink_factory< CharT > base_type;
614     typedef typename base_type::char_type char_type;
615     typedef typename base_type::string_type string_type;
616     typedef typename base_type::settings_section settings_section;
617     typedef typename base_type::constants constants;
618
619 private:
620     struct impl;
621     friend struct impl;
622     struct impl
623     {
624         typedef shared_ptr< sinks::sink > result_type;
625
626         template< typename BackendCharT >
627         result_type operator() (settings_section const& params, type< BackendCharT >) const
628         {
629             // Construct the backend
630             typedef sinks::basic_debug_output_backend< BackendCharT > backend_t;
631             shared_ptr< backend_t > backend = boost::make_shared< backend_t >();
632
633             return base_type::init_sink(backend, params);
634         }
635     };
636
637 public:
638     //! The function constructs a sink that writes log records to the debugger
639     shared_ptr< sinks::sink > create_sink(settings_section const& params)
640     {
641         return base_type::select_backend_character_type(params, impl());
642     }
643 };
644
645 #endif // !defined(BOOST_LOG_WITHOUT_DEBUG_OUTPUT)
646
647 #ifndef BOOST_LOG_WITHOUT_EVENT_LOG
648
649 //! Default simple event log sink factory
650 template< typename CharT >
651 class default_simple_event_log_sink_factory :
652     public basic_default_sink_factory< CharT >
653 {
654 public:
655     typedef basic_default_sink_factory< CharT > base_type;
656     typedef typename base_type::char_type char_type;
657     typedef typename base_type::string_type string_type;
658     typedef typename base_type::settings_section settings_section;
659     typedef typename base_type::constants constants;
660
661 private:
662     struct impl;
663     friend struct impl;
664     struct impl
665     {
666         typedef shared_ptr< sinks::sink > result_type;
667
668         template< typename BackendCharT >
669         result_type operator() (settings_section const& params, type< BackendCharT >) const
670         {
671             typedef sinks::basic_simple_event_log_backend< BackendCharT > backend_t;
672             typedef typename backend_t::string_type backend_string_type;
673
674             // Determine the log name
675             backend_string_type log_name;
676             if (optional< string_type > log_name_param = params["LogName"])
677                 log::aux::code_convert(log_name_param.get(), log_name);
678             else
679                 log_name = backend_t::get_default_log_name();
680
681             // Determine the log source name
682             backend_string_type source_name;
683             if (optional< string_type > log_source_param = params["LogSource"])
684                 log::aux::code_convert(log_source_param.get(), source_name);
685             else
686                 source_name = backend_t::get_default_source_name();
687
688             // Determine the registration mode
689             sinks::event_log::registration_mode reg_mode = sinks::event_log::on_demand;
690             if (optional< string_type > registration_param = params["Registration"])
691             {
692                 string_type const& value = registration_param.get();
693                 if (value == constants::registration_never())
694                     reg_mode = sinks::event_log::never;
695                 else if (value == constants::registration_on_demand())
696                     reg_mode = sinks::event_log::on_demand;
697                 else if (value == constants::registration_forced())
698                     reg_mode = sinks::event_log::forced;
699                 else
700                 {
701                     BOOST_LOG_THROW_DESCR(invalid_value,
702                         "The registration mode \"" + log::aux::to_narrow(value) + "\" is not supported");
703                 }
704             }
705
706             // Construct the backend
707             shared_ptr< backend_t > backend(boost::make_shared< backend_t >((
708                 keywords::log_name = log_name,
709                 keywords::log_source = source_name,
710                 keywords::registration = reg_mode)));
711
712             // For now we use only the default event type mapping. Will add support for configuration later.
713             backend->set_event_type_mapper(sinks::event_log::direct_event_type_mapping< >(log::aux::default_attribute_names::severity()));
714
715             return base_type::init_sink(backend, params);
716         }
717     };
718
719 public:
720     //! The function constructs a sink that writes log records to the Windows NT Event Log
721     shared_ptr< sinks::sink > create_sink(settings_section const& params)
722     {
723         return base_type::select_backend_character_type(params, impl());
724     }
725 };
726
727 #endif // !defined(BOOST_LOG_WITHOUT_EVENT_LOG)
728
729
730 //! The supported sinks repository
731 template< typename CharT >
732 struct sinks_repository :
733     public log::aux::lazy_singleton< sinks_repository< CharT > >
734 {
735     typedef log::aux::lazy_singleton< sinks_repository< CharT > > base_type;
736
737 #if !defined(BOOST_LOG_BROKEN_FRIEND_TEMPLATE_SPECIALIZATIONS)
738     friend class log::aux::lazy_singleton< sinks_repository< CharT > >;
739 #else
740     friend class base_type;
741 #endif
742
743     typedef CharT char_type;
744     typedef std::basic_string< char_type > string_type;
745     typedef basic_settings_section< char_type > settings_section;
746     typedef boost::log::aux::char_constants< char_type > constants;
747     typedef boost::shared_ptr< sink_factory< char_type > > sink_factory_ptr;
748     typedef std::map< std::string, sink_factory_ptr > sink_factories;
749
750 #if !defined(BOOST_LOG_NO_THREADS)
751     //! Synchronization mutex
752     log::aux::light_rw_mutex m_Mutex;
753 #endif
754     //! Map of the sink factories
755     sink_factories m_Factories;
756
757     //! The function constructs a sink from the settings
758     shared_ptr< sinks::sink > construct_sink_from_settings(settings_section const& params)
759     {
760         typedef typename settings_section::const_reference param_const_reference;
761         if (param_const_reference dest_node = params["Destination"])
762         {
763             std::string dest = log::aux::to_narrow(dest_node.get().get());
764
765             BOOST_LOG_EXPR_IF_MT(log::aux::shared_lock_guard< log::aux::light_rw_mutex > lock(m_Mutex);)
766             typename sink_factories::const_iterator it = m_Factories.find(dest);
767             if (it != m_Factories.end())
768             {
769                 return it->second->create_sink(params);
770             }
771             else
772             {
773                 BOOST_LOG_THROW_DESCR(invalid_value, "The sink destination is not supported: " + dest);
774             }
775         }
776         else
777         {
778             BOOST_LOG_THROW_DESCR(missing_value, "The sink destination is not set");
779         }
780     }
781
782     static void init_instance()
783     {
784         sinks_repository& instance = base_type::get_instance();
785         instance.m_Factories["TextFile"] = boost::make_shared< default_text_file_sink_factory< char_type > >();
786         instance.m_Factories["Console"] = boost::make_shared< default_console_sink_factory< char_type > >();
787 #ifndef BOOST_LOG_WITHOUT_SYSLOG
788         instance.m_Factories["Syslog"] = boost::make_shared< default_syslog_sink_factory< char_type > >();
789 #endif
790 #ifndef BOOST_LOG_WITHOUT_DEBUG_OUTPUT
791         instance.m_Factories["Debugger"] = boost::make_shared< default_debugger_sink_factory< char_type > >();
792 #endif
793 #ifndef BOOST_LOG_WITHOUT_EVENT_LOG
794         instance.m_Factories["SimpleEventLog"] = boost::make_shared< default_simple_event_log_sink_factory< char_type > >();
795 #endif
796     }
797
798 private:
799     sinks_repository() {}
800 };
801
802 //! The function applies the settings to the logging core
803 template< typename CharT >
804 void apply_core_settings(basic_settings_section< CharT > const& params)
805 {
806     typedef CharT char_type;
807     typedef std::basic_string< char_type > string_type;
808
809     core_ptr core = boost::log::core::get();
810
811     // Filter
812     if (optional< string_type > filter_param = params["Filter"])
813         core->set_filter(parse_filter(filter_param.get()));
814     else
815         core->reset_filter();
816
817     // DisableLogging
818     if (optional< string_type > disable_logging_param = params["DisableLogging"])
819         core->set_logging_enabled(!param_cast_to_bool("DisableLogging", disable_logging_param.get()));
820     else
821         core->set_logging_enabled(true);
822 }
823
824 } // namespace
825
826
827 //! The function initializes the logging library from a settings container
828 template< typename CharT >
829 BOOST_LOG_SETUP_API void init_from_settings(basic_settings_section< CharT > const& setts)
830 {
831     typedef basic_settings_section< CharT > section;
832     typedef typename section::char_type char_type;
833     typedef sinks_repository< char_type > sinks_repo_t;
834
835     // Apply core settings
836     if (section core_params = setts["Core"])
837         apply_core_settings(core_params);
838
839     // Construct and initialize sinks
840     if (section sink_params = setts["Sinks"])
841     {
842         sinks_repo_t& sinks_repo = sinks_repo_t::get();
843         std::vector< shared_ptr< sinks::sink > > new_sinks;
844
845         for (typename section::const_iterator it = sink_params.begin(), end = sink_params.end(); it != end; ++it)
846         {
847             section sink_params = *it;
848
849             // Ignore empty sections as they are most likely individual parameters (which should not be here anyway)
850             if (!sink_params.empty())
851             {
852                 new_sinks.push_back(sinks_repo.construct_sink_from_settings(sink_params));
853             }
854         }
855
856         std::for_each(new_sinks.begin(), new_sinks.end(), boost::bind(&core::add_sink, core::get(), _1));
857     }
858 }
859
860
861 //! The function registers a factory for a sink
862 template< typename CharT >
863 BOOST_LOG_SETUP_API void register_sink_factory(const char* sink_name, shared_ptr< sink_factory< CharT > > const& factory)
864 {
865     sinks_repository< CharT >& repo = sinks_repository< CharT >::get();
866     BOOST_LOG_EXPR_IF_MT(lock_guard< log::aux::light_rw_mutex > lock(repo.m_Mutex);)
867     repo.m_Factories[sink_name] = factory;
868 }
869
870 #ifdef BOOST_LOG_USE_CHAR
871 template BOOST_LOG_SETUP_API void register_sink_factory< char >(const char* sink_name, shared_ptr< sink_factory< char > > const& factory);
872 template BOOST_LOG_SETUP_API void init_from_settings< char >(basic_settings_section< char > const& setts);
873 #endif
874
875 #ifdef BOOST_LOG_USE_WCHAR_T
876 template BOOST_LOG_SETUP_API void register_sink_factory< wchar_t >(const char* sink_name, shared_ptr< sink_factory< wchar_t > > const& factory);
877 template BOOST_LOG_SETUP_API void init_from_settings< wchar_t >(basic_settings_section< wchar_t > const& setts);
878 #endif
879
880 BOOST_LOG_CLOSE_NAMESPACE // namespace log
881
882 } // namespace boost
883
884 #include <boost/log/detail/footer.hpp>
885
886 #endif // BOOST_LOG_WITHOUT_SETTINGS_PARSERS