LCOV - code coverage report
Current view: top level - snaplogger - private_logger.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 88 186 47.3 %
Date: 2019-08-18 12:59:55 Functions: 20 35 57.1 %
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/runner.h>
      43             : 
      44             : 
      45             : // last include
      46             : //
      47             : #include    <snapdev/poison.h>
      48             : 
      49             : 
      50             : 
      51             : namespace snaplogger
      52             : {
      53             : 
      54             : 
      55             : 
      56             : namespace detail
      57             : {
      58             : 
      59             : 
      60             : 
      61             : 
      62           0 : class asynchronous_logger
      63             :     : public cppthread::runner
      64             : {
      65             : public:
      66           0 :     asynchronous_logger(message_fifo_t::pointer_t fifo)
      67             :         : runner("logger asynchronous thread")
      68           0 :         , f_logger(logger::get_instance())
      69           0 :         , f_fifo(fifo)
      70             :     {
      71           0 :     }
      72             : 
      73           0 :     virtual void run()
      74             :     {
      75             :         // loop until the FIFO is marked as being done
      76             :         //
      77           0 :         for(;;)
      78             :         {
      79           0 :             message::pointer_t msg;
      80           0 :             if(!f_fifo->pop_front(msg, -1))
      81             :             {
      82           0 :                 break;
      83             :             }
      84           0 :             logger::pointer_t l(f_logger.lock());
      85           0 :             if(l != nullptr)
      86             :             {
      87           0 :                 l->process_message(*msg);
      88             :             }
      89             :         }
      90           0 :     }
      91             : 
      92             : private:
      93             :     logger::weak_pointer_t      f_logger = logger::pointer_t();
      94             :     message_fifo_t::pointer_t   f_fifo = message_fifo_t::pointer_t();
      95             : };
      96             : 
      97             : 
      98             : 
      99             : }
     100             : // detail namespace
     101             : 
     102             : 
     103             : 
     104           2 : private_logger::private_logger()
     105             : {
     106           2 :     f_normal_component = get_component(COMPONENT_NORMAL);
     107           2 : }
     108             : 
     109             : 
     110           6 : private_logger::~private_logger()
     111             : {
     112           2 :     delete_thread();
     113           4 : }
     114             : 
     115             : 
     116           2 : void private_logger::shutdown()
     117             : {
     118           2 :     delete_thread();
     119           2 : }
     120             : 
     121             : 
     122           8 : void private_logger::register_appender_factory(appender_factory::pointer_t factory)
     123             : {
     124           8 :     if(factory == nullptr)
     125             :     {
     126             :         throw logger_logic_error(
     127           0 :                 "register_appender_factory() called with a nullptr.");
     128             :     }
     129             : 
     130          16 :     guard g;
     131             : 
     132           8 :     if(f_appender_factories.find(factory->get_type()) != f_appender_factories.end())
     133             :     {
     134             :         throw duplicate_error(
     135             :                   "trying to register appender type \""
     136           0 :                 + factory->get_type()
     137           0 :                 + "\" twice won't work.");
     138             :     }
     139             : 
     140           8 :     f_appender_factories[factory->get_type()] = factory;
     141           8 : }
     142             : 
     143             : 
     144           0 : appender::pointer_t private_logger::create_appender(std::string const & type, std::string const & name)
     145             : {
     146           0 :     guard g;
     147             : 
     148           0 :     auto it(f_appender_factories.find(type));
     149           0 :     if(it != f_appender_factories.end())
     150             :     {
     151           0 :         return it->second->create(name);
     152             :     }
     153             : 
     154           0 :     return appender::pointer_t();
     155             : }
     156             : 
     157             : 
     158          20 : component::pointer_t private_logger::get_component(std::string const & name)
     159             : {
     160          40 :     guard g;
     161             : 
     162          20 :     auto it(f_components.find(name));
     163          20 :     if(it != f_components.end())
     164             :     {
     165          14 :         return it->second;
     166             :     }
     167             : 
     168          12 :     auto comp(std::make_shared<component>(name));
     169           6 :     f_components[name] = comp;
     170             : 
     171           6 :     return comp;
     172             : }
     173             : 
     174             : 
     175          12 : format::pointer_t private_logger::get_default_format()
     176             : {
     177          24 :     guard g;
     178             : 
     179          12 :     if(f_default_format == nullptr)
     180             :     {
     181           2 :         f_default_format = std::make_shared<format>(
     182             :             //"${env:name=HOME:padding='-':align=center:exact_width=6} "
     183             :             "${date} ${time} ${hostname}"
     184             :             " ${progname}[${pid}]: ${severity}:"
     185             :             " ${message:escape:max_width=1000}"
     186             :             " (in function \"${function}()\")"
     187             :             " (${basename}:${line})"
     188           1 :         );
     189             :     }
     190             : 
     191          24 :     return f_default_format;
     192             : }
     193             : 
     194             : 
     195       92588 : environment::pointer_t private_logger::create_environment()
     196             : {
     197       92588 :     pid_t const tid(cppthread::gettid());
     198             : 
     199      185176 :     guard g;
     200             : 
     201       92588 :     auto it(f_environment.find(tid));
     202       92588 :     if(it == f_environment.end())
     203             :     {
     204           2 :         auto result(std::make_shared<environment>(tid));
     205           1 :         f_environment[tid] = result;
     206           1 :         return result;
     207             :     }
     208             : 
     209       92587 :     return it->second;
     210             : }
     211             : 
     212             : 
     213           0 : bool private_logger::has_severities() const
     214             : {
     215           0 :     return !f_severity_by_severity.empty();
     216             : }
     217             : 
     218             : 
     219             : /** \brief Add a severity.
     220             :  *
     221             :  * This function adds a severity to the private logger object.
     222             :  *
     223             :  * Remember that a severity can be given aliases so this function may
     224             :  * add quite a few entries, not just one.
     225             :  *
     226             :  * \warning
     227             :  * You should not be calling this function directly. Please see the
     228             :  * direct snaplogger::add_severity() function instead.
     229             :  *
     230             :  * \exception duplicate_error
     231             :  * The function verifies that the new severity is not a duplicate of
     232             :  * an existing system severity.
     233             :  *
     234             :  * \param[in] sev  The severity object to be added.
     235             :  */
     236           0 : void private_logger::add_severity(severity::pointer_t sev)
     237             : {
     238           0 :     guard g;
     239             : 
     240           0 :     auto it(f_severity_by_severity.find(sev->get_severity()));
     241           0 :     if(it != f_severity_by_severity.end())
     242             :     {
     243           0 :         if(it->second->is_system())
     244             :         {
     245           0 :             throw duplicate_error("a system severity cannot be replaced.");
     246             :         }
     247             :     }
     248             : 
     249           0 :     for(auto n : sev->get_all_names())
     250             :     {
     251           0 :         auto s(f_severity_by_name.find(n));
     252           0 :         if(s != f_severity_by_name.end())
     253             :         {
     254           0 :             if(s->second->is_system())
     255             :             {
     256           0 :                 throw duplicate_error("a system severity cannot be replaced.");
     257             :             }
     258             :         }
     259             :     }
     260             : 
     261           0 :     f_severity_by_severity[sev->get_severity()] = sev;
     262             : 
     263           0 :     for(auto n : sev->get_all_names())
     264             :     {
     265           0 :         f_severity_by_name[n] = sev;
     266             :     }
     267           0 : }
     268             : 
     269             : 
     270           0 : severity::pointer_t private_logger::get_severity(std::string const & name) const
     271             : {
     272           0 :     guard g;
     273             : 
     274           0 :     auto it(f_severity_by_name.find(name));
     275           0 :     if(it == f_severity_by_name.end())
     276             :     {
     277           0 :         return severity::pointer_t();
     278             :     }
     279             : 
     280           0 :     return it->second;
     281             : }
     282             : 
     283             : 
     284           0 : severity::pointer_t private_logger::get_severity(severity_t sev) const
     285             : {
     286           0 :     guard g;
     287             : 
     288           0 :     auto it(f_severity_by_severity.find(sev));
     289           0 :     if(it == f_severity_by_severity.end())
     290             :     {
     291           0 :         return severity::pointer_t();
     292             :     }
     293             : 
     294           0 :     return it->second;
     295             : }
     296             : 
     297             : 
     298          16 : void private_logger::set_diagnostic(std::string const & key, std::string const & diagnostic)
     299             : {
     300          32 :     guard g;
     301             : 
     302          16 :     f_map_diagnostics[key] = diagnostic;
     303          16 : }
     304             : 
     305             : 
     306           0 : void private_logger::unset_diagnostic(std::string const & key)
     307             : {
     308           0 :     guard g;
     309             : 
     310           0 :     auto it(f_map_diagnostics.find(key));
     311           0 :     if(it != f_map_diagnostics.end())
     312             :     {
     313           0 :         f_map_diagnostics.erase(it);
     314             :     }
     315           0 : }
     316             : 
     317             : 
     318           9 : map_diagnostics_t private_logger::get_map_diagnostics()
     319             : {
     320          18 :     guard g;
     321             : 
     322          18 :     return f_map_diagnostics;
     323             : }
     324             : 
     325             : 
     326           0 : void private_logger::push_nested_diagnostic(std::string const & diagnostic)
     327             : {
     328           0 :     guard g;
     329             : 
     330           0 :     f_nested_diagnostics.push_back(diagnostic);
     331           0 : }
     332             : 
     333             : 
     334           0 : void private_logger::pop_nested_diagnostic()
     335             : {
     336           0 :     guard g;
     337             : 
     338           0 :     f_nested_diagnostics.pop_back();
     339           0 : }
     340             : 
     341             : 
     342           0 : string_vector_t private_logger::get_nested_diagnostics() const
     343             : {
     344           0 :     guard g;
     345             : 
     346           0 :     return f_nested_diagnostics;
     347             : }
     348             : 
     349             : 
     350          56 : void private_logger::register_variable_factory(variable_factory::pointer_t factory)
     351             : {
     352         112 :     guard g;
     353             : 
     354          56 :     auto it(f_variable_factories.find(factory->get_type()));
     355          56 :     if(it != f_variable_factories.end())
     356             :     {
     357             :         throw duplicate_error(
     358             :                   "trying to add two variable factories of type \""
     359           0 :                 + factory->get_type()
     360           0 :                 + "\".");
     361             :     }
     362             : 
     363          56 :     f_variable_factories[factory->get_type()] = factory;
     364          56 : }
     365             : 
     366             : 
     367          77 : variable::pointer_t private_logger::get_variable(std::string const & type)
     368             : {
     369         154 :     guard g;
     370             : 
     371          77 :     if(f_variable_factories.empty())
     372             :     {
     373             :         throw invalid_variable("No variable factories were registered yet; you can't create a variable with type \""
     374           0 :                              + type
     375           0 :                              + "\" at this point.");
     376             :     }
     377             : 
     378          77 :     auto it(f_variable_factories.find(type));
     379          77 :     if(it == f_variable_factories.end())
     380             :     {
     381             :         // TBD: should we instead return a null var.?
     382             :         throw invalid_variable("You can't create variable with type \""
     383           0 :                              + type
     384           0 :                              + "\", no such variable type was registered.");
     385             :     }
     386             : 
     387         154 :     return it->second->create_variable();
     388             : }
     389             : 
     390             : 
     391       45563 : bool private_logger::has_functions() const
     392             : {
     393       91126 :     guard g;
     394             : 
     395       91126 :     return !f_functions.empty();
     396             : }
     397             : 
     398             : 
     399          22 : void private_logger::register_function(function::pointer_t func)
     400             : {
     401          44 :     guard g;
     402             : 
     403          22 :     auto it(f_functions.find(func->get_name()));
     404          22 :     if(it != f_functions.end())
     405             :     {
     406             :         throw duplicate_error(
     407             :                   "trying to add two functions named \""
     408           0 :                 + func->get_name()
     409           0 :                 + "\".");
     410             :     }
     411          22 :     f_functions[func->get_name()] = func;
     412          22 : }
     413             : 
     414             : 
     415          18 : function::pointer_t private_logger::get_function(std::string const & name) const
     416             : {
     417          36 :     guard g;
     418             : 
     419          18 :     auto it(f_functions.find(name));
     420          18 :     if(it != f_functions.end())
     421             :     {
     422          14 :         return it->second;
     423             :     }
     424             : 
     425           4 :     return function::pointer_t();
     426             : }
     427             : 
     428             : 
     429           0 : void private_logger::create_thread()
     430             : {
     431           0 :     guard g;
     432             : 
     433             :     try
     434             :     {
     435           0 :         f_fifo = std::make_shared<message_fifo_t>();
     436           0 :         f_asynchronous_logger = std::make_shared<detail::asynchronous_logger>(f_fifo);
     437           0 :         f_thread = std::make_shared<cppthread::thread>("asynchronous logger thread", f_asynchronous_logger.get());
     438           0 :         f_thread->start();
     439             :     }
     440           0 :     catch(...)
     441             :     {
     442           0 :         if(f_fifo != nullptr)
     443             :         {
     444           0 :             f_fifo->done(false);
     445             :         }
     446             : 
     447           0 :         f_thread.reset();
     448           0 :         f_asynchronous_logger.reset();
     449           0 :         f_fifo.reset();
     450           0 :         throw;
     451             :     }
     452           0 : }
     453             : 
     454             : 
     455           4 : void private_logger::delete_thread()
     456             : {
     457             :     // WARNING: we can't call fifo::done() while our guard is locked
     458             :     //          we also have to make sure it's not a null pointer
     459             :     //
     460           8 :     message_fifo_t::pointer_t       fifo                = message_fifo_t::pointer_t();
     461           8 :     asynchronous_logger_pointer_t   asynchronous_logger = asynchronous_logger_pointer_t();
     462           8 :     cppthread::thread::pointer_t    thread              = cppthread::thread::pointer_t();
     463             : 
     464             :     {
     465           8 :         guard g;
     466             : 
     467           4 :         swap(thread,              f_thread);
     468           4 :         swap(asynchronous_logger, f_asynchronous_logger);
     469           4 :         swap(fifo,                f_fifo);
     470             :     }
     471             : 
     472           4 :     if(fifo != nullptr)
     473             :     {
     474           0 :         fifo->done(false);
     475             :     }
     476             : 
     477             :     try
     478             :     {
     479           4 :         thread.reset();
     480             :     }
     481             :     catch(std::exception const & e)
     482             :     {
     483             :         // in most cases this one happens when quitting when one of your
     484             :         // functions attempts to get an instance of the logger, which is
     485             :         // forbidden once you return from your main() function
     486             :         //
     487             :         std::cerr << "got exception \""
     488             :                   << e.what()
     489             :                   << "\" while deleting the asynchronous thread."
     490             :                   << std::endl;
     491             :     }
     492           4 : }
     493             : 
     494             : 
     495           0 : void private_logger::send_message_to_thread(message::pointer_t msg)
     496             : {
     497             :     {
     498           0 :         guard g;
     499             : 
     500           0 :         if(f_fifo == nullptr)
     501             :         {
     502           0 :             create_thread();
     503             :         }
     504             :     }
     505             : 
     506           0 :     f_fifo->push_back(msg);
     507           0 : }
     508             : 
     509             : 
     510             : 
     511             : 
     512       92798 : private_logger::pointer_t get_private_logger()
     513             : {
     514       92798 :     return std::dynamic_pointer_cast<private_logger>(logger::get_instance());
     515             : }
     516             : 
     517             : 
     518       45571 : private_logger::pointer_t get_private_logger(message const & msg)
     519             : {
     520       45571 :     return std::dynamic_pointer_cast<private_logger>(msg.get_logger());
     521             : }
     522             : 
     523             : 
     524             : 
     525           6 : } // snaplogger namespace
     526             : // vim: ts=4 sw=4 et

Generated by: LCOV version 1.12