LCOV - code coverage report
Current view: top level - snapwebsites - log.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 57 505 11.3 %
Date: 2019-12-15 17:13:15 Functions: 10 66 15.2 %
Legend: Lines: hit not hit

          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

Generated by: LCOV version 1.13