LCOV - code coverage report
Current view: top level - snaplogger - private_logger.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 82 186 44.1 %
Date: 2019-08-13 00:35:33 Functions: 19 35 54.3 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.12