LCOV - code coverage report
Current view: top level - snaplogger - appender.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 87 190 45.8 %
Date: 2019-12-13 00:59:36 Functions: 19 28 67.9 %
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 implements the base appender class.
      26             :  */
      27             : 
      28             : 
      29             : // self
      30             : //
      31             : #include    "snaplogger/appender.h"
      32             : 
      33             : #include    "snaplogger/exception.h"
      34             : #include    "snaplogger/guard.h"
      35             : #include    "snaplogger/private_logger.h"
      36             : 
      37             : 
      38             : // snapdev lib
      39             : //
      40             : #include    <snapdev/empty_set_intersection.h>
      41             : #include    <snapdev/not_used.h>
      42             : 
      43             : 
      44             : // C++ lib
      45             : //
      46             : #include    <iostream>
      47             : 
      48             : 
      49             : // last include
      50             : //
      51             : #include    <snapdev/poison.h>
      52             : 
      53             : 
      54             : 
      55             : namespace snaplogger
      56             : {
      57             : 
      58             : 
      59             : namespace
      60             : {
      61             : 
      62             : 
      63             : 
      64             : // if we want to be able to reference such we need to create it TBD
      65             : // (and it should probably be in the null_appender.cpp file instead)
      66             : //APPENDER_FACTORY(null);
      67             : 
      68             : 
      69             : }
      70             : 
      71             : 
      72          18 : appender::appender(std::string const & name, std::string const & type)
      73             :     : f_type(type)
      74             :     , f_name(name)
      75          18 :     , f_normal_component(get_component(COMPONENT_NORMAL))
      76             : {
      77          36 :     guard g;
      78             : 
      79          18 :     f_format = get_private_logger()->get_default_format();
      80          18 : }
      81             : 
      82             : 
      83          18 : appender::~appender()
      84             : {
      85          18 : }
      86             : 
      87             : 
      88           3 : std::string const & appender::get_type() const
      89             : {
      90           3 :     return f_type;
      91             : }
      92             : 
      93             : 
      94           1 : std::string const & appender::get_name() const
      95             : {
      96           1 :     return f_name;
      97             : }
      98             : 
      99             : 
     100       94627 : bool appender::is_enabled() const
     101             : {
     102       94627 :     return f_enabled;
     103             : }
     104             : 
     105             : 
     106           0 : void appender::set_enabled(bool status)
     107             : {
     108           0 :     guard g;
     109             : 
     110           0 :     f_enabled = status;
     111           0 : }
     112             : 
     113             : 
     114          18 : bool appender::unique() const
     115             : {
     116          18 :     return false;
     117             : }
     118             : 
     119             : 
     120         304 : severity_t appender::get_severity() const
     121             : {
     122         608 :     guard g;
     123             : 
     124         608 :     return f_severity;
     125             : }
     126             : 
     127             : 
     128         288 : void appender::set_severity(severity_t severity_level)
     129             : {
     130         576 :     guard g;
     131             : 
     132         288 :     f_severity = severity_level;
     133         288 :     logger::get_instance()->severity_changed(severity_level);
     134         288 : }
     135             : 
     136             : 
     137           0 : void appender::reduce_severity(severity_t severity_level)
     138             : {
     139           0 :     guard g;
     140             : 
     141           0 :     if(severity_level < f_severity)
     142             :     {
     143           0 :         set_severity(severity_level);
     144             :     }
     145           0 : }
     146             : 
     147             : 
     148           0 : bool appender::operator < (appender const & rhs) const
     149             : {
     150           0 :     return f_severity < rhs.f_severity;
     151             : }
     152             : 
     153             : 
     154          18 : void appender::set_config(advgetopt::getopt const & opts)
     155             : {
     156          36 :     guard g;
     157             : 
     158             :     // ENABLE
     159             :     //
     160             :     {
     161          36 :         std::string const specialized_enabled(f_name + "::enabled");
     162          18 :         if(opts.is_defined(specialized_enabled))
     163             :         {
     164           0 :             f_enabled = opts.get_string(specialized_enabled) != "false";
     165             :         }
     166          18 :         else if(opts.is_defined("enabled"))
     167             :         {
     168           0 :             f_enabled = opts.get_string("enabled") != "false";
     169             :         }
     170             :         else
     171             :         {
     172          18 :             f_enabled = true;
     173             :         }
     174             :     }
     175             : 
     176             :     // FORMAT
     177             :     //
     178             :     {
     179          36 :         std::string const specialized_format(f_name + "::format");
     180          18 :         if(opts.is_defined(specialized_format))
     181             :         {
     182           0 :             f_format = std::make_shared<format>(opts.get_string(specialized_format));
     183             :         }
     184          18 :         else if(opts.is_defined("format"))
     185             :         {
     186           0 :             f_format = std::make_shared<format>(opts.get_string("format"));
     187             :         }
     188             :     }
     189             : 
     190             :     // SEVERITY
     191             :     //
     192          36 :     std::string const specialized_severity(f_name + "::severity");
     193          18 :     if(opts.is_defined(specialized_severity))
     194             :     {
     195           0 :         std::string const severity_name(opts.get_string(specialized_severity));
     196           0 :         severity::pointer_t sev(snaplogger::get_severity(severity_name));
     197           0 :         if(sev != nullptr)
     198             :         {
     199           0 :             set_severity(sev->get_severity());
     200             :         }
     201             :         else
     202             :         {
     203             :             throw invalid_severity(
     204             :                           "severity level named \""
     205           0 :                         + severity_name
     206           0 :                         + "\" not found.");
     207             :         }
     208             :     }
     209          18 :     else if(opts.is_defined("severity"))
     210             :     {
     211           0 :         std::string const severity_name(opts.get_string("severity"));
     212           0 :         severity::pointer_t sev(snaplogger::get_severity(severity_name));
     213           0 :         if(sev != nullptr)
     214             :         {
     215           0 :             set_severity(sev->get_severity());
     216             :         }
     217             :         else
     218             :         {
     219             :             throw invalid_severity(
     220             :                           "severity level named \""
     221           0 :                         + severity_name
     222           0 :                         + "\" not found.");
     223             :         }
     224             :     }
     225             : 
     226             :     // COMPONENTS
     227             :     //
     228          36 :     std::string comp;
     229          36 :     std::string const components(f_name + "::components");
     230          18 :     if(opts.is_defined(components))
     231             :     {
     232           0 :         comp = opts.get_string(components);
     233             :     }
     234          18 :     else if(opts.is_defined("components"))
     235             :     {
     236           0 :         comp = opts.get_string("components");
     237             :     }
     238          18 :     if(comp.empty())
     239             :     {
     240          18 :         add_component(f_normal_component);
     241             :     }
     242             :     else
     243             :     {
     244           0 :         advgetopt::string_list_t component_names;
     245           0 :         advgetopt::split_string(comp, component_names, {","});
     246           0 :         for(auto name : component_names)
     247             :         {
     248           0 :             add_component(get_component(name));
     249             :         }
     250             :     }
     251             : 
     252             :     // FILTER
     253             :     //
     254             :     {
     255          36 :         std::string filter;
     256          36 :         std::string const specialized_filter(f_name + "::filter");
     257          18 :         if(opts.is_defined(specialized_filter))
     258             :         {
     259           0 :             filter = opts.get_string(specialized_filter);
     260             :         }
     261          18 :         else if(opts.is_defined("filter"))
     262             :         {
     263           0 :             filter = opts.get_string("filter");
     264             :         }
     265          18 :         if(!filter.empty())
     266             :         {
     267           0 :             std::regex_constants::syntax_option_type flags(std::regex::nosubs | std::regex::optimize);
     268           0 :             std::regex_constants::syntax_option_type type(std::regex::extended);
     269           0 :             if(filter[0] == '/')
     270             :             {
     271           0 :                 std::string::size_type pos(filter.rfind('/'));
     272           0 :                 if(pos == 0)
     273             :                 {
     274             :                     throw invalid_variable(
     275             :                                   "invalid filter \""
     276           0 :                                 + filter
     277           0 :                                 + "\"; missing ending '/'.");
     278             :                 }
     279           0 :                 std::string const flag_list(filter.substr(pos + 1));
     280           0 :                 filter = filter.substr(1, pos - 2);
     281           0 :                 if(filter.empty())
     282             :                 {
     283             :                     throw invalid_variable(
     284             :                                   "invalid filter \""
     285           0 :                                 + filter
     286           0 :                                 + "\"; the regular expression is empty.");
     287             :                 }
     288             :                 // TODO: for errors we would need to iterate using the libutf8
     289             :                 //       (since we could have a Unicode character after the /)
     290             :                 //
     291             :                 // TODO: if two type flags are found, err too
     292             :                 //
     293           0 :                 int count(0);
     294           0 :                 for(auto f : flag_list)
     295             :                 {
     296           0 :                     switch(f)
     297             :                     {
     298           0 :                     case 'i':
     299           0 :                         flags |= std::regex::icase;
     300           0 :                         break;
     301             : 
     302           0 :                     case 'c':
     303           0 :                         flags |= std::regex::collate;
     304           0 :                         break;
     305             : 
     306           0 :                     case 'j':
     307           0 :                         type = std::regex::ECMAScript;
     308           0 :                         ++count;
     309           0 :                         break;
     310             : 
     311           0 :                     case 'b':
     312           0 :                         type = std::regex::basic;
     313           0 :                         ++count;
     314           0 :                         break;
     315             : 
     316           0 :                     case 'x':
     317           0 :                         type = std::regex::extended;
     318           0 :                         ++count;
     319           0 :                         break;
     320             : 
     321           0 :                     case 'a':
     322           0 :                         type = std::regex::awk;
     323           0 :                         ++count;
     324           0 :                         break;
     325             : 
     326           0 :                     case 'g':
     327           0 :                         type = std::regex::grep;
     328           0 :                         ++count;
     329           0 :                         break;
     330             : 
     331           0 :                     case 'e':
     332           0 :                         type = std::regex::egrep;
     333           0 :                         ++count;
     334           0 :                         break;
     335             : 
     336           0 :                     default:
     337             :                         throw invalid_variable(
     338             :                                       "in \""
     339           0 :                                     + filter
     340           0 :                                     + "\", found invalid flag '"
     341           0 :                                     + f
     342           0 :                                     + "'.");
     343             : 
     344             :                     }
     345           0 :                     if(count > 1)
     346             :                     {
     347             :                         throw invalid_variable(
     348             :                                       "found multiple types in \""
     349           0 :                                     + filter
     350           0 :                                     + "\".");
     351             :                     }
     352             :                 }
     353             :             }
     354           0 :             f_filter = std::make_shared<std::regex>(filter, flags | type);
     355             :         }
     356             :     }
     357          18 : }
     358             : 
     359             : 
     360           0 : void appender::reopen()
     361             : {
     362           0 : }
     363             : 
     364             : 
     365          19 : void appender::add_component(component::pointer_t comp)
     366             : {
     367          19 :     f_components.insert(comp);
     368          19 : }
     369             : 
     370             : 
     371          40 : format::pointer_t appender::set_format(format::pointer_t new_format)
     372             : {
     373          80 :     guard g;
     374             : 
     375          40 :     format::pointer_t old(f_format);
     376          40 :     f_format = new_format;
     377          80 :     return old;
     378             : }
     379             : 
     380             : 
     381       94627 : void appender::send_message(message const & msg)
     382             : {
     383      189254 :     if(!is_enabled()
     384       94627 :     || msg.get_severity() < f_severity)
     385             :     {
     386       98193 :         return;
     387             :     }
     388             : 
     389       48157 :     component::set_t const & components(msg.get_components());
     390       48157 :     if(components.empty())
     391             :     {
     392             :         // user did not supply any component in 'msg', check for
     393             :         // the normal component
     394             :         //
     395       96306 :         if(!f_components.empty()
     396       48153 :         && f_components.find(f_normal_component) == f_components.end())
     397             :         {
     398           0 :             return;
     399             :         }
     400             :     }
     401             :     else
     402             :     {
     403           4 :         if(snap::empty_set_intersection(f_components, components))
     404             :         {
     405           2 :             return;
     406             :         }
     407             :     }
     408             : 
     409       91054 :     std::string formatted_message(f_format->process_message(msg));
     410       48150 :     if(formatted_message.empty())
     411             :     {
     412        5251 :         return;
     413             :     }
     414             : 
     415       85798 :     if(f_filter != nullptr
     416       42899 :     && !std::regex_match(formatted_message, *f_filter))
     417             :     {
     418           0 :         return;
     419             :     }
     420             : 
     421       85798 :     if(formatted_message.back() != '\n'
     422       42899 :     && formatted_message.back() != '\r')
     423             :     {
     424             :         // TODO: add support to define line terminator (cr, nl, cr nl)
     425             :         //
     426       42899 :         formatted_message += '\n';
     427             :     }
     428             : 
     429       42899 :     process_message(msg, formatted_message);
     430             : }
     431             : 
     432             : 
     433           0 : void appender::process_message(message const & msg, std::string const & formatted_message)
     434             : {
     435             :     // the default is a "null appender" -- do nothing
     436           0 :     snap::NOTUSED(msg);
     437           0 :     snap::NOTUSED(formatted_message);
     438           0 : }
     439             : 
     440             : 
     441             : 
     442             : 
     443             : 
     444           8 : appender_factory::appender_factory(std::string const & type)
     445           8 :     : f_type(type)
     446             : {
     447           8 : }
     448             : 
     449             : 
     450           8 : appender_factory::~appender_factory()
     451             : {
     452           8 : }
     453             : 
     454             : 
     455          16 : std::string const & appender_factory::get_type() const
     456             : {
     457          16 :     return f_type;
     458             : }
     459             : 
     460             : 
     461             : 
     462             : 
     463           8 : void register_appender_factory(appender_factory::pointer_t factory)
     464             : {
     465           8 :     get_private_logger()->register_appender_factory(factory);
     466           8 : }
     467             : 
     468             : 
     469           2 : appender::pointer_t create_appender(std::string const & type, std::string const & name)
     470             : {
     471           2 :     return get_private_logger()->create_appender(type, name);
     472             : }
     473             : 
     474             : 
     475             : 
     476             : 
     477             : 
     478             : 
     479           0 : safe_format::safe_format(appender::pointer_t a, format::pointer_t new_format)
     480             :     : f_appender(a)
     481           0 :     , f_old_format(a->set_format(new_format))
     482             : {
     483           0 : }
     484             : 
     485             : 
     486           0 : safe_format::~safe_format()
     487             : {
     488           0 :     snap::NOTUSED(f_appender->set_format(f_old_format));
     489           0 : }
     490             : 
     491             : 
     492             : 
     493             : 
     494             : 
     495             : 
     496             : 
     497           6 : } // snaplogger namespace
     498             : // vim: ts=4 sw=4 et

Generated by: LCOV version 1.13