Line data Source code
1 : // Copyright (c) 2013-2025 Made to Order Software Corp. All Rights Reserved
2 : //
3 : // https://snapwebsites.org/project/snaplogger
4 : // contact@m2osw.com
5 : //
6 : // This program is free software; you can redistribute it and/or modify
7 : // it under the terms of the GNU General Public License as published by
8 : // the Free Software Foundation; either version 2 of the License, or
9 : // (at your option) any later version.
10 : //
11 : // This program is distributed in the hope that it will be useful,
12 : // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 : // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 : // GNU General Public License for more details.
15 : //
16 : // You should have received a copy of the GNU General Public License along
17 : // with this program; if not, write to the Free Software Foundation, Inc.,
18 : // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 :
20 : /** \file
21 : * \brief Appenders are used to append data to somewhere.
22 : *
23 : * This file declares the base appender class.
24 : */
25 :
26 : // self
27 : //
28 : #include "snaplogger/logger.h"
29 :
30 : #include "snaplogger/console_appender.h"
31 : #include "snaplogger/exception.h"
32 : #include "snaplogger/file_appender.h"
33 : #include "snaplogger/guard.h"
34 : #include "snaplogger/private_logger.h"
35 : #include "snaplogger/syslog_appender.h"
36 :
37 :
38 : // serverplugins
39 : //
40 : #include <serverplugins/paths.h>
41 :
42 :
43 : // last include
44 : //
45 : #include <snapdev/poison.h>
46 :
47 :
48 :
49 : namespace snaplogger
50 : {
51 :
52 :
53 : namespace
54 : {
55 :
56 :
57 :
58 : bool g_first_instance = true;
59 : logger::pointer_t * g_instance = nullptr;
60 : std::string g_default_plugin_paths = std::string("/usr/local/lib/snaplogger/plugins:/usr/lib/snaplogger/plugins");
61 :
62 :
63 : struct auto_delete_logger
64 : {
65 2 : ~auto_delete_logger()
66 : {
67 2 : logger::pointer_t * ptr(nullptr);
68 : {
69 2 : guard g;
70 2 : swap(ptr, g_instance);
71 2 : }
72 2 : if(ptr != nullptr)
73 : {
74 2 : (*ptr)->shutdown();
75 2 : delete ptr;
76 : }
77 2 : }
78 : };
79 :
80 : auto_delete_logger g_logger_deleter = auto_delete_logger();
81 :
82 :
83 :
84 : }
85 : // no name namespace
86 :
87 :
88 :
89 2 : logger::logger()
90 10 : : server(serverplugins::get_id("logger"))
91 : {
92 2 : }
93 :
94 :
95 1 : logger::~logger()
96 : {
97 1 : }
98 :
99 :
100 274764 : logger::pointer_t logger::get_instance()
101 : {
102 274764 : guard g;
103 :
104 274764 : if(g_instance == nullptr)
105 : {
106 2 : if(!g_first_instance)
107 : {
108 0 : throw duplicate_error("preventing an attempt of re-creating the snap logger.");
109 : }
110 :
111 2 : g_first_instance = false;
112 :
113 : // note that we create a `private_logger` object
114 : //
115 2 : g_instance = new logger::pointer_t();
116 2 : g_instance->reset(new private_logger());
117 : }
118 :
119 549528 : return *g_instance;
120 274764 : }
121 :
122 :
123 : /** \brief Reset the logger to its startup state.
124 : *
125 : * This function resets the logger to non-asynchronous and no appenders.
126 : *
127 : * This is mainly used in our unit tests so we do not have to run the
128 : * tests one at a time. It should nearly never be useful in your environment
129 : * except if you do a fork() and wanted the child to have its own special
130 : * log environment.
131 : */
132 16 : void logger::reset()
133 : {
134 16 : guard g;
135 :
136 16 : set_asynchronous(false);
137 16 : f_appenders.clear();
138 16 : f_lowest_severity = severity_t::SEVERITY_OFF;
139 32 : }
140 :
141 :
142 0 : void logger::shutdown()
143 : {
144 0 : }
145 :
146 :
147 1 : std::string const & logger::default_plugin_paths()
148 : {
149 1 : return g_default_plugin_paths;
150 : }
151 :
152 :
153 1 : void logger::load_plugins(std::string const & plugin_paths)
154 : {
155 1 : guard g;
156 :
157 : // we can load plugins only once, further calls must be ignored
158 : // (it happens in our tests)
159 : //
160 1 : if(f_plugins == nullptr)
161 : {
162 1 : serverplugins::paths paths;
163 1 : paths.add(plugin_paths);
164 :
165 1 : serverplugins::names names(paths);
166 3 : names.find_plugins("snaplogger_");
167 :
168 1 : f_plugins = std::make_shared<serverplugins::collection>(names);
169 1 : f_plugins->load_plugins(shared_from_this());
170 1 : }
171 2 : }
172 :
173 :
174 0 : bool logger::is_configured() const
175 : {
176 0 : guard g;
177 :
178 0 : return !f_appenders.empty();
179 0 : }
180 :
181 :
182 0 : bool logger::has_appender(std::string const & type) const
183 : {
184 0 : return std::find_if(
185 : f_appenders.begin()
186 : , f_appenders.end()
187 0 : , [&type](auto a)
188 : {
189 0 : return type == a->get_type();
190 0 : }) != f_appenders.end();
191 : }
192 :
193 :
194 2 : appender::pointer_t logger::get_appender(std::string const & name) const
195 : {
196 2 : auto it(std::find_if(
197 : f_appenders.begin()
198 : , f_appenders.end()
199 1 : , [&name](auto a)
200 : {
201 1 : return name == a->get_name();
202 : }));
203 2 : if(it == f_appenders.end())
204 : {
205 1 : return appender::pointer_t();
206 : }
207 :
208 1 : return *it;
209 : }
210 :
211 :
212 0 : appender::vector_t logger::get_appenders() const
213 : {
214 0 : return f_appenders;
215 : }
216 :
217 :
218 2 : void logger::set_config(advgetopt::getopt const & params)
219 : {
220 : // The asynchronous flag can cause problems unless the programmer
221 : // specifically planned for it so we do not allow it in configuration
222 : // files at the moment. Later we may have two flags. If both are true
223 : // then we allow asynchronous logging.
224 : //
225 : //if(params.is_defined("asynchronous"))
226 : //{
227 : // set_asynchronous(advgetopt::is_true(params.get_string("asynchronous")));
228 : //}
229 :
230 6 : auto const & sections(params.get_option(advgetopt::CONFIGURATION_SECTIONS));
231 2 : if(sections != nullptr)
232 : {
233 0 : size_t const max(sections->size());
234 0 : for(size_t idx(0); idx < max; ++idx)
235 : {
236 0 : std::string const section_name(sections->get_value(idx));
237 0 : std::string const section_type(section_name + "::type");
238 0 : std::string type;
239 0 : if(params.is_defined(section_type))
240 : {
241 0 : type = params.get_string(section_type);
242 : }
243 : else
244 : {
245 : // try with the name of the section if no type is defined
246 : //
247 0 : type = section_name;
248 : }
249 0 : if(!type.empty())
250 : {
251 0 : appender::pointer_t a(create_appender(type, section_name));
252 0 : if(a != nullptr)
253 : {
254 0 : add_appender(a);
255 : }
256 : // else -- this may be a section which does not represent an appender
257 0 : }
258 0 : }
259 : }
260 :
261 2 : guard g;
262 :
263 6 : for(auto a : f_appenders)
264 : {
265 4 : a->set_config(params);
266 4 : }
267 4 : }
268 :
269 :
270 0 : void logger::reopen()
271 : {
272 0 : guard g;
273 :
274 0 : for(auto a : f_appenders)
275 : {
276 0 : a->reopen();
277 0 : }
278 0 : }
279 :
280 :
281 23 : void logger::add_appender(appender::pointer_t a)
282 : {
283 23 : guard g;
284 :
285 23 : if(a->unique())
286 : {
287 0 : std::string const type(a->get_type());
288 0 : auto it(std::find_if(
289 : f_appenders.begin()
290 : , f_appenders.end()
291 0 : , [&type](auto app)
292 : {
293 0 : return type == app->get_type();
294 : }));
295 0 : if(it != f_appenders.end())
296 : {
297 : // the console is a pretty special type because it can't be
298 : // added twice but it may get added early because an error
299 : // occurs and forces initialization of the logger "too soon"
300 : //
301 0 : if(type == "console")
302 : {
303 0 : if(a->get_name() != "console"
304 0 : && (*it)->get_name() == "console")
305 : {
306 0 : (*it)->set_name(a->get_name());
307 : }
308 0 : return;
309 : }
310 0 : if(type == "syslog")
311 : {
312 0 : if(a->get_name() != "syslog"
313 0 : && (*it)->get_name() == "syslog")
314 : {
315 0 : (*it)->set_name(a->get_name());
316 : }
317 0 : return;
318 : }
319 : throw duplicate_error(
320 : "an appender of type \""
321 0 : + type
322 0 : + "\" can only be added once.");
323 : }
324 0 : }
325 :
326 23 : f_appenders.push_back(a);
327 :
328 23 : severity_changed(a->get_severity());
329 23 : }
330 :
331 :
332 0 : void logger::add_config(std::string const & config_filename)
333 : {
334 0 : advgetopt::options_environment opt_env;
335 :
336 0 : char const * configuration_files[] =
337 : {
338 0 : config_filename.c_str()
339 : , nullptr
340 0 : };
341 :
342 0 : opt_env.f_project_name = "snaplogger";
343 0 : opt_env.f_environment_variable_name = "SNAPLOGGER";
344 0 : opt_env.f_configuration_files = configuration_files;
345 0 : opt_env.f_environment_flags = advgetopt::GETOPT_ENVIRONMENT_FLAG_DYNAMIC_PARAMETERS;
346 :
347 0 : advgetopt::getopt opts(opt_env);
348 :
349 0 : opts.parse_configuration_files();
350 0 : opts.parse_environment_variable();
351 :
352 0 : set_config(opts);
353 0 : }
354 :
355 :
356 0 : appender::pointer_t logger::add_console_appender()
357 : {
358 0 : appender::pointer_t a(std::make_shared<console_appender>("console"));
359 :
360 0 : advgetopt::options_environment opt_env;
361 0 : opt_env.f_project_name = "snaplogger";
362 0 : opt_env.f_environment_flags = advgetopt::GETOPT_ENVIRONMENT_FLAG_AUTO_DONE;
363 0 : advgetopt::getopt opts(opt_env);
364 0 : a->set_config(opts);
365 :
366 0 : guard g;
367 :
368 0 : add_appender(a);
369 :
370 0 : return a;
371 0 : }
372 :
373 :
374 0 : appender::pointer_t logger::add_syslog_appender(std::string const & identity)
375 : {
376 0 : appender::pointer_t a(std::make_shared<syslog_appender>("syslog"));
377 :
378 0 : advgetopt::option options[] =
379 : {
380 : advgetopt::define_option(
381 : advgetopt::Name("syslog::identity")
382 : , advgetopt::Flags(advgetopt::command_flags<advgetopt::GETOPT_FLAG_REQUIRED>())
383 : ),
384 : advgetopt::end_options()
385 : };
386 :
387 0 : advgetopt::options_environment opt_env;
388 0 : opt_env.f_project_name = "snaplogger";
389 0 : opt_env.f_environment_flags = advgetopt::GETOPT_ENVIRONMENT_FLAG_AUTO_DONE;
390 0 : opt_env.f_options = options;
391 0 : advgetopt::getopt opts(opt_env);
392 0 : if(!identity.empty())
393 : {
394 0 : opts.get_option("syslog::identity")->set_value(0, identity);
395 : }
396 0 : a->set_config(opts);
397 :
398 0 : guard g;
399 :
400 0 : add_appender(a);
401 :
402 0 : return a;
403 0 : }
404 :
405 :
406 0 : appender::pointer_t logger::add_file_appender(std::string const & filename)
407 : {
408 0 : file_appender::pointer_t a(std::make_shared<file_appender>("file"));
409 :
410 0 : advgetopt::option options[] =
411 : {
412 : advgetopt::define_option(
413 : advgetopt::Name("file::filename")
414 : , advgetopt::Flags(advgetopt::command_flags<advgetopt::GETOPT_FLAG_REQUIRED>())
415 : ),
416 : advgetopt::end_options()
417 : };
418 :
419 0 : advgetopt::options_environment opt_env;
420 0 : opt_env.f_project_name = "snaplogger";
421 0 : opt_env.f_environment_flags = advgetopt::GETOPT_ENVIRONMENT_FLAG_AUTO_DONE;
422 0 : opt_env.f_options = options;
423 0 : advgetopt::getopt opts(opt_env);
424 0 : if(!filename.empty())
425 : {
426 0 : opts.get_option("file::filename")->set_value(0, filename);
427 : }
428 0 : a->set_config(opts);
429 :
430 0 : guard g;
431 :
432 0 : add_appender(a);
433 :
434 0 : return a;
435 0 : }
436 :
437 :
438 91296 : severity_t logger::get_lowest_severity() const
439 : {
440 91296 : guard g;
441 :
442 91296 : if(f_appenders.empty())
443 : {
444 : // we do not know the level yet, we do not have the appenders
445 : // yet... so accept anything at this point
446 : //
447 1 : return severity_t::SEVERITY_ALL;
448 : }
449 :
450 91295 : if(f_lowest_replacements.empty())
451 : {
452 91295 : return f_lowest_severity;
453 : }
454 :
455 : // there is not need to build messages that no appenders is going
456 : // to handle, so return the max. between the lowest of all appenders
457 : // and the lowest from the replacements
458 : //
459 0 : return std::max(f_lowest_severity, f_lowest_replacements.back());
460 91296 : }
461 :
462 :
463 : /** \brief Override the lowest severity.
464 : *
465 : * After this call, and until you call the restore_lowest_severity() function,
466 : * the get_lowest_severity() function will return \p severity_level. This
467 : * new security level may be lower or higher than the expected level.
468 : *
469 : * Setting this level to a level lower than the current lowest level is
470 : * not useful. The get_lowest_severity() will still return the
471 : * f_lowest_severiry value in that case. Since it can change dynamically,
472 : * this lowest replacement is still saved as is.
473 : *
474 : * \param[in] severity_level The severity level to use in
475 : * get_lowest_severity() until restore_lower_severity().
476 : */
477 0 : void logger::override_lowest_severity(severity_t severity_level)
478 : {
479 0 : f_lowest_replacements.push_back(severity_level);
480 0 : }
481 :
482 :
483 : /** \brief Cancel one call to the override_lowest_severity().
484 : *
485 : * Each time you call the override_lowest_severity() function, you are
486 : * expected to call restore_lowest_severity() once to cancel the effect.
487 : *
488 : * Call the restore_lowest_severity() too many times is safe. However,
489 : * to make it safe, you are expected to use the override_lowest_severity_level
490 : * class. Create an object of that type. When the object is detroyed, the
491 : * lowest level added gets removed automatically.
492 : */
493 0 : void logger::restore_lowest_severity()
494 : {
495 0 : if(!f_lowest_replacements.empty())
496 : {
497 0 : f_lowest_replacements.pop_back();
498 : }
499 0 : }
500 :
501 :
502 1 : void logger::set_severity(severity_t severity_level)
503 : {
504 1 : guard g;
505 :
506 1 : f_lowest_severity = severity_level;
507 6 : for(auto a : f_appenders)
508 : {
509 5 : a->set_severity(severity_level);
510 5 : }
511 2 : }
512 :
513 :
514 1 : void logger::reduce_severity(severity_t severity_level)
515 : {
516 3 : for(auto a : f_appenders)
517 : {
518 2 : a->reduce_severity(severity_level);
519 2 : }
520 1 : }
521 :
522 :
523 317 : void logger::severity_changed(severity_t severity_level)
524 : {
525 317 : guard g;
526 :
527 317 : if(severity_level < f_lowest_severity)
528 : {
529 21 : f_lowest_severity = severity_level;
530 : }
531 296 : else if(severity_level > f_lowest_severity)
532 : {
533 : // if the severity level grew we have to search for the new lowest;
534 : // this happens very rarely while running, it's likely to happen
535 : // up to once per appender on initialization.
536 : //
537 285 : auto const min(std::min_element(f_appenders.begin(), f_appenders.end()));
538 285 : if(min == f_appenders.end())
539 : {
540 : // I don't think this is possible because if there are no appenders
541 : // then we should not even get called; also the new level should
542 : // not be higher if the list is empty
543 : //
544 0 : f_lowest_severity = severity_t::SEVERITY_ALL;
545 : }
546 : else
547 : {
548 285 : f_lowest_severity = (*min)->get_severity();
549 : }
550 : }
551 634 : }
552 :
553 :
554 0 : severity_t logger::get_default_severity() const
555 : {
556 0 : private_logger const * l(dynamic_cast<private_logger const *>(this));
557 0 : severity::pointer_t sev(l->get_default_severity());
558 0 : return sev == nullptr ? severity_t::SEVERITY_DEFAULT : sev->get_severity();
559 0 : }
560 :
561 :
562 0 : bool logger::set_default_severity(severity_t severity_level)
563 : {
564 0 : private_logger * l(dynamic_cast<private_logger *>(this));
565 0 : if(severity_level == severity_t::SEVERITY_ALL)
566 : {
567 : // reset to default
568 0 : l->set_default_severity(severity::pointer_t());
569 : }
570 : else
571 : {
572 0 : severity::pointer_t sev(l->get_severity(severity_level));
573 0 : if(sev == nullptr)
574 : {
575 0 : return false;
576 : }
577 0 : l->set_default_severity(sev);
578 0 : }
579 0 : return true;
580 : }
581 :
582 :
583 0 : void logger::add_component_to_include(component::pointer_t comp)
584 : {
585 0 : guard g;
586 :
587 0 : f_components_to_include.insert(comp);
588 0 : }
589 :
590 :
591 0 : void logger::remove_component_to_include(component::pointer_t comp)
592 : {
593 0 : guard g;
594 :
595 0 : f_components_to_include.erase(comp);
596 0 : }
597 :
598 :
599 1 : void logger::add_component_to_ignore(component::pointer_t comp)
600 : {
601 1 : guard g;
602 :
603 1 : f_components_to_ignore.insert(comp);
604 2 : }
605 :
606 :
607 0 : void logger::remove_component_to_ignore(component::pointer_t comp)
608 : {
609 0 : guard g;
610 :
611 0 : f_components_to_ignore.erase(comp);
612 0 : }
613 :
614 :
615 0 : component::map_t logger::get_component_list() const
616 : {
617 0 : guard g;
618 :
619 0 : private_logger const * l(dynamic_cast<private_logger const *>(this));
620 0 : return l->get_component_list();
621 0 : }
622 :
623 :
624 0 : void logger::add_default_field(std::string const & name, std::string const & value)
625 : {
626 0 : if(!name.empty())
627 : {
628 0 : if(name[0] == '_')
629 : {
630 : throw invalid_parameter(
631 : "field name \""
632 0 : + name
633 0 : + "\" is a system name (whether reserved or already defined) and as such is read-only."
634 0 : " Do not start your field names with an underscore (_).");
635 : }
636 0 : if(name == "id")
637 : {
638 : throw invalid_parameter(
639 : "field name \"id\" is automatically set by the message class,"
640 0 : " it cannot be set as a default field.");
641 : }
642 :
643 0 : guard g;
644 :
645 0 : f_default_fields[name] = value;
646 0 : }
647 0 : }
648 :
649 :
650 0 : std::string logger::get_default_field(std::string const & name) const
651 : {
652 0 : guard g;
653 :
654 0 : auto it(f_default_fields.find(name));
655 0 : if(it != f_default_fields.end())
656 : {
657 0 : return it->second;
658 : }
659 0 : return std::string();
660 0 : }
661 :
662 :
663 91296 : field_map_t logger::get_default_fields() const
664 : {
665 91296 : guard g;
666 :
667 182592 : return f_default_fields;
668 91296 : }
669 :
670 :
671 0 : void logger::remove_default_field(std::string const & name)
672 : {
673 0 : guard g;
674 :
675 0 : auto it(f_default_fields.find(name));
676 0 : if(it != f_default_fields.end())
677 : {
678 0 : f_default_fields.erase(it);
679 : }
680 0 : }
681 :
682 :
683 0 : bool logger::is_asynchronous() const
684 : {
685 0 : guard g;
686 :
687 0 : return f_asynchronous;
688 0 : }
689 :
690 :
691 18 : void logger::set_asynchronous(bool status)
692 : {
693 18 : status = status != false;
694 :
695 18 : bool do_delete(false);
696 : {
697 18 : guard g;
698 :
699 18 : if(f_asynchronous != status)
700 : {
701 2 : f_asynchronous = status;
702 2 : if(!f_asynchronous)
703 : {
704 1 : do_delete = true;
705 : }
706 : }
707 18 : }
708 :
709 18 : if(do_delete)
710 : {
711 1 : private_logger * l(dynamic_cast<private_logger *>(this));
712 1 : l->delete_thread();
713 : }
714 18 : }
715 :
716 :
717 91295 : void logger::log_message(message const & msg)
718 : {
719 91295 : if(const_cast<message &>(msg).tellp() > 0)
720 : {
721 45747 : bool asynchronous(false);
722 : {
723 45747 : guard g;
724 :
725 45747 : if(f_asynchronous)
726 : {
727 1 : message::pointer_t m(std::make_shared<message>(msg, msg));
728 1 : private_logger * l(dynamic_cast<private_logger *>(this));
729 1 : l->send_message_to_thread(m);
730 1 : asynchronous = true;
731 1 : }
732 45747 : }
733 :
734 45747 : if(!asynchronous)
735 : {
736 45746 : process_message(msg);
737 : }
738 : }
739 :
740 182578 : if(f_fatal_severity != severity_t::SEVERITY_OFF
741 91289 : && msg.get_severity() >= f_fatal_severity)
742 : {
743 0 : call_fatal_error_callback();
744 0 : throw fatal_error("A fatal error occurred.");
745 : }
746 91289 : }
747 :
748 :
749 45747 : void logger::process_message(message const & msg)
750 : {
751 45747 : appender::vector_t appenders;
752 :
753 : {
754 45747 : guard g;
755 :
756 45747 : bool include(f_components_to_include.empty());
757 45747 : component::set_t const & components(msg.get_components());
758 45747 : if(components.empty())
759 : {
760 45738 : if(f_components_to_ignore.find(f_normal_component) != f_components_to_ignore.end())
761 : {
762 0 : return;
763 : }
764 45738 : if(!include)
765 : {
766 0 : if(f_components_to_include.find(f_normal_component) != f_components_to_include.end())
767 : {
768 0 : include = true;
769 : }
770 : }
771 : }
772 : else
773 : {
774 22 : for(auto c : components)
775 : {
776 15 : if(f_components_to_ignore.find(c) != f_components_to_ignore.end())
777 : {
778 2 : return;
779 : }
780 13 : if(!include)
781 : {
782 0 : if(f_components_to_include.find(c) != f_components_to_include.end())
783 : {
784 0 : include = true;
785 : }
786 : }
787 15 : }
788 : }
789 45745 : if(!include)
790 : {
791 0 : return;
792 : }
793 :
794 45745 : if(f_appenders.empty())
795 : {
796 0 : if(isatty(fileno(stdout)))
797 : {
798 0 : add_console_appender();
799 : }
800 : else
801 : {
802 0 : add_syslog_appender(std::string());
803 : }
804 : }
805 :
806 45745 : ++f_severity_stats[static_cast<std::size_t>(msg.get_severity())];
807 :
808 45745 : appenders = f_appenders;
809 45747 : }
810 :
811 91532 : for(auto a : appenders)
812 : {
813 45793 : a->send_message(msg);
814 45793 : }
815 45747 : }
816 :
817 :
818 0 : void logger::set_fatal_error_severity(severity_t sev)
819 : {
820 0 : f_fatal_severity = sev;
821 0 : }
822 :
823 :
824 0 : void logger::set_fatal_error_callback(std::function<void(void)> & f)
825 : {
826 0 : f_fatal_error_callback = f;
827 0 : }
828 :
829 :
830 0 : void logger::call_fatal_error_callback()
831 : {
832 0 : if(f_fatal_error_callback != nullptr)
833 : {
834 0 : f_fatal_error_callback();
835 : }
836 0 : }
837 :
838 :
839 : /** \brief Return statistics about log severities.
840 : *
841 : * This function returns the statistics counting each message sent per
842 : * severity.
843 : *
844 : * If you enabled the asynchronous functionality of the snaplogger,
845 : * then this statistics may not reflect the current state as the
846 : * logger thread may still not have processed all the messages.
847 : *
848 : * \note
849 : * The severity_stats_t type is a vector that includes all possible
850 : * severity levels (0 to 255), including severity levels that are not
851 : * currently declared. It is done that way so the access is as fast
852 : * as possible when we want to increment one of the stats. Using a
853 : * map would have a much greater impact on the process_message()
854 : * function.
855 : *
856 : * \return a copy of the severity statistics at the time of the call.
857 : */
858 0 : severity_stats_t logger::get_severity_stats() const
859 : {
860 0 : guard g;
861 :
862 0 : return f_severity_stats;
863 0 : }
864 :
865 :
866 0 : bool is_configured()
867 : {
868 0 : guard g;
869 :
870 0 : if(g_instance == nullptr)
871 : {
872 0 : return false;
873 : }
874 :
875 0 : return (*g_instance)->is_configured();
876 0 : }
877 :
878 :
879 0 : bool has_appender(std::string const & type)
880 : {
881 0 : guard g;
882 :
883 0 : if(g_instance == nullptr)
884 : {
885 0 : return false;
886 : }
887 :
888 0 : return (*g_instance)->has_appender(type);
889 0 : }
890 :
891 :
892 0 : void reopen()
893 : {
894 0 : guard g;
895 :
896 0 : if(g_instance == nullptr)
897 : {
898 0 : return;
899 : }
900 :
901 0 : (*g_instance)->reopen();
902 0 : }
903 :
904 :
905 0 : bool configure_console(bool force)
906 : {
907 0 : bool result(!is_configured() || (force && !has_appender("console")));
908 0 : if(result)
909 : {
910 0 : logger::get_instance()->add_console_appender();
911 : }
912 :
913 0 : return result;
914 : }
915 :
916 :
917 0 : bool configure_syslog(std::string const & identity)
918 : {
919 0 : bool result(!is_configured());
920 0 : if(result)
921 : {
922 0 : logger::get_instance()->add_syslog_appender(identity);
923 : }
924 :
925 0 : return result;
926 : }
927 :
928 :
929 0 : bool configure_file(std::string const & filename)
930 : {
931 0 : bool result(!is_configured());
932 0 : if(result)
933 : {
934 0 : logger::get_instance()->add_file_appender(filename);
935 : }
936 :
937 0 : return result;
938 : }
939 :
940 :
941 0 : bool configure_config(std::string const & config_filename)
942 : {
943 0 : bool result(!is_configured());
944 0 : if(result)
945 : {
946 0 : logger::get_instance()->add_config(config_filename);
947 : }
948 :
949 0 : return result;
950 : }
951 :
952 :
953 :
954 :
955 : } // snaplogger namespace
956 : // vim: ts=4 sw=4 et
|