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