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

Generated by: LCOV version 1.12