LCOV - code coverage report
Current view: top level - snaplogger - private_logger.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 174 214 81.3 %
Date: 2019-12-13 00:59:36 Functions: 33 40 82.5 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2013-2019  Made to Order Software Corp.  All Rights Reserved
       3             :  *
       4             :  * https://snapwebsites.org/project/snaplogger
       5             :  * contact@m2osw.com
       6             :  *
       7             :  * This program is free software; you can redistribute it and/or modify
       8             :  * it under the terms of the GNU General Public License as published by
       9             :  * the Free Software Foundation; either version 2 of the License, or
      10             :  * (at your option) any later version.
      11             :  *
      12             :  * This program is distributed in the hope that it will be useful,
      13             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      14             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      15             :  * GNU General Public License for more details.
      16             :  *
      17             :  * You should have received a copy of the GNU General Public License along
      18             :  * with this program; if not, write to the Free Software Foundation, Inc.,
      19             :  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
      20             :  */
      21             : 
      22             : /** \file
      23             :  * \brief Appenders are used to append data to somewhere.
      24             :  *
      25             :  * This file declares the base appender class.
      26             :  */
      27             : 
      28             : // self
      29             : //
      30             : #include    "snaplogger/private_logger.h"
      31             : 
      32             : #include    "snaplogger/console_appender.h"
      33             : #include    "snaplogger/exception.h"
      34             : #include    "snaplogger/file_appender.h"
      35             : #include    "snaplogger/guard.h"
      36             : #include    "snaplogger/logger.h"
      37             : #include    "snaplogger/syslog_appender.h"
      38             : 
      39             : 
      40             : // cppthread lib
      41             : //
      42             : #include    <cppthread/log.h>
      43             : #include    <cppthread/runner.h>
      44             : 
      45             : 
      46             : // last include
      47             : //
      48             : #include    <snapdev/poison.h>
      49             : 
      50             : 
      51             : 
      52             : namespace snaplogger
      53             : {
      54             : 
      55             : 
      56             : namespace
      57             : {
      58             : 
      59             : 
      60             : 
      61           0 : void getopt_logs(cppthread::log_level_t l, std::string const & m)
      62             : {
      63           0 :     severity_t sev(severity_t::SEVERITY_ERROR);
      64           0 :     switch(l)
      65             :     {
      66           0 :     case cppthread::log_level_t::debug:
      67           0 :         sev = severity_t::SEVERITY_DEBUG;
      68           0 :         break;
      69             : 
      70           0 :     case cppthread::log_level_t::info:
      71           0 :         sev = severity_t::SEVERITY_INFORMATION;
      72           0 :         break;
      73             : 
      74           0 :     case cppthread::log_level_t::warning:
      75           0 :         sev = severity_t::SEVERITY_WARNING;
      76           0 :         break;
      77             : 
      78           0 :     case cppthread::log_level_t::fatal:
      79           0 :         sev = severity_t::SEVERITY_FATAL;
      80           0 :         break;
      81             : 
      82             :     //case cppthread::log_level_t::error:
      83           0 :     default:
      84             :         // anything else, keep SEVERITY_ERROR
      85           0 :         break;
      86             : 
      87             :     }
      88             : 
      89           0 :     message msg(sev, __FILE__, __func__, __LINE__);
      90           0 :     msg << m;
      91             : 
      92             :     // this call cannot create a loop, if the creation of the logger
      93             :     // generates an cppthread log, then the second call will generate
      94             :     // an exception (see get_instance() in snaplogger/logger.cpp)
      95             :     //
      96           0 :     logger::pointer_t lg(logger::get_instance());
      97             : 
      98           0 :     lg->log_message(msg);
      99           0 : }
     100             : 
     101             : 
     102             : 
     103             : }
     104             : // no name namespace
     105             : 
     106             : 
     107             : namespace detail
     108             : {
     109             : 
     110             : 
     111             : 
     112             : 
     113           1 : class asynchronous_logger
     114             :     : public cppthread::runner
     115             : {
     116             : public:
     117           1 :     asynchronous_logger(message_fifo_t::pointer_t fifo)
     118           1 :         : runner("logger asynchronous thread")
     119           2 :         , f_logger(logger::get_instance())
     120           3 :         , f_fifo(fifo)
     121             :     {
     122           1 :     }
     123             : 
     124           2 :     virtual void run()
     125             :     {
     126             :         // loop until the FIFO is marked as being done
     127             :         //
     128             :         for(;;)
     129             :         {
     130           3 :             message::pointer_t msg;
     131           2 :             if(!f_fifo->pop_front(msg, -1))
     132             :             {
     133           1 :                 break;
     134             :             }
     135           2 :             logger::pointer_t l(f_logger.lock());
     136           1 :             if(l != nullptr)
     137             :             {
     138           1 :                 l->process_message(*msg);
     139             :             }
     140           1 :         }
     141           1 :     }
     142             : 
     143             : private:
     144             :     logger::weak_pointer_t      f_logger = logger::pointer_t();
     145             :     message_fifo_t::pointer_t   f_fifo = message_fifo_t::pointer_t();
     146             : };
     147             : 
     148             : 
     149             : 
     150             : }
     151             : // detail namespace
     152             : 
     153             : 
     154             : 
     155           2 : private_logger::private_logger()
     156             : {
     157           2 :     f_normal_component = get_component(COMPONENT_NORMAL);
     158             : 
     159           2 :     cppthread::set_log_callback(getopt_logs);
     160           2 : }
     161             : 
     162             : 
     163           6 : private_logger::~private_logger()
     164             : {
     165           2 :     delete_thread();
     166           4 : }
     167             : 
     168             : 
     169           2 : void private_logger::shutdown()
     170             : {
     171           2 :     delete_thread();
     172           2 : }
     173             : 
     174             : 
     175           8 : void private_logger::register_appender_factory(appender_factory::pointer_t factory)
     176             : {
     177           8 :     if(factory == nullptr)
     178             :     {
     179             :         throw logger_logic_error(                                       // LCOV_EXCL_LINE
     180             :                 "register_appender_factory() called with a nullptr.");  // LCOV_EXCL_LINE
     181             :     }
     182             : 
     183          16 :     guard g;
     184             : 
     185           8 :     if(f_appender_factories.find(factory->get_type()) != f_appender_factories.end())
     186             :     {
     187             :         throw duplicate_error(                                  // LCOV_EXCL_LINE
     188             :                   "trying to register appender type \""         // LCOV_EXCL_LINE
     189             :                 + factory->get_type()                           // LCOV_EXCL_LINE
     190             :                 + "\" twice won't work.");                      // LCOV_EXCL_LINE
     191             :     }
     192             : 
     193           8 :     f_appender_factories[factory->get_type()] = factory;
     194           8 : }
     195             : 
     196             : 
     197           2 : appender::pointer_t private_logger::create_appender(std::string const & type, std::string const & name)
     198             : {
     199           4 :     guard g;
     200             : 
     201           2 :     auto it(f_appender_factories.find(type));
     202           2 :     if(it != f_appender_factories.end())
     203             :     {
     204           1 :         return it->second->create(name);
     205             :     }
     206             : 
     207           1 :     return appender::pointer_t();
     208             : }
     209             : 
     210             : 
     211          26 : component::pointer_t private_logger::get_component(std::string const & name)
     212             : {
     213          52 :     guard g;
     214             : 
     215          26 :     auto it(f_components.find(name));
     216          26 :     if(it != f_components.end())
     217             :     {
     218          20 :         return it->second;
     219             :     }
     220             : 
     221          12 :     auto comp(std::make_shared<component>(name));
     222           6 :     f_components[name] = comp;
     223             : 
     224           6 :     return comp;
     225             : }
     226             : 
     227             : 
     228          18 : format::pointer_t private_logger::get_default_format()
     229             : {
     230          36 :     guard g;
     231             : 
     232          18 :     if(f_default_format == nullptr)
     233             :     {
     234           2 :         f_default_format = std::make_shared<format>(
     235             :             //"${env:name=HOME:padding='-':align=center:exact_width=6} "
     236             :             "${date} ${time} ${hostname}"
     237             :             " ${progname}[${pid}]: ${severity}:"
     238             :             " ${message:escape:max_width=1000}"
     239             :             " (in function \"${function}()\")"
     240             :             " (${basename}:${line})"
     241           1 :         );
     242             :     }
     243             : 
     244          36 :     return f_default_format;
     245             : }
     246             : 
     247             : 
     248       94615 : environment::pointer_t private_logger::create_environment()
     249             : {
     250       94615 :     pid_t const tid(cppthread::gettid());
     251             : 
     252      189230 :     guard g;
     253             : 
     254       94615 :     auto it(f_environment.find(tid));
     255       94615 :     if(it == f_environment.end())
     256             :     {
     257           2 :         auto result(std::make_shared<environment>(tid));
     258           1 :         f_environment[tid] = result;
     259           1 :         return result;
     260             :     }
     261             : 
     262       94614 :     return it->second;
     263             : }
     264             : 
     265             : 
     266             : /** \brief Add a severity.
     267             :  *
     268             :  * This function adds a severity to the private logger object.
     269             :  *
     270             :  * Remember that a severity can be given aliases so this function may
     271             :  * add quite a few entries, not just one.
     272             :  *
     273             :  * \warning
     274             :  * You should not be calling this function directly. Please see the
     275             :  * direct snaplogger::add_severity() function instead.
     276             :  *
     277             :  * \exception duplicate_error
     278             :  * The function verifies that the new severity is not a duplicate of
     279             :  * an existing system severity.
     280             :  *
     281             :  * \param[in] sev  The severity object to be added.
     282             :  */
     283          25 : void private_logger::add_severity(severity::pointer_t sev)
     284             : {
     285          50 :     guard g;
     286             : 
     287          25 :     auto it(f_severity_by_severity.find(sev->get_severity()));
     288          25 :     if(it != f_severity_by_severity.end())
     289             :     {
     290           3 :         if(it->second->is_system())
     291             :         {
     292           2 :             throw duplicate_error("a system severity cannot be replaced.");
     293             :         }
     294             :     }
     295             : 
     296          59 :     for(auto n : sev->get_all_names())
     297             :     {
     298          36 :         auto s(f_severity_by_name.find(n));
     299          36 :         if(s != f_severity_by_name.end())
     300             :         {
     301           3 :             if(s->second->is_system())
     302             :             {
     303           2 :                 throw duplicate_error("a system severity cannot be replaced.");
     304             :             }
     305             :         }
     306             :     }
     307             : 
     308          21 :     f_severity_by_severity[sev->get_severity()] = sev;
     309             : 
     310          55 :     for(auto n : sev->get_all_names())
     311             :     {
     312          34 :         f_severity_by_name[n] = sev;
     313             :     }
     314          21 : }
     315             : 
     316             : 
     317          24 : severity::pointer_t private_logger::get_severity(std::string const & name) const
     318             : {
     319          48 :     guard g;
     320             : 
     321          24 :     auto it(f_severity_by_name.find(name));
     322          24 :     if(it == f_severity_by_name.end())
     323             :     {
     324          17 :         return severity::pointer_t();
     325             :     }
     326             : 
     327           7 :     return it->second;
     328             : }
     329             : 
     330             : 
     331          16 : severity::pointer_t private_logger::get_severity(severity_t sev) const
     332             : {
     333          32 :     guard g;
     334             : 
     335          16 :     auto it(f_severity_by_severity.find(sev));
     336          16 :     if(it == f_severity_by_severity.end())
     337             :     {
     338           2 :         return severity::pointer_t();
     339             :     }
     340             : 
     341          14 :     return it->second;
     342             : }
     343             : 
     344             : 
     345          26 : void private_logger::set_diagnostic(std::string const & key, std::string const & diagnostic)
     346             : {
     347          52 :     guard g;
     348             : 
     349          26 :     f_map_diagnostics[key] = diagnostic;
     350          26 : }
     351             : 
     352             : 
     353           1 : void private_logger::unset_diagnostic(std::string const & key)
     354             : {
     355           2 :     guard g;
     356             : 
     357           1 :     auto it(f_map_diagnostics.find(key));
     358           1 :     if(it != f_map_diagnostics.end())
     359             :     {
     360           1 :         f_map_diagnostics.erase(it);
     361             :     }
     362           1 : }
     363             : 
     364             : 
     365          45 : map_diagnostics_t private_logger::get_map_diagnostics()
     366             : {
     367          90 :     guard g;
     368             : 
     369          90 :     return f_map_diagnostics;
     370             : }
     371             : 
     372             : 
     373           0 : void private_logger::set_maximum_trace_diagnostics(size_t max)
     374             : {
     375           0 :     f_maximum_trace_diagnostics = max;
     376           0 : }
     377             : 
     378             : 
     379           0 : size_t private_logger::get_maximum_trace_diagnostics() const
     380             : {
     381           0 :     return f_maximum_trace_diagnostics;
     382             : }
     383             : 
     384             : 
     385           0 : void private_logger::add_trace_diagnostic(std::string const & diagnostic)
     386             : {
     387           0 :     guard g;
     388             : 
     389           0 :     f_trace_diagnostics.push_back(diagnostic);
     390           0 :     if(f_trace_diagnostics.size() > f_maximum_trace_diagnostics)
     391             :     {
     392           0 :         f_trace_diagnostics.pop_front();
     393             :     }
     394           0 : }
     395             : 
     396             : 
     397           0 : void private_logger::clear_trace_diagnostics()
     398             : {
     399           0 :     guard g;
     400             : 
     401           0 :     f_trace_diagnostics.clear();
     402           0 : }
     403             : 
     404             : 
     405           0 : trace_diagnostics_t private_logger::get_trace_diagnostics()
     406             : {
     407           0 :     guard g;
     408             : 
     409           0 :     return f_trace_diagnostics;
     410             : }
     411             : 
     412             : 
     413           3 : void private_logger::push_nested_diagnostic(std::string const & diagnostic)
     414             : {
     415           6 :     guard g;
     416             : 
     417           3 :     f_nested_diagnostics.push_back(diagnostic);
     418           3 : }
     419             : 
     420             : 
     421           3 : void private_logger::pop_nested_diagnostic()
     422             : {
     423           6 :     guard g;
     424             : 
     425           3 :     f_nested_diagnostics.pop_back();
     426           3 : }
     427             : 
     428             : 
     429           8 : string_vector_t private_logger::get_nested_diagnostics() const
     430             : {
     431          16 :     guard g;
     432             : 
     433          16 :     return f_nested_diagnostics;
     434             : }
     435             : 
     436             : 
     437          57 : void private_logger::register_variable_factory(variable_factory::pointer_t factory)
     438             : {
     439         114 :     guard g;
     440             : 
     441          57 :     auto it(f_variable_factories.find(factory->get_type()));
     442          57 :     if(it != f_variable_factories.end())
     443             :     {
     444             :         throw duplicate_error(
     445             :                   "trying to add two variable factories of type \""
     446           2 :                 + factory->get_type()
     447           3 :                 + "\".");
     448             :     }
     449             : 
     450          56 :     f_variable_factories[factory->get_type()] = factory;
     451          56 : }
     452             : 
     453             : 
     454         212 : variable::pointer_t private_logger::get_variable(std::string const & type)
     455             : {
     456         424 :     guard g;
     457             : 
     458         212 :     if(f_variable_factories.empty())
     459             :     {
     460             :         throw invalid_variable("No variable factories were registered yet; you can't create a variable with type \""    // LCOV_EXCL_LINE
     461             :                              + type                                     // LCOV_EXCL_LINE
     462             :                              + "\" at this point.");                    // LCOV_EXCL_LINE
     463             :     }
     464             : 
     465         212 :     auto it(f_variable_factories.find(type));
     466         212 :     if(it == f_variable_factories.end())
     467             :     {
     468             :         // TBD: should we instead return a null var.?
     469             :         throw invalid_variable("You can't create variable with type \""
     470           2 :                              + type
     471           3 :                              + "\", no such variable type was registered.");
     472             :     }
     473             : 
     474         422 :     return it->second->create_variable();
     475             : }
     476             : 
     477             : 
     478       48247 : bool private_logger::has_functions() const
     479             : {
     480       96494 :     guard g;
     481             : 
     482       96494 :     return !f_functions.empty();
     483             : }
     484             : 
     485             : 
     486          23 : void private_logger::register_function(function::pointer_t func)
     487             : {
     488          46 :     guard g;
     489             : 
     490          23 :     auto it(f_functions.find(func->get_name()));
     491          23 :     if(it != f_functions.end())
     492             :     {
     493             :         throw duplicate_error(
     494             :                   "trying to add two functions named \""
     495           2 :                 + func->get_name()
     496           3 :                 + "\".");
     497             :     }
     498          22 :     f_functions[func->get_name()] = func;
     499          22 : }
     500             : 
     501             : 
     502          95 : function::pointer_t private_logger::get_function(std::string const & name) const
     503             : {
     504         190 :     guard g;
     505             : 
     506          95 :     auto it(f_functions.find(name));
     507          95 :     if(it != f_functions.end())
     508             :     {
     509          73 :         return it->second;
     510             :     }
     511             : 
     512          22 :     return function::pointer_t();
     513             : }
     514             : 
     515             : 
     516           1 : void private_logger::create_thread()
     517             : {
     518           2 :     guard g;
     519             : 
     520             :     try
     521             :     {
     522           1 :         f_fifo = std::make_shared<message_fifo_t>();
     523           1 :         f_asynchronous_logger = std::make_shared<detail::asynchronous_logger>(f_fifo);
     524           1 :         f_thread = std::make_shared<cppthread::thread>("asynchronous logger thread", f_asynchronous_logger.get());
     525           1 :         f_thread->start();
     526             :     }
     527             :     catch(...)                              // LCOV_EXCL_LINE
     528             :     {
     529             :         if(f_fifo != nullptr)               // LCOV_EXCL_LINE
     530             :         {
     531             :             f_fifo->done(false);            // LCOV_EXCL_LINE
     532             :         }
     533             : 
     534             :         f_thread.reset();                   // LCOV_EXCL_LINE
     535             :         f_asynchronous_logger.reset();      // LCOV_EXCL_LINE
     536             :         f_fifo.reset();                     // LCOV_EXCL_LINE
     537             :         throw;                              // LCOV_EXCL_LINE
     538             :     }
     539           1 : }
     540             : 
     541             : 
     542           5 : void private_logger::delete_thread()
     543             : {
     544             :     // WARNING: we can't call fifo::done() while our guard is locked
     545             :     //          we also have to make sure it's not a null pointer
     546             :     //
     547          10 :     message_fifo_t::pointer_t       fifo                = message_fifo_t::pointer_t();
     548          10 :     asynchronous_logger_pointer_t   asynchronous_logger = asynchronous_logger_pointer_t();
     549          10 :     cppthread::thread::pointer_t    thread              = cppthread::thread::pointer_t();
     550             : 
     551             :     {
     552          10 :         guard g;
     553             : 
     554           5 :         swap(thread,              f_thread);
     555           5 :         swap(asynchronous_logger, f_asynchronous_logger);
     556           5 :         swap(fifo,                f_fifo);
     557             :     }
     558             : 
     559           5 :     if(fifo != nullptr)
     560             :     {
     561           1 :         fifo->done(false);
     562             :     }
     563             : 
     564             :     try
     565             :     {
     566           5 :         thread.reset();
     567             :     }
     568             :     catch(std::exception const & e)
     569             :     {
     570             :         // in most cases this one happens when quitting when one of your
     571             :         // functions attempts to get an instance of the logger, which is
     572             :         // forbidden once you return from your main() function
     573             :         //
     574             :         std::cerr << "got exception \""
     575             :                   << e.what()
     576             :                   << "\" while deleting the asynchronous thread."
     577             :                   << std::endl;
     578             :     }
     579           5 : }
     580             : 
     581             : 
     582           1 : void private_logger::send_message_to_thread(message::pointer_t msg)
     583             : {
     584             :     {
     585           2 :         guard g;
     586             : 
     587           1 :         if(f_fifo == nullptr)
     588             :         {
     589           1 :             create_thread();
     590             :         }
     591             :     }
     592             : 
     593           1 :     f_fifo->push_back(msg);
     594           1 : }
     595             : 
     596             : 
     597             : 
     598             : 
     599       95026 : private_logger::pointer_t get_private_logger()
     600             : {
     601       95026 :     return std::dynamic_pointer_cast<private_logger>(logger::get_instance());
     602             : }
     603             : 
     604             : 
     605       48313 : private_logger::pointer_t get_private_logger(message const & msg)
     606             : {
     607       48313 :     return std::dynamic_pointer_cast<private_logger>(msg.get_logger());
     608             : }
     609             : 
     610             : 
     611             : 
     612           6 : } // snaplogger namespace
     613             : // vim: ts=4 sw=4 et

Generated by: LCOV version 1.13