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/smart_ptr/make_shared_object.hpp>
41#include <boost/core/null_deleter.hpp>
42#include <boost/optional/optional.hpp>
43#include <boost/filesystem/path.hpp>
44#include <boost/date_time/date_defs.hpp>
45#include <boost/property_tree/ptree.hpp>
46#include <boost/type_traits/conditional.hpp>
47#include <boost/type_traits/is_unsigned.hpp>
48#include <boost/type_traits/integral_constant.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
76namespace qi = boost::spirit::qi;
77
78namespace boost {
79
80BOOST_LOG_OPEN_NAMESPACE
81
82BOOST_LOG_ANONYMOUS_NAMESPACE {
83
84//! Throws an exception when a parameter value is not valid
85BOOST_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
94template< typename IntT, typename CharT >
95inline IntT param_cast_to_int(const char* param_name, std::basic_string< CharT > const& value)
96{
97 IntT res = 0;
98 typedef typename conditional<
99 is_unsigned< IntT >::value,
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
111struct 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
124template< typename CharT >
125inline 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
154template< typename CharT >
155inline 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
175template< typename CharT >
176inline 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
182template< typename CharT >
183inline 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
190template< typename CharT >
191sinks::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
286template< typename CharT >
287class basic_default_sink_factory :
288 public sink_factory< CharT >
289{
290public:
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
297protected:
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
368private:
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, true_type)
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, false_type)
385 {
386 return sink;
387 }
388};
389
390//! Default console sink factory
391template< typename CharT >
392class default_console_sink_factory :
393 public basic_default_sink_factory< CharT >
394{
395public:
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
402private:
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
434public:
435 //! The function constructs a sink that writes log records to the console
436 shared_ptr< sinks::sink > create_sink(settings_section const& params) BOOST_OVERRIDE
437 {
438 return base_type::select_backend_character_type(params, impl());
439 }
440};
441
442//! Default text file sink factory
443template< typename CharT >
444class default_text_file_sink_factory :
445 public basic_default_sink_factory< CharT >
446{
447public:
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
454public:
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) BOOST_OVERRIDE
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(enable: 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(enable: 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 a1: keywords::target = target_dir,
541 a2: keywords::max_size = max_size,
542 a3: keywords::min_free_space = space,
543 a4: 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(method: sinks::file::scan_all);
551 else if (value == constants::scan_method_matching())
552 backend->scan_for_files(method: 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
568template< typename CharT >
569class default_syslog_sink_factory :
570 public basic_default_sink_factory< CharT >
571{
572public:
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
579public:
580 //! The function constructs a sink that writes log records to syslog
581 shared_ptr< sinks::sink > create_sink(settings_section const& params) BOOST_OVERRIDE
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
608template< typename CharT >
609class default_debugger_sink_factory :
610 public basic_default_sink_factory< CharT >
611{
612public:
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
619private:
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
637public:
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
650template< typename CharT >
651class default_simple_event_log_sink_factory :
652 public basic_default_sink_factory< CharT >
653{
654public:
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
661private:
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
719public:
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
731template< typename CharT >
732struct 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
798private:
799 sinks_repository() {}
800};
801
802//! The function applies the settings to the logging core
803template< typename CharT >
804void 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
828template< typename CharT >
829BOOST_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 typedef std::vector< shared_ptr< sinks::sink > > sink_list_t;
844 sink_list_t 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 core_ptr core = boost::log::core::get();
858 for (sink_list_t::const_iterator it = new_sinks.begin(), end = new_sinks.end(); it != end; ++it)
859 core->add_sink(s: *it);
860 }
861}
862
863
864//! The function registers a factory for a sink
865template< typename CharT >
866BOOST_LOG_SETUP_API void register_sink_factory(const char* sink_name, shared_ptr< sink_factory< CharT > > const& factory)
867{
868 sinks_repository< CharT >& repo = sinks_repository< CharT >::get();
869 BOOST_LOG_EXPR_IF_MT(lock_guard< log::aux::light_rw_mutex > lock(repo.m_Mutex);)
870 repo.m_Factories[sink_name] = factory;
871}
872
873#ifdef BOOST_LOG_USE_CHAR
874template BOOST_LOG_SETUP_API void register_sink_factory< char >(const char* sink_name, shared_ptr< sink_factory< char > > const& factory);
875template BOOST_LOG_SETUP_API void init_from_settings< char >(basic_settings_section< char > const& setts);
876#endif
877
878#ifdef BOOST_LOG_USE_WCHAR_T
879template BOOST_LOG_SETUP_API void register_sink_factory< wchar_t >(const char* sink_name, shared_ptr< sink_factory< wchar_t > > const& factory);
880template BOOST_LOG_SETUP_API void init_from_settings< wchar_t >(basic_settings_section< wchar_t > const& setts);
881#endif
882
883BOOST_LOG_CLOSE_NAMESPACE // namespace log
884
885} // namespace boost
886
887#include <boost/log/detail/footer.hpp>
888
889#endif // BOOST_LOG_WITHOUT_SETTINGS_PARSERS
890

source code of boost/libs/log/src/setup/init_from_settings.cpp