Line data Source code
1 : // Snap Websites Server -- log services
2 : // Copyright (c) 2013-2019 Made to Order Software Corp. All Rights Reserved
3 : //
4 : // This program is free software; you can redistribute it and/or modify
5 : // it under the terms of the GNU General Public License as published by
6 : // the Free Software Foundation; either version 2 of the License, or
7 : // (at your option) any later version.
8 : //
9 : // This program is distributed in the hope that it will be useful,
10 : // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 : // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 : // GNU General Public License for more details.
13 : //
14 : // You should have received a copy of the GNU General Public License
15 : // along with this program; if not, write to the Free Software
16 : // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17 :
18 : // self
19 : //
20 : #include "snapwebsites/log.h"
21 :
22 :
23 : // snapwebsite lib
24 : //
25 : #include "snapwebsites/qstring_stream.h"
26 : #include "snapwebsites/snap_exception.h"
27 : #include "snapwebsites/snapwebsites.h"
28 :
29 :
30 : // snapdev lib
31 : //
32 : #include <snapdev/not_reached.h>
33 : #include <snapdev/not_used.h>
34 :
35 :
36 : // boost lib
37 : //
38 : #include <boost/algorithm/string/replace.hpp>
39 :
40 :
41 : // Qt lib
42 : //
43 : #include <QFileInfo>
44 :
45 :
46 : // log4cplus lib
47 : //
48 : // this one wants to be compatible with (really) old compilers and thus
49 : // uses std::auto_ptr<>() which throws an error in our code
50 : //
51 : #pragma GCC diagnostic push
52 : #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
53 : #pragma GCC diagnostic ignored "-Weffc++"
54 : #include <log4cplus/configurator.h>
55 : #include <log4cplus/consoleappender.h>
56 : #include <log4cplus/fileappender.h>
57 : #include <log4cplus/helpers/property.h>
58 : #include <log4cplus/logger.h>
59 : #include <log4cplus/socketappender.h>
60 : #include <log4cplus/spi/loggingevent.h>
61 : #include <log4cplus/spi/factory.h>
62 : #include <log4cplus/syslogappender.h>
63 : #pragma GCC diagnostic pop
64 :
65 :
66 : // C lib
67 : //
68 : #include <syslog.h>
69 :
70 :
71 :
72 : // last include
73 : //
74 : #include <snapdev/poison.h>
75 :
76 :
77 :
78 :
79 : /** \file
80 : * \brief Handle logging in the Snap environment.
81 : *
82 : * The snap::logging namespace defines a set of functions and classes used
83 : * to setup the snap logger that can be easily accessed with the following
84 : * macros:
85 : *
86 : * \li SNAP_LOG_FATAL -- output what is viewed as fatal error
87 : * \li SNAP_LOG_ERROR -- output an error
88 : * \li SNAP_LOG_WARNING -- output a warning
89 : * \li SNAP_LOG_INFO -- output some information
90 : * \li SNAP_LOG_DEBUG -- output debug information
91 : * \li SNAP_LOG_TRACE -- output trace information
92 : *
93 : * The macros should be used so that way you include the filename and line
94 : * number of where the message is generated from. That information is then
95 : * available to be printed in the logs.
96 : *
97 : * The macros define a logger object that accepts messages with either the
98 : * << operator or the () operator, both of which support null terminated
99 : * C strings (char and wchar_t), QString, std::string, std::wstring,
100 : * and all basic types (integers and floats).
101 : *
102 : * The () operator also accepts the security enumeration as input, so you
103 : * can change the level to SECURE at any time when you generate a log.
104 : *
105 : * \code
106 : * SNAP_LOG_INFO("User password is: ")
107 : * (snap::logging::log_security_t::LOG_SECURITY_SECURE)
108 : * (password);
109 : *
110 : * SNAP_LOG_FATAL("We could not read resources: ") << filename;
111 : * \endcode
112 : *
113 : * Try to remember that the \\n character is not necessary. The logger
114 : * will automatically add a newline at the end of each log message.
115 : *
116 : * \note
117 : * The newer versions of the log4cplus library offer a very similar set
118 : * of macros. These macro, though, do not properly check out all of
119 : * our flags and levels so you should avoid them for now.
120 : *
121 : * To setup the logging system, the snapserver makes use of the following
122 : * files:
123 : *
124 : * \li log.properties
125 : * \li snapcgi.properties
126 : *
127 : * \code
128 : * log_config=/etc/snapwebsites/logger/log.properties
129 : * \endcode
130 : *
131 : * The backends run just like the snapserver so they get the same logger
132 : * settings.
133 : *
134 : * The snap.cgi tool, however, has its own setup. It first checks the
135 : * command line, and if no configuration is defined on the command
136 : * line it uses the log_config=... parameter from the snapcgi.conf
137 : * file. The default file is snapcgi.properties.
138 : *
139 : * \code
140 : * log_config=/etc/snapwebsites/logger/snapcgi.properties
141 : * \endcode
142 : *
143 : * \sa log4cplus/include/log4cplus/loggingmacros.h
144 : */
145 :
146 : namespace snap
147 : {
148 :
149 : namespace logging
150 : {
151 :
152 : namespace
153 : {
154 :
155 2 : std::string g_progname;
156 2 : QString g_log_config_filename;
157 2 : QString g_log_output_filename;
158 2 : messenger_t g_log_messenger;
159 2 : log4cplus::Logger g_logger;
160 2 : log4cplus::Logger g_secure_logger;
161 2 : log4cplus::Logger g_messenger_logger;
162 : bool g_messenger_logger_initialized = false;
163 :
164 : enum class logging_type_t
165 : {
166 : UNCONFIGURED_LOGGER
167 : , CONSOLE_LOGGER
168 : , FILE_LOGGER
169 : , CONFFILE_LOGGER
170 : , SYSLOG_LOGGER
171 : , MESSENGER_LOGGER
172 : };
173 :
174 : logging_type_t g_logging_type( logging_type_t::UNCONFIGURED_LOGGER );
175 : logging_type_t g_last_logging_type( logging_type_t::UNCONFIGURED_LOGGER );
176 :
177 :
178 :
179 0 : class logger_stub
180 : : public logger
181 : {
182 : public:
183 0 : logger_stub(log_level_t const log_level, char const * file, char const * func, int const line)
184 0 : : logger(log_level, file, func, line)
185 : {
186 0 : f_ignore = true;
187 0 : }
188 :
189 : logger_stub(logger const & l)
190 : : logger(l)
191 : {
192 : }
193 :
194 : logger & operator () () { return *this; }
195 : logger & operator () (log_security_t const v) { NOTUSED(v); return *this; }
196 : logger & operator () (char const * s) { NOTUSED(s); return *this; }
197 : logger & operator () (wchar_t const * s) { NOTUSED(s); return *this; }
198 : logger & operator () (std::string const & s) { NOTUSED(s); return *this; }
199 : logger & operator () (std::wstring const & s) { NOTUSED(s); return *this; }
200 : logger & operator () (QString const & s) { NOTUSED(s); return *this; }
201 : logger & operator () (snap::snap_config::snap_config_parameter_ref const & s) { NOTUSED(s); return *this; }
202 : logger & operator () (char const v) { NOTUSED(v); return *this; }
203 : logger & operator () (signed char const v) { NOTUSED(v); return *this; }
204 : logger & operator () (unsigned char const v) { NOTUSED(v); return *this; }
205 : logger & operator () (signed short const v) { NOTUSED(v); return *this; }
206 : logger & operator () (unsigned short const v) { NOTUSED(v); return *this; }
207 : logger & operator () (signed int const v) { NOTUSED(v); return *this; }
208 : logger & operator () (unsigned int const v) { NOTUSED(v); return *this; }
209 : logger & operator () (signed long const v) { NOTUSED(v); return *this; }
210 : logger & operator () (unsigned long const v) { NOTUSED(v); return *this; }
211 : logger & operator () (signed long long const v) { NOTUSED(v); return *this; }
212 : logger & operator () (unsigned long long const v) { NOTUSED(v); return *this; }
213 : logger & operator () (float const v) { NOTUSED(v); return *this; }
214 : logger & operator () (double const v) { NOTUSED(v); return *this; }
215 : logger & operator () (bool const v) { NOTUSED(v); return *this; }
216 : logger & operator () (void const * p) { NOTUSED(p); return *this; }
217 : };
218 :
219 :
220 : class MessengerAppender
221 : : public log4cplus::Appender
222 : {
223 : public:
224 0 : MessengerAppender()
225 0 : {
226 0 : }
227 :
228 0 : MessengerAppender(log4cplus::helpers::Properties const & props)
229 0 : : Appender(props)
230 : {
231 0 : }
232 :
233 0 : virtual ~MessengerAppender() override
234 0 : {
235 0 : destructorImpl();
236 0 : }
237 :
238 0 : virtual void close() override
239 : {
240 0 : }
241 :
242 0 : static void registerAppender()
243 : {
244 : // The registration must run just once and static variables
245 : // are initialized just once
246 : //
247 0 : static bool const g_registered = []()
248 : {
249 0 : log4cplus::spi::AppenderFactoryRegistry & reg(log4cplus::spi::getAppenderFactoryRegistry());
250 :
251 : // there are macros to do the following, but it uses the log4cplus
252 : // namespace which is not terribly useful in our case
253 : //
254 : #pragma GCC diagnostic push
255 : #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
256 0 : reg.put(std::auto_ptr<log4cplus::spi::AppenderFactory>(
257 : new log4cplus::spi::FactoryTempl<snap::logging::MessengerAppender, log4cplus::spi::AppenderFactory>(
258 : LOG4CPLUS_TEXT("snap::logging::")
259 0 : LOG4CPLUS_TEXT("MessengerAppender"))));
260 : #pragma GCC diagnostic pop
261 :
262 0 : return false;
263 0 : }();
264 :
265 0 : NOTUSED(g_registered);
266 0 : }
267 :
268 : protected:
269 0 : virtual void append(const log4cplus::spi::InternalLoggingEvent& event) override
270 : {
271 0 : auto messenger( g_log_messenger.lock() );
272 0 : if( messenger != nullptr ) // silently fail if the shared object has been deleted...
273 : {
274 0 : char const * level_str("unknown");
275 0 : switch( event.getLogLevel() )
276 : {
277 0 : case log4cplus::FATAL_LOG_LEVEL:
278 0 : level_str = "fatal error";
279 0 : break;
280 :
281 0 : case log4cplus::ERROR_LOG_LEVEL:
282 0 : level_str = "error";
283 0 : break;
284 :
285 0 : case log4cplus::WARN_LOG_LEVEL:
286 0 : level_str = "warning";
287 0 : break;
288 :
289 0 : case log4cplus::INFO_LOG_LEVEL:
290 0 : level_str = "info";
291 0 : break;
292 :
293 0 : case log4cplus::DEBUG_LOG_LEVEL:
294 0 : level_str = "debug";
295 0 : break;
296 :
297 0 : case log4cplus::TRACE_LOG_LEVEL:
298 0 : level_str = "trace";
299 0 : break;
300 : }
301 :
302 : // Send the log to snapcommunicator, and eventually to snaplog.
303 : //
304 0 : snap::snap_communicator_message request;
305 0 : request.set_command("SNAPLOG");
306 0 : request.set_service("snaplog");
307 0 : request.add_parameter( "cache", "ttl=60" );
308 0 : request.add_parameter( "level", level_str );
309 0 : request.add_parameter( "file", QString::fromUtf8(event.getFile().c_str()) );
310 0 : request.add_parameter( "func", QString::fromUtf8(event.getFunction().c_str()) );
311 0 : request.add_parameter( "line", event.getLine() );
312 0 : request.add_parameter( "message", QString::fromUtf8(event.getMessage().c_str()) );
313 :
314 0 : messenger->send_message(request);
315 : }
316 0 : }
317 :
318 : private:
319 : };
320 :
321 :
322 : /** \brief Check whether the logger exists.
323 : *
324 : * Although it should never happens, the alloc_dc() function throws
325 : * a logic_error exception if called when it is already initialized.
326 : * For this reason we have this function which makes sure that the
327 : * exception does not occur (in part because it is called from the
328 : * logger destructor)
329 : *
330 : * \param[in] name The name of the logger to retrieve.
331 : *
332 : * \return true if the logger exists, false otherwise.
333 : */
334 0 : bool logger_exists(char const * name)
335 : {
336 : try
337 : {
338 0 : return log4cplus::Logger::exists(name);
339 : }
340 0 : catch(std::logic_error const & )
341 : {
342 : // no logging for this error, we are in the logger and it failed!
343 0 : return false;
344 : }
345 : }
346 :
347 :
348 : }
349 : // no name namespace
350 :
351 :
352 : /** \brief Set the name of the program.
353 : *
354 : * This function is used to setup the logger progname parameter.
355 : * Although we had a server::instance()->servername() call, that
356 : * would not work with tools that do not start the server code,
357 : * so better have a function to do that setup.
358 : *
359 : * \param[in] progname The name of the program initializing the logger.
360 : *
361 : * \sa get_progname()
362 : */
363 0 : void set_progname( std::string const & progname )
364 : {
365 0 : g_progname = progname;
366 0 : }
367 :
368 :
369 : /** \brief Retrieve the program name.
370 : *
371 : * This function returns the program name as set with set_progname().
372 : * If the program name was not set, then this function attempts to
373 : * define it from the server::instance()->servername() function. If
374 : * still empty, then the function throws so we (should) know right
375 : * away that something is wrong.
376 : *
377 : * \exception snap_exception
378 : * This exception is raised if the set_progname() is never called.
379 : *
380 : * \return The name of the program.
381 : *
382 : * \sa set_progname()
383 : */
384 0 : std::string get_progname()
385 : {
386 0 : if(g_progname.empty())
387 : {
388 0 : throw snap_exception( "g_progname undefined, please make sure to call set_progname() before calling any logger functions (even if with a fixed name at first)" );
389 : }
390 :
391 0 : return g_progname;
392 : }
393 :
394 :
395 :
396 : /** \brief Setup the messenger for the messenger appender.
397 : *
398 : * This function saves a copy of the smart pointer of the connection
399 : * to snapcommunicator in the logger.
400 : *
401 : * This connection will be used if available and a messenger logger
402 : * is setup.
403 : *
404 : * \param[in] messenger A connection to snapcommunicator.
405 : */
406 0 : void set_log_messenger( messenger_t messenger )
407 : {
408 0 : if( messenger.lock() == nullptr )
409 : {
410 0 : throw snap_exception( "Snap communicator messenger must be allocated!" );
411 : }
412 :
413 0 : g_log_messenger = messenger;
414 0 : }
415 :
416 :
417 : /** \brief Unconfigure the logger and reset.
418 : *
419 : * This is an internal function which is here to prevent code duplication.
420 : *
421 : * \sa configure()
422 : */
423 0 : void unconfigure()
424 : {
425 0 : if( g_logging_type != logging_type_t::UNCONFIGURED_LOGGER )
426 : {
427 : // shutdown the previous version before re-configuring
428 : // (this is done after a fork() call.)
429 : //
430 0 : log4cplus::Logger::shutdown();
431 0 : g_logging_type = logging_type_t::UNCONFIGURED_LOGGER;
432 : //g_last_logging_type = ... -- keep the last valid configuration
433 : // type so we can call reconfigure() and get it back "as expected"
434 :
435 : // TBD: should we clear the logger and secure logger instances?
436 : //g_logger = log4cplus::Logger();
437 : //g_secure_logger = log4cplus::Logger();
438 : }
439 :
440 : // register our appender
441 : //
442 : // Note: this function gets called by all the configure_...() functions
443 : // so it is a fairly logical place to do that registration...
444 : //
445 0 : MessengerAppender::registerAppender();
446 0 : }
447 :
448 :
449 : /** \brief Configure log4cplus system to the console.
450 : *
451 : * This function is the default called in case the user has not specified
452 : * a configuration file to read.
453 : *
454 : * It sets up a default appender to the standard output.
455 : *
456 : * \note
457 : * This function marks that the logger was configured. The other functions
458 : * do not work (do nothing) until this happens. In case of the server,
459 : * configure() is called from the server::config() function. If no configuration
460 : * file is defined then the other functions will do nothing.
461 : *
462 : * Format documentation:
463 : * http://log4cplus.sourceforge.net/docs/html/classlog4cplus_1_1PatternLayout.html
464 : *
465 : * \sa fatal()
466 : * \sa error()
467 : * \sa warning()
468 : * \sa info()
469 : * \sa server::config()
470 : * \sa unconfigure()
471 : */
472 0 : void configure_console()
473 : {
474 0 : unconfigure();
475 :
476 0 : log4cplus::SharedAppenderPtr appender(new log4cplus::ConsoleAppender());
477 0 : appender->setName(LOG4CPLUS_TEXT("console"));
478 : const log4cplus::tstring pattern
479 0 : ( boost::replace_all_copy(get_progname(), "%", "%%").c_str()
480 0 : + log4cplus::tstring("[%i]:%b:%L:%h: %m%n")
481 0 : );
482 : //const log4cplus::tstring pattern( "%b:%L:%h: %m%n" );
483 : // log4cplus only accepts std::auto_ptr<> which is deprecated in newer versions
484 : // of g++ so we have to make sure the deprecation definition gets ignored
485 : #pragma GCC diagnostic push
486 : #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
487 0 : appender->setLayout( std::auto_ptr<log4cplus::Layout>( new log4cplus::PatternLayout(pattern) ) );
488 : #pragma GCC diagnostic pop
489 0 : appender->setThreshold( log4cplus::TRACE_LOG_LEVEL );
490 :
491 0 : g_log_config_filename.clear();
492 0 : g_log_output_filename.clear();
493 0 : g_logging_type = logging_type_t::CONSOLE_LOGGER;
494 0 : g_last_logging_type = logging_type_t::CONSOLE_LOGGER;
495 0 : g_logger = log4cplus::Logger::getInstance("snap");
496 0 : g_secure_logger = log4cplus::Logger::getInstance("security");
497 :
498 0 : g_logger.addAppender( appender );
499 0 : g_secure_logger.addAppender( appender );
500 0 : set_log_output_level( log_level_t::LOG_LEVEL_INFO );
501 0 : }
502 :
503 :
504 : /** \brief Configure log4cplus system turning on the rolling file appender.
505 : *
506 : * This function is called when the user has specified to write logs to a file.
507 : *
508 : * \note
509 : * This function marks that the logger was configured. The other functions
510 : * do not work (do nothing) until this happens. In case of the server,
511 : * configure() is called from the server::config() function. If no configuration
512 : * file is defined then the other functions will do nothing.
513 : *
514 : * \param[in] logfile The name of the configuration file.
515 : *
516 : * \sa fatal()
517 : * \sa error()
518 : * \sa warning()
519 : * \sa info()
520 : * \sa server::config()
521 : * \sa unconfigure()
522 : */
523 0 : void configure_logfile( QString const & logfile )
524 : {
525 0 : unconfigure();
526 :
527 0 : if( logfile.isEmpty() )
528 : {
529 0 : throw snap_exception( "No output logfile specified!" );
530 : }
531 :
532 0 : QByteArray utf8_name(logfile.toUtf8());
533 0 : log4cplus::SharedAppenderPtr appender(new log4cplus::RollingFileAppender( utf8_name.data() ));
534 0 : appender->setName(LOG4CPLUS_TEXT("log_file"));
535 : log4cplus::tstring const pattern
536 0 : ( log4cplus::tstring("%d{%Y/%m/%d %H:%M:%S} %h ")
537 0 : + boost::replace_all_copy(get_progname(), "%", "%%").c_str()
538 0 : + log4cplus::tstring("[%i]: %m (%b:%L)%n")
539 0 : );
540 : // log4cplus only accepts std::auto_ptr<> which is deprecated in newer versions
541 : // of g++ so we have to make sure the deprecation definition gets ignored
542 : #pragma GCC diagnostic push
543 : #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
544 0 : appender->setLayout( std::auto_ptr<log4cplus::Layout>( new log4cplus::PatternLayout(pattern) ) );
545 : #pragma GCC diagnostic pop
546 0 : appender->setThreshold( log4cplus::TRACE_LOG_LEVEL );
547 :
548 0 : g_log_config_filename.clear();
549 0 : g_log_output_filename = logfile;
550 0 : g_logging_type = logging_type_t::FILE_LOGGER;
551 0 : g_last_logging_type = logging_type_t::FILE_LOGGER;
552 0 : g_logger = log4cplus::Logger::getInstance( "snap" );
553 0 : g_secure_logger = log4cplus::Logger::getInstance( "security" );
554 :
555 0 : g_logger.addAppender( appender );
556 0 : g_secure_logger.addAppender( appender );
557 0 : set_log_output_level( log_level_t::LOG_LEVEL_INFO );
558 0 : }
559 :
560 :
561 : /** \brief Configure a messenger instance.
562 : *
563 : * Log entries are sent to snapcommunicator. The configured log level of
564 : * the "snap" logger is used to determine what to send "over the wire."
565 : * This is making the assumption that you have set up the "snap" logger
566 : * correctly.
567 : *
568 : * Note that in most cases you want to use configure_logfile() which
569 : * can define a messenger too, without the need to call this function.
570 : *
571 : * \warning
572 : * Make sure that you call the set_log_messenger() function with a
573 : * connection to snapcommunicator or this appender won't do anything.
574 : */
575 0 : void configure_messenger()
576 : {
577 0 : unconfigure();
578 :
579 0 : log4cplus::SharedAppenderPtr appender( new MessengerAppender );
580 0 : appender->setName( LOG4CPLUS_TEXT("snapcommunicator") );
581 : log4cplus::tstring const pattern
582 0 : ( log4cplus::tstring("%d{%Y/%m/%d %H:%M:%S} %h ")
583 0 : + boost::replace_all_copy(get_progname(), "%", "%%").c_str()
584 0 : + log4cplus::tstring("[%i]: %m (%b:%L)%n")
585 0 : );
586 : // log4cplus only accepts std::auto_ptr<> which is deprecated in newer versions
587 : // of g++ so we have to make sure the deprecation definition gets ignored
588 : #pragma GCC diagnostic push
589 : #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
590 0 : appender->setLayout( std::auto_ptr<log4cplus::Layout>( new log4cplus::PatternLayout(pattern) ) );
591 : #pragma GCC diagnostic pop
592 0 : appender->setThreshold( log4cplus::TRACE_LOG_LEVEL );
593 :
594 0 : g_logging_type = logging_type_t::MESSENGER_LOGGER;
595 0 : g_last_logging_type = logging_type_t::MESSENGER_LOGGER;
596 0 : g_messenger_logger = log4cplus::Logger::getInstance( "messenger" );
597 :
598 0 : g_messenger_logger_initialized = true;
599 :
600 0 : g_messenger_logger.addAppender( appender );
601 0 : set_log_output_level( log_level_t::LOG_LEVEL_INFO );
602 0 : }
603 :
604 :
605 : /** \brief Configure log4cplus system to the syslog.
606 : *
607 : * Set up the logging to be routed to the syslog.
608 : *
609 : * \note
610 : * This function marks that the logger was configured. The other functions
611 : * do not work (do nothing) until this happens. In case of the snap server,
612 : * configure() is called from the server::config() function. If no
613 : * configuration file is defined then the other functions will do nothing.
614 : *
615 : * Format documentation:
616 : * http://log4cplus.sourceforge.net/docs/html/classlog4cplus_1_1PatternLayout.html
617 : *
618 : * \sa fatal()
619 : * \sa error()
620 : * \sa warning()
621 : * \sa info()
622 : * \sa server::config()
623 : * \sa unconfigure()
624 : */
625 0 : void configure_syslog()
626 : {
627 0 : unconfigure();
628 :
629 : // set identifier to: "<progname>[<pid>]:" as expected in syslog on Ubuntu
630 : //
631 0 : std::string const ident("snapcpp/" + boost::replace_all_copy(get_progname(), "%", "%%") + "[" + std::to_string(getpid()) + "]");
632 0 : log4cplus::SharedAppenderPtr appender( new log4cplus::SysLogAppender( ident ) );
633 :
634 : // define the pattern as "<message> (<source filename>:<line>)"
635 : //
636 0 : log4cplus::tstring const pattern(log4cplus::tstring("%m (%b:%L)%n"));
637 :
638 : // log4cplus only accepts std::auto_ptr<> which is deprecated in newer versions
639 : // of g++ so we have to make sure the deprecated definition gets ignored
640 : #pragma GCC diagnostic push
641 : #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
642 0 : appender->setLayout( std::auto_ptr<log4cplus::Layout>( new log4cplus::PatternLayout(pattern) ) );
643 : #pragma GCC diagnostic pop
644 0 : appender->setThreshold( log4cplus::TRACE_LOG_LEVEL );
645 :
646 0 : g_log_config_filename.clear();
647 0 : g_log_output_filename.clear();
648 0 : g_logging_type = logging_type_t::SYSLOG_LOGGER;
649 0 : g_last_logging_type = logging_type_t::SYSLOG_LOGGER;
650 0 : g_logger = log4cplus::Logger::getInstance("snap");
651 0 : g_secure_logger = log4cplus::Logger::getInstance("security");
652 :
653 0 : g_logger.addAppender( appender );
654 0 : g_secure_logger.addAppender( appender );
655 0 : set_log_output_level( log_level_t::LOG_LEVEL_INFO );
656 0 : }
657 :
658 :
659 : /** \brief Configure from a log4cplus header file.
660 : *
661 : * This function sends the specified \p filename to the log4cplus configurator
662 : * for initialization.
663 : *
664 : * If \p filename is empty (undefined in the server configuration file) then
665 : * the /etc/snapwebsites/log.conf file is used if it exists. If not, then
666 : * no configuration is created.
667 : *
668 : * \note
669 : * This function marks that the logger was configured. The other functions
670 : * do not work (do nothing) until this happens. In case of the server,
671 : * configure() is called from the server::config() function. If no configuration
672 : * file is defined then the other functions will do nothing.
673 : *
674 : * \todo
675 : * We may also want to get the progname so we can setup the system with that
676 : * name, although at this time we offer different configuration files for
677 : * each process.
678 : *
679 : * \param[in] filename The name of the configuration file.
680 : *
681 : * \sa fatal()
682 : * \sa error()
683 : * \sa warning()
684 : * \sa info()
685 : * \sa server::config()
686 : * \sa unconfigure()
687 : */
688 0 : void configure_conffile(QString const & filename)
689 : {
690 0 : unconfigure();
691 :
692 0 : QFileInfo info(filename);
693 0 : if(!info.exists())
694 : {
695 0 : throw snap_exception( QObject::tr("Cannot open logger configuration file [%1].").arg(filename) );
696 : }
697 :
698 0 : g_log_config_filename = filename;
699 0 : g_log_output_filename.clear();
700 0 : g_logging_type = logging_type_t::CONFFILE_LOGGER;
701 0 : g_last_logging_type = logging_type_t::CONFFILE_LOGGER;
702 :
703 : // note the doConfigure() may throw if the log.properties is invalid
704 : //
705 0 : log4cplus::PropertyConfigurator::doConfigure(LOG4CPLUS_C_STR_TO_TSTRING(filename.toUtf8().data()));
706 :
707 0 : g_logger = log4cplus::Logger::getInstance("snap");
708 0 : g_secure_logger = log4cplus::Logger::getInstance("security");
709 :
710 0 : g_messenger_logger_initialized = logger_exists("messenger");
711 0 : if(g_messenger_logger_initialized)
712 : {
713 0 : g_messenger_logger = log4cplus::Logger::getInstance("messenger");
714 : }
715 0 : }
716 :
717 :
718 : /** \brief Ensure that the configuration is still in place.
719 : *
720 : * On a fork() the configuration of log4cplus is lost. We have to
721 : * call this function again before we can use the logs again.
722 : *
723 : * \note
724 : * TBD -- is it really necessary to reconfigure after a fork() or
725 : * would the logger know how to handle that case?
726 : */
727 0 : void reconfigure()
728 : {
729 0 : switch( g_last_logging_type )
730 : {
731 0 : case logging_type_t::CONSOLE_LOGGER:
732 0 : configure_console();
733 0 : break;
734 :
735 0 : case logging_type_t::FILE_LOGGER:
736 0 : configure_logfile( g_log_output_filename );
737 0 : break;
738 :
739 0 : case logging_type_t::CONFFILE_LOGGER:
740 0 : configure_conffile( g_log_config_filename );
741 0 : break;
742 :
743 0 : case logging_type_t::SYSLOG_LOGGER:
744 0 : configure_syslog();
745 0 : break;
746 :
747 0 : case logging_type_t::MESSENGER_LOGGER:
748 0 : configure_messenger();
749 0 : break;
750 :
751 0 : default:
752 : /* do nearly nothing */
753 0 : unconfigure();
754 0 : break;
755 :
756 : }
757 0 : }
758 :
759 :
760 : /** \brief Return the current configuration status.
761 : *
762 : * This function returns true if the log facility was successfully
763 : * configured, false otherwise.
764 : *
765 : * \return true if the configure() function was called with success.
766 : */
767 0 : bool is_configured()
768 : {
769 0 : return g_logging_type != logging_type_t::UNCONFIGURED_LOGGER;
770 : }
771 :
772 :
773 : /** \brief Retrieve the current log level.
774 : *
775 : * This function returns the current log level. In most cases this is
776 : * used with the RAII class which saves the log level for a period
777 : * of time while you change the level before doing some work and want
778 : * to reset the level to what it was once done with that work.
779 : *
780 : * Note that we do not have a one to one mapping between our log levels
781 : * and the log4cplus log level. Instead we return the next level when
782 : * it is not a match (it is possible to not be an exact match if the
783 : * administrator used a number to define the log level in the properties
784 : * file of the service using the Snap! logger.)
785 : *
786 : * \return The current level.
787 : */
788 0 : log_level_t get_log_output_level()
789 : {
790 0 : log4cplus::LogLevel level(g_logger.getLogLevel());
791 :
792 0 : if(level == log4cplus::NOT_SET_LOG_LEVEL)
793 : {
794 0 : return log_level_t::LOG_LEVEL_DEFAULT;
795 : }
796 :
797 0 : if(level <= log4cplus::TRACE_LOG_LEVEL)
798 : {
799 0 : return log_level_t::LOG_LEVEL_TRACE;
800 : }
801 :
802 0 : if(level <= log4cplus::DEBUG_LOG_LEVEL)
803 : {
804 0 : return log_level_t::LOG_LEVEL_DEBUG;
805 : }
806 :
807 0 : if(level <= log4cplus::INFO_LOG_LEVEL)
808 : {
809 0 : return log_level_t::LOG_LEVEL_INFO;
810 : }
811 :
812 0 : if(level <= log4cplus::WARN_LOG_LEVEL)
813 : {
814 0 : return log_level_t::LOG_LEVEL_WARNING;
815 : }
816 :
817 0 : if(level <= log4cplus::ERROR_LOG_LEVEL)
818 : {
819 0 : return log_level_t::LOG_LEVEL_ERROR;
820 : }
821 :
822 0 : if(level <= log4cplus::FATAL_LOG_LEVEL)
823 : {
824 0 : return log_level_t::LOG_LEVEL_FATAL;
825 : }
826 :
827 : // anything higher is considered to be OFF
828 0 : return log_level_t::LOG_LEVEL_OFF;
829 : }
830 :
831 :
832 : /* \brief Set the current logging threshold.
833 : *
834 : * Tells log4cplus to limit the logging output to the specified threshold.
835 : *
836 : * \todo
837 : * The log level should be cached if this function gets called before
838 : * the logger is setup. Right now, we lose the information.
839 : */
840 0 : void set_log_output_level( log_level_t level )
841 : {
842 0 : if(!is_configured())
843 : {
844 0 : return;
845 : }
846 :
847 0 : log4cplus::LogLevel new_level(log4cplus::OFF_LOG_LEVEL);
848 :
849 0 : switch(level)
850 : {
851 0 : case log_level_t::LOG_LEVEL_OFF:
852 0 : new_level = log4cplus::OFF_LOG_LEVEL;
853 0 : return;
854 :
855 0 : case log_level_t::LOG_LEVEL_FATAL:
856 0 : new_level = log4cplus::FATAL_LOG_LEVEL;
857 0 : break;
858 :
859 0 : case log_level_t::LOG_LEVEL_ERROR:
860 0 : new_level = log4cplus::ERROR_LOG_LEVEL;
861 0 : break;
862 :
863 0 : case log_level_t::LOG_LEVEL_WARNING:
864 0 : new_level = log4cplus::WARN_LOG_LEVEL;
865 0 : break;
866 :
867 0 : case log_level_t::LOG_LEVEL_INFO:
868 : //case log_level_t::LOG_LEVEL_DEFAULT:
869 0 : new_level = log4cplus::INFO_LOG_LEVEL;
870 0 : break;
871 :
872 0 : case log_level_t::LOG_LEVEL_DEBUG:
873 0 : new_level = log4cplus::DEBUG_LOG_LEVEL;
874 0 : break;
875 :
876 0 : case log_level_t::LOG_LEVEL_TRACE:
877 0 : new_level = log4cplus::TRACE_LOG_LEVEL;
878 0 : break;
879 :
880 : }
881 :
882 0 : log4cplus::Logger::getRoot().setLogLevel( new_level );
883 0 : g_logger.setLogLevel( new_level );
884 0 : g_secure_logger.setLogLevel( new_level );
885 0 : if(g_messenger_logger_initialized)
886 : {
887 0 : g_messenger_logger.setLogLevel( new_level );
888 : }
889 : }
890 :
891 :
892 : /* \brief Set the maximum logging threshold.
893 : *
894 : * Tells log4cplus to reduce the logging output to the specified threshold.
895 : * If the threshold is already that low or lower, nothing happens.
896 : *
897 : * \note
898 : * Our threshold levels are increasing when the log4cplus levels decrease...
899 : * Here we use "reduce" in the sense that we show more data and thus it
900 : * matches the log4cplus order.
901 : *
902 : * \todo
903 : * The conversion of our log level to the log4cplus level needs to be
904 : * in a separate function.
905 : */
906 0 : void reduce_log_output_level( log_level_t level )
907 : {
908 0 : if(!is_configured())
909 : {
910 0 : return;
911 : }
912 :
913 0 : log4cplus::LogLevel new_level = log4cplus::OFF_LOG_LEVEL;
914 :
915 0 : switch(level)
916 : {
917 0 : case log_level_t::LOG_LEVEL_OFF:
918 0 : new_level = log4cplus::OFF_LOG_LEVEL;
919 0 : return;
920 :
921 0 : case log_level_t::LOG_LEVEL_FATAL:
922 0 : new_level = log4cplus::FATAL_LOG_LEVEL;
923 0 : break;
924 :
925 0 : case log_level_t::LOG_LEVEL_ERROR:
926 0 : new_level = log4cplus::ERROR_LOG_LEVEL;
927 0 : break;
928 :
929 0 : case log_level_t::LOG_LEVEL_WARNING:
930 0 : new_level = log4cplus::WARN_LOG_LEVEL;
931 0 : break;
932 :
933 0 : case log_level_t::LOG_LEVEL_INFO:
934 0 : new_level = log4cplus::INFO_LOG_LEVEL;
935 0 : break;
936 :
937 0 : case log_level_t::LOG_LEVEL_DEBUG:
938 0 : new_level = log4cplus::DEBUG_LOG_LEVEL;
939 0 : break;
940 :
941 0 : case log_level_t::LOG_LEVEL_TRACE:
942 0 : new_level = log4cplus::TRACE_LOG_LEVEL;
943 0 : break;
944 :
945 : }
946 :
947 0 : log4cplus::Logger::getRoot().setLogLevel( new_level );
948 0 : if( new_level < g_logger.getLogLevel() )
949 : {
950 0 : g_logger.setLogLevel( new_level );
951 : }
952 0 : if( new_level < g_secure_logger.getLogLevel() )
953 : {
954 0 : g_secure_logger.setLogLevel( new_level );
955 : }
956 0 : if(g_messenger_logger_initialized)
957 : {
958 0 : if( new_level < g_messenger_logger.getLogLevel() )
959 : {
960 0 : g_messenger_logger.setLogLevel( new_level );
961 : }
962 : }
963 : }
964 :
965 :
966 : /** \brief Create a log object with the specified information.
967 : *
968 : * This function generates a log object that can be used to generate
969 : * a log message with the () operator and then gets logged using
970 : * log4cplus on destruction.
971 : *
972 : * The level can be set to any one of the log levels available in
973 : * the log_level_t enumeration. The special LOG_LEVEL_OFF value can be
974 : * used to avoid the log altogether (can be handy when you support a
975 : * varying log level.)
976 : *
977 : * By default logs are not marked as secure. If you are creating a log
978 : * that should only go to the secure logger, then use the () operator
979 : * with the LOG_SECURITY_SECURE value as in:
980 : *
981 : * \code
982 : * // use the "security" logger
983 : * SNAP_LOG_FATAL(LOG_SECURITY_SECURE)("this is not authorized!");
984 : * \endcode
985 : *
986 : * \param[in] log_level The level of logging.
987 : * \param[in] file The name of the source file that log was generated from.
988 : * \param[in] func The name of the function that log was generated from.
989 : * \param[in] line The line number that log was generated from.
990 : */
991 1 : logger::logger(log_level_t const log_level, char const * file, char const * func, int const line)
992 : : f_log_level(log_level)
993 : , f_file(file)
994 : , f_func(func)
995 : , f_line(line)
996 1 : , f_security(log_security_t::LOG_SECURITY_NONE)
997 : {
998 1 : }
999 :
1000 :
1001 : /** \brief Create a copy of this logger instance.
1002 : *
1003 : * This function creates a copy of the logger instance. This happens when
1004 : * you use the predefined fatal(), error(), warning(), ... functions since
1005 : * the logger instantiated inside the function is returned and thus copied
1006 : * once or twice (the number of copies will depend on the way the compiler
1007 : * is capable of optimizing our work.)
1008 : *
1009 : * \note
1010 : * The copy has a side effect on the input logger: it marks it as "please
1011 : * ignore that copy" so its destructor does not print out anything.
1012 : *
1013 : * \param[in] l The logger to duplicate.
1014 : */
1015 1 : logger::logger(logger const & l)
1016 1 : : f_log_level(l.f_log_level)
1017 1 : , f_file(l.f_file)
1018 1 : , f_func(l.f_func)
1019 1 : , f_line(l.f_line)
1020 1 : , f_security(l.f_security)
1021 6 : , f_message(l.f_message)
1022 : {
1023 1 : l.f_ignore = true;
1024 1 : }
1025 :
1026 :
1027 : /** \brief Output the log created with the () operators.
1028 : *
1029 : * The destructor of the log object is where things happen. This function
1030 : * prints out the message that was built using the different () operators
1031 : * and the parameters specified in the constructor.
1032 : *
1033 : * The snap log level is converted to a log4cplus log level (and a syslog
1034 : * level in case log4cplus is not available.)
1035 : *
1036 : * If the () operator was used with LOG_SECURITY_SECURE, then the message
1037 : * is sent using the "security" logger. Otherwise it uses the standard
1038 : * "snap" logger.
1039 : */
1040 4 : logger::~logger()
1041 : {
1042 2 : if(f_ignore)
1043 : {
1044 : // someone made a copy, this version we ignore
1045 1 : return;
1046 : }
1047 :
1048 1 : log4cplus::LogLevel ll(log4cplus::FATAL_LOG_LEVEL);
1049 1 : int sll(-1); // syslog level if log4cplus not available (if -1 do not syslog() anything)
1050 1 : bool console(false);
1051 1 : char const * level_str(nullptr);
1052 1 : switch(f_log_level)
1053 : {
1054 0 : case log_level_t::LOG_LEVEL_OFF:
1055 : // off means we do not emit anything
1056 0 : return;
1057 :
1058 0 : case log_level_t::LOG_LEVEL_FATAL:
1059 0 : ll = log4cplus::FATAL_LOG_LEVEL;
1060 0 : sll = LOG_CRIT;
1061 0 : console = true;
1062 0 : level_str = "fatal error";
1063 0 : break;
1064 :
1065 0 : case log_level_t::LOG_LEVEL_ERROR:
1066 0 : ll = log4cplus::ERROR_LOG_LEVEL;
1067 0 : sll = LOG_ERR;
1068 0 : console = true;
1069 0 : level_str = "error";
1070 0 : break;
1071 :
1072 0 : case log_level_t::LOG_LEVEL_WARNING:
1073 0 : ll = log4cplus::WARN_LOG_LEVEL;
1074 0 : sll = LOG_WARNING;
1075 0 : console = true;
1076 0 : level_str = "warning";
1077 0 : break;
1078 :
1079 0 : case log_level_t::LOG_LEVEL_INFO:
1080 0 : ll = log4cplus::INFO_LOG_LEVEL;
1081 0 : sll = LOG_INFO;
1082 0 : level_str = "info";
1083 0 : break;
1084 :
1085 1 : case log_level_t::LOG_LEVEL_DEBUG:
1086 1 : ll = log4cplus::DEBUG_LOG_LEVEL;
1087 1 : level_str = "debug";
1088 1 : break;
1089 :
1090 0 : case log_level_t::LOG_LEVEL_TRACE:
1091 0 : ll = log4cplus::TRACE_LOG_LEVEL;
1092 0 : level_str = "trace";
1093 0 : break;
1094 :
1095 : }
1096 :
1097 1 : if(f_file == nullptr)
1098 : {
1099 0 : f_file = "unknown-file";
1100 : }
1101 1 : if(f_func == nullptr)
1102 : {
1103 0 : f_func = "unknown-func";
1104 : }
1105 :
1106 : // TODO: instead of calling logger_exists() which is very expensive
1107 : // (because it uses a try/catch), we should instead have a flag
1108 : // to know whether a logger is properly configured; if so then
1109 : // we can use the else block.
1110 : //
1111 2 : if( (g_logging_type == logging_type_t::UNCONFIGURED_LOGGER)
1112 1 : || !logger_exists(log_security_t::LOG_SECURITY_SECURE == f_security ? "security" : "snap"))
1113 : {
1114 : // if not even configured, return immediately
1115 1 : if(sll != -1)
1116 : {
1117 0 : syslog(sll, "%s (%s:%s: %d)", f_message.toUtf8().data(), f_file, f_func, static_cast<int32_t>(f_line));
1118 : }
1119 : }
1120 : else
1121 : {
1122 0 : if(f_func)
1123 : {
1124 : // TBD: how should we really include the function name to the log4cplus messages?
1125 : //
1126 : // Note: we permit ourselves to modify f_message since we are in the destructor
1127 : // about to leave this object anyway.
1128 0 : f_message += QString(" (in function \"%1()\")").arg(f_func);
1129 : }
1130 :
1131 : // actually emit the log
1132 0 : if(log_security_t::LOG_SECURITY_SECURE == f_security)
1133 : {
1134 : // generally this at least goes in the /var/log/syslog
1135 : // and it may also go in a secure log file (i.e. not readable by everyone)
1136 : //
1137 0 : g_secure_logger.log(ll, LOG4CPLUS_C_STR_TO_TSTRING(f_message.toUtf8().data()), f_file, f_line, f_func);
1138 : }
1139 : else
1140 : {
1141 0 : g_logger.log(ll, LOG4CPLUS_C_STR_TO_TSTRING(f_message.toUtf8().data()), f_file, f_line, f_func);
1142 :
1143 : // full logger used, do not report error in console, logger can
1144 : // do it if the user wants to
1145 : //
1146 0 : console = false;
1147 : }
1148 : }
1149 :
1150 1 : if( g_messenger_logger_initialized )
1151 : {
1152 0 : g_messenger_logger.log( ll, LOG4CPLUS_C_STR_TO_TSTRING(f_message.toUtf8().data()), f_file, f_line, f_func );
1153 : }
1154 :
1155 1 : if(console && isatty(STDERR_FILENO))
1156 : {
1157 0 : std::cerr << level_str << ":" << f_file << ":" << f_line << ": " << f_message << std::endl;
1158 : }
1159 2 : }
1160 :
1161 :
1162 0 : logger & logger::operator () ()
1163 : {
1164 : // does nothing
1165 0 : return *this;
1166 : }
1167 :
1168 :
1169 0 : logger & logger::operator () (log_security_t const v)
1170 : {
1171 0 : f_security = v;
1172 0 : return *this;
1173 : }
1174 :
1175 :
1176 7 : logger & logger::operator () (char const * s)
1177 : {
1178 : // we assume UTF-8 because in our Snap environment most everything is
1179 : // TODO: change control characters to \xXX
1180 7 : if(s != nullptr)
1181 : {
1182 7 : f_message += QString::fromUtf8(s);
1183 : }
1184 7 : return *this;
1185 : }
1186 :
1187 :
1188 0 : logger & logger::operator () (wchar_t const * s)
1189 : {
1190 : // TODO: change control characters to \xXX
1191 0 : if(s != nullptr)
1192 : {
1193 0 : f_message += QString::fromWCharArray(s);
1194 : }
1195 0 : return *this;
1196 : }
1197 :
1198 :
1199 0 : logger & logger::operator () (std::string const & s)
1200 : {
1201 : // we assume UTF-8 because in our Snap environment most everything is
1202 : // TODO: change control characters to \xXX
1203 0 : f_message += QString::fromUtf8(s.c_str());
1204 0 : return *this;
1205 : }
1206 :
1207 :
1208 0 : logger & logger::operator () (std::wstring const & s)
1209 : {
1210 : // we assume UTF-8 because in our Snap environment most everything is
1211 : // TODO: change control characters to \xXX
1212 0 : f_message += QString::fromWCharArray(s.c_str());
1213 0 : return *this;
1214 : }
1215 :
1216 :
1217 3 : logger & logger::operator () (QString const & s)
1218 : {
1219 : // TODO: change control characters to \xXX
1220 3 : f_message += s;
1221 3 : return *this;
1222 : }
1223 :
1224 :
1225 0 : logger & logger::operator () (snap::snap_config::snap_config_parameter_ref const & s)
1226 : {
1227 0 : f_message += QString(s);
1228 0 : return *this;
1229 : }
1230 :
1231 :
1232 0 : logger & logger::operator () (char const v)
1233 : {
1234 0 : f_message += QString("%1").arg(static_cast<int>(v));
1235 0 : return *this;
1236 : }
1237 :
1238 :
1239 0 : logger & logger::operator () (signed char const v)
1240 : {
1241 0 : f_message += QString("%1").arg(static_cast<int>(v));
1242 0 : return *this;
1243 : }
1244 :
1245 :
1246 0 : logger & logger::operator () (unsigned char const v)
1247 : {
1248 0 : f_message += QString("%1").arg(static_cast<int>(v));
1249 0 : return *this;
1250 : }
1251 :
1252 :
1253 0 : logger & logger::operator () (signed short const v)
1254 : {
1255 0 : f_message += QString("%1").arg(static_cast<int>(v));
1256 0 : return *this;
1257 : }
1258 :
1259 :
1260 0 : logger & logger::operator () (unsigned short const v)
1261 : {
1262 0 : f_message += QString("%1").arg(static_cast<int>(v));
1263 0 : return *this;
1264 : }
1265 :
1266 :
1267 1 : logger & logger::operator () (signed int const v)
1268 : {
1269 1 : f_message += QString("%1").arg(v);
1270 1 : return *this;
1271 : }
1272 :
1273 :
1274 0 : logger & logger::operator () (unsigned int const v)
1275 : {
1276 0 : f_message += QString("%1").arg(v);
1277 0 : return *this;
1278 : }
1279 :
1280 :
1281 0 : logger & logger::operator () (signed long const v)
1282 : {
1283 0 : f_message += QString("%1").arg(v);
1284 0 : return *this;
1285 : }
1286 :
1287 :
1288 0 : logger & logger::operator () (unsigned long const v)
1289 : {
1290 0 : f_message += QString("%1").arg(v);
1291 0 : return *this;
1292 : }
1293 :
1294 :
1295 0 : logger & logger::operator () (signed long long const v)
1296 : {
1297 0 : f_message += QString("%1").arg(v);
1298 0 : return *this;
1299 : }
1300 :
1301 :
1302 0 : logger & logger::operator () (unsigned long long const v)
1303 : {
1304 0 : f_message += QString("%1").arg(v);
1305 0 : return *this;
1306 : }
1307 :
1308 :
1309 0 : logger & logger::operator () (float const v)
1310 : {
1311 0 : f_message += QString("%1").arg(v);
1312 0 : return *this;
1313 : }
1314 :
1315 :
1316 0 : logger & logger::operator () (double const v)
1317 : {
1318 0 : f_message += QString("%1").arg(v);
1319 0 : return *this;
1320 : }
1321 :
1322 :
1323 0 : logger & logger::operator () (bool const v)
1324 : {
1325 0 : f_message += QString("%1").arg(static_cast<int>(v));
1326 0 : return *this;
1327 : }
1328 :
1329 :
1330 0 : logger & logger::operator () (void const * p)
1331 : {
1332 0 : f_message += QString("0x%1").arg(reinterpret_cast<qulonglong>(p), 0, 16);
1333 0 : return *this;
1334 : }
1335 :
1336 :
1337 0 : logger & operator << ( logger & l, QString const & msg )
1338 : {
1339 0 : return l( msg );
1340 : }
1341 :
1342 :
1343 0 : logger & operator << ( logger & l, std::basic_string<char> const & msg )
1344 : {
1345 0 : return l( msg );
1346 : }
1347 :
1348 :
1349 0 : logger & operator << ( logger & l, snap::snap_config::snap_config_parameter_ref const & msg )
1350 : {
1351 0 : return l( msg );
1352 : }
1353 :
1354 :
1355 0 : logger & operator << ( logger & l, std::basic_string<wchar_t> const & msg )
1356 : {
1357 0 : return l( msg );
1358 : }
1359 :
1360 :
1361 0 : logger & operator << ( logger & l, char const * msg )
1362 : {
1363 0 : return l( msg );
1364 : }
1365 :
1366 :
1367 0 : logger & operator << ( logger & l, wchar_t const * msg )
1368 : {
1369 0 : return l( msg );
1370 : }
1371 :
1372 :
1373 :
1374 : /** \brief This function checks whether the log level allows output.
1375 : *
1376 : * This function checks the user specified log level against
1377 : * the current log level of the logger. If the log is to be
1378 : * output, then the function returns true (i.e. user log level
1379 : * is larger or equal to the logger's log level.)
1380 : *
1381 : * \todo
1382 : * Unfortunately we cannot be sure, at this point, whether the
1383 : * log will be secure or not. So we have to check with both
1384 : * loggers and return true if either would log the data. Since
1385 : * the secure logger is likely to have a higher log level and
1386 : * we log way less secure data, we should be just fine.
1387 : *
1388 : * \return true if the log should be computed.
1389 : */
1390 1 : bool is_enabled_for( log_level_t const log_level )
1391 : {
1392 : // if still unconfigured, we just pretend the level is ON because
1393 : // we do not really know for sure what the level is at this point
1394 : //
1395 1 : if( g_logging_type == logging_type_t::UNCONFIGURED_LOGGER )
1396 : {
1397 1 : return true;
1398 : }
1399 :
1400 0 : log4cplus::LogLevel ll(log4cplus::FATAL_LOG_LEVEL);
1401 :
1402 0 : switch(log_level)
1403 : {
1404 0 : case log_level_t::LOG_LEVEL_OFF:
1405 : // off means we do not emit anything so always return false
1406 0 : return false;
1407 :
1408 0 : case log_level_t::LOG_LEVEL_FATAL:
1409 0 : ll = log4cplus::FATAL_LOG_LEVEL;
1410 0 : break;
1411 :
1412 0 : case log_level_t::LOG_LEVEL_ERROR:
1413 0 : ll = log4cplus::ERROR_LOG_LEVEL;
1414 0 : break;
1415 :
1416 0 : case log_level_t::LOG_LEVEL_WARNING:
1417 0 : ll = log4cplus::WARN_LOG_LEVEL;
1418 0 : break;
1419 :
1420 0 : case log_level_t::LOG_LEVEL_INFO:
1421 0 : ll = log4cplus::INFO_LOG_LEVEL;
1422 0 : break;
1423 :
1424 0 : case log_level_t::LOG_LEVEL_DEBUG:
1425 0 : ll = log4cplus::DEBUG_LOG_LEVEL;
1426 0 : break;
1427 :
1428 0 : case log_level_t::LOG_LEVEL_TRACE:
1429 0 : ll = log4cplus::TRACE_LOG_LEVEL;
1430 0 : break;
1431 :
1432 : }
1433 :
1434 : // TODO: see whether we could have a better way to only
1435 : // return the one concerned (i.e. 2x the macros
1436 : // and specify secure right there?) -- although
1437 : // the likelihood is that g_logger is going to
1438 : // be used and the log level of that one is
1439 : // likely lower than g_secure_logger; but such
1440 : // a statement can always be all wrong...
1441 : //
1442 0 : return g_logger.isEnabledFor(ll)
1443 0 : || g_secure_logger.isEnabledFor(ll)
1444 0 : || (g_messenger_logger_initialized && g_messenger_logger.isEnabledFor(ll));
1445 : }
1446 :
1447 :
1448 :
1449 0 : logger fatal(char const * file, char const * func, int line)
1450 : {
1451 0 : if(is_enabled_for(log_level_t::LOG_LEVEL_FATAL))
1452 : {
1453 0 : logger l(log_level_t::LOG_LEVEL_FATAL, file, func, line);
1454 0 : return l.operator () ("fatal error: ");
1455 : }
1456 : else
1457 : {
1458 0 : logger_stub l(log_level_t::LOG_LEVEL_FATAL, file, func, line);
1459 0 : return l;
1460 : }
1461 : }
1462 :
1463 0 : logger error(char const * file, char const * func, int line)
1464 : {
1465 0 : if(is_enabled_for(log_level_t::LOG_LEVEL_ERROR))
1466 : {
1467 0 : logger l(log_level_t::LOG_LEVEL_ERROR, file, func, line);
1468 0 : return l.operator () ("error: ");
1469 : }
1470 : else
1471 : {
1472 0 : logger_stub l(log_level_t::LOG_LEVEL_ERROR, file, func, line);
1473 0 : return l;
1474 : }
1475 : }
1476 :
1477 0 : logger warning(char const * file, char const * func, int line)
1478 : {
1479 0 : if(is_enabled_for(log_level_t::LOG_LEVEL_WARNING))
1480 : {
1481 0 : logger l(log_level_t::LOG_LEVEL_WARNING, file, func, line);
1482 0 : return l.operator () ("warning: ");
1483 : }
1484 : else
1485 : {
1486 0 : logger_stub l(log_level_t::LOG_LEVEL_WARNING, file, func, line);
1487 0 : return l;
1488 : }
1489 : }
1490 :
1491 0 : logger info(char const * file, char const * func, int line)
1492 : {
1493 0 : if(is_enabled_for(log_level_t::LOG_LEVEL_INFO))
1494 : {
1495 0 : logger l(log_level_t::LOG_LEVEL_INFO, file, func, line);
1496 0 : return l.operator () ("info: ");
1497 : }
1498 : else
1499 : {
1500 0 : logger_stub l(log_level_t::LOG_LEVEL_INFO, file, func, line);
1501 0 : return l;
1502 : }
1503 : }
1504 :
1505 1 : logger debug(char const * file, char const * func, int line)
1506 : {
1507 1 : if(is_enabled_for(log_level_t::LOG_LEVEL_DEBUG))
1508 : {
1509 2 : logger l(log_level_t::LOG_LEVEL_DEBUG, file, func, line);
1510 1 : return l.operator () ("debug: ");
1511 : }
1512 : else
1513 : {
1514 0 : logger_stub l(log_level_t::LOG_LEVEL_DEBUG, file, func, line);
1515 0 : return l;
1516 : }
1517 : }
1518 :
1519 0 : logger trace(char const * file, char const * func, int line)
1520 : {
1521 0 : if(is_enabled_for(log_level_t::LOG_LEVEL_TRACE))
1522 : {
1523 0 : logger l(log_level_t::LOG_LEVEL_TRACE, file, func, line);
1524 0 : return l.operator () ("trace: ");
1525 : }
1526 : else
1527 : {
1528 0 : logger_stub l(log_level_t::LOG_LEVEL_TRACE, file, func, line);
1529 0 : return l;
1530 : }
1531 : }
1532 :
1533 :
1534 : } // namespace logging
1535 6 : } // namespace snap
1536 : // vim: ts=4 sw=4 et
|