LCOV - code coverage report
Current view: top level - snaplogger - message.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 100 172 58.1 %
Date: 2021-10-14 20:12:47 Functions: 28 37 75.7 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : // Copyright (c) 2013-2021  Made to Order Software Corp.  All Rights Reserved
       2             : //
       3             : // https://snapwebsites.org/project/snaplogger
       4             : // contact@m2osw.com
       5             : //
       6             : // This program is free software; you can redistribute it and/or modify
       7             : // it under the terms of the GNU General Public License as published by
       8             : // the Free Software Foundation; either version 2 of the License, or
       9             : // (at your option) any later version.
      10             : //
      11             : // This program is distributed in the hope that it will be useful,
      12             : // but WITHOUT ANY WARRANTY; without even the implied warranty of
      13             : // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      14             : // GNU General Public License for more details.
      15             : //
      16             : // You should have received a copy of the GNU General Public License along
      17             : // with this program; if not, write to the Free Software Foundation, Inc.,
      18             : // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
      19             : 
      20             : /** \file
      21             :  * \brief Appenders are used to append data to somewhere.
      22             :  *
      23             :  * This file declares the base appender class.
      24             :  */
      25             : 
      26             : // self
      27             : // 
      28             : #include    "snaplogger/message.h"
      29             : 
      30             : #include    "snaplogger/exception.h"
      31             : #include    "snaplogger/guard.h"
      32             : #include    "snaplogger/logger.h"
      33             : 
      34             : 
      35             : // C++ lib
      36             : //
      37             : #include    <iostream>
      38             : 
      39             : 
      40             : // C lib
      41             : //
      42             : #include    <sys/time.h>
      43             : 
      44             : 
      45             : // last include
      46             : //
      47             : #include    <snapdev/poison.h>
      48             : 
      49             : 
      50             : 
      51             : namespace snaplogger
      52             : {
      53             : 
      54             : 
      55             : namespace
      56             : {
      57             : 
      58             : #pragma GCC diagnostic push
      59             : #pragma GCC diagnostic ignored "-Wpedantic"
      60             : constexpr char const * const g_system_field_names[] =
      61             : {
      62             :     [static_cast<std::size_t>(system_field_t::SYSTEM_FIELD_MESSAGE      )] = "_message",
      63             :     [static_cast<std::size_t>(system_field_t::SYSTEM_FIELD_TIMESTAMP    )] = "_timestamp",
      64             :     [static_cast<std::size_t>(system_field_t::SYSTEM_FIELD_SEVERITY     )] = "_severity",
      65             :     [static_cast<std::size_t>(system_field_t::SYSTEM_FIELD_FILENAME     )] = "_filename",
      66             :     [static_cast<std::size_t>(system_field_t::SYSTEM_FIELD_FUNCTION_NAME)] = "_function_name",
      67             :     [static_cast<std::size_t>(system_field_t::SYSTEM_FIELD_LINE         )] = "_line",
      68             : };
      69             : #pragma GCC diagnostic pop
      70             : 
      71             : 
      72             : int         g_message_id = 0;
      73             : 
      74             : 
      75       94852 : int get_next_id()
      76             : {
      77      189704 :     guard g;
      78             : 
      79       94852 :     ++g_message_id;
      80       94852 :     if(g_message_id == 0)
      81             :     {
      82             :         // never use 0 as the id; of course, it's very unlikely that this happens
      83           0 :         g_message_id = 1;
      84             :     }
      85      189704 :     return g_message_id;
      86             : }
      87             : 
      88             : 
      89             : 
      90             : }
      91             : // no name namespace
      92             : 
      93             : 
      94             : 
      95             : 
      96     1071787 : int null_buffer::overflow(int c)
      97             : {
      98     1071787 :     return c;
      99             : }
     100             : 
     101             : 
     102             : 
     103             : 
     104             : 
     105       94852 : message::message(
     106             :           severity_t sev
     107             :         , char const * file
     108             :         , char const * func
     109       94852 :         , int line)
     110             :     : f_logger(logger::get_instance())
     111             :     , f_severity(sev)
     112             :     , f_filename(file == nullptr ? std::string() : std::string(file))
     113             :     , f_funcname(func == nullptr ? std::string() : std::string(func))
     114             :     , f_line(line)
     115             :     , f_environment(create_environment())
     116       94852 :     , f_fields(f_logger->get_default_fields())
     117             : {
     118       94852 :     clock_gettime(CLOCK_REALTIME_COARSE, &f_timestamp);
     119             : 
     120       94852 :     add_field("id", std::to_string(get_next_id()));
     121             : 
     122      189704 :     if(f_severity < f_logger->get_lowest_severity()
     123       94852 :     || f_severity == severity_t::SEVERITY_OFF)
     124             :     {
     125       47003 :         f_null.reset(new null_buffer);
     126       47003 :         std::ostream & ref = *this;
     127       47003 :         f_saved_buffer = ref.rdbuf(f_null.get());
     128             :     }
     129       94852 : }
     130             : 
     131             : 
     132           2 : message::message(std::basic_stringstream<char> const & m, message const & msg)
     133             :     : f_logger(msg.f_logger)
     134             :     , f_timestamp(msg.f_timestamp)
     135           2 :     , f_severity(msg.f_severity)
     136             :     , f_filename(msg.f_filename)
     137             :     , f_funcname(msg.f_funcname)
     138           2 :     , f_line(msg.f_line)
     139           2 :     , f_recursive_message(msg.f_recursive_message)
     140             :     , f_environment(msg.f_environment)
     141             :     , f_components(msg.f_components)
     142             :     , f_fields(msg.f_fields)
     143             :     , f_null(null_buffer::pointer_t())
     144             :     , f_saved_buffer(nullptr)
     145           8 :     , f_copy(true)
     146             : {
     147           2 :     *this << m.rdbuf();
     148           2 : }
     149             : 
     150             : 
     151      189708 : message::~message()
     152             : {
     153       94854 :     if(f_saved_buffer != nullptr)
     154             :     {
     155       47003 :         std::ostream & ref = *this;
     156       47003 :         ref.rdbuf(f_saved_buffer);
     157             :     }
     158       94854 : }
     159             : 
     160             : 
     161           0 : severity_t message::default_severity()
     162             : {
     163           0 :     return logger::get_instance()->get_default_severity();
     164             : }
     165             : 
     166             : 
     167       29253 : void message::set_severity(severity_t severity)
     168             : {
     169       29253 :     f_severity = severity;
     170       29253 : }
     171             : 
     172             : 
     173           1 : void message::set_filename(std::string const & filename)
     174             : {
     175           1 :     f_filename = filename;
     176           1 : }
     177             : 
     178             : 
     179           1 : void message::set_function(std::string const & funcname)
     180             : {
     181           1 :     f_funcname = funcname;
     182           1 : }
     183             : 
     184             : 
     185           1 : void message::set_line(int line)
     186             : {
     187           1 :     f_line = line;
     188           1 : }
     189             : 
     190             : 
     191          34 : void message::set_recursive_message(bool state) const
     192             : {
     193          34 :     f_recursive_message = state;
     194          34 : }
     195             : 
     196             : 
     197           8 : bool message::can_add_component(component::pointer_t c) const
     198             : {
     199           8 :     if(c != nullptr)
     200             :     {
     201           8 :         return !c->is_mutually_exclusive(f_components);
     202             :     }
     203             : 
     204           0 :     return false;
     205             : }
     206             : 
     207             : 
     208           8 : void message::add_component(component::pointer_t c)
     209             : {
     210           8 :     if(c != nullptr)
     211             :     {
     212           8 :         if(!can_add_component(c))
     213             :         {
     214             :             throw conflict_error(
     215             :                   "component \""
     216           0 :                 + c->get_name()
     217           0 :                 + "\" cannot be added to this message as it is mutually exclusive with one or more of the other components that were already added to this message.");
     218             :         }
     219             : 
     220           8 :         f_components.insert(c);
     221             :     }
     222           8 : }
     223             : 
     224             : 
     225       94855 : void message::add_field(std::string const & name, std::string const & value)
     226             : {
     227       94855 :     if(!name.empty())
     228             :     {
     229       94855 :         if(name[0] == '_')
     230             :         {
     231             :             throw invalid_parameter(
     232             :                   "field name \""
     233           0 :                 + name
     234           0 :                 + "\" is a system name (whether reserved or already defined) and as such is read-only."
     235           0 :                   " Do not start your field names with an underscore (_).");
     236             :         }
     237             : 
     238       94855 :         f_fields[name] = value;
     239             :     }
     240       94855 : }
     241             : 
     242             : 
     243       48456 : std::shared_ptr<logger> message::get_logger() const
     244             : {
     245       48456 :     return f_logger;
     246             : }
     247             : 
     248             : 
     249      189782 : severity_t message::get_severity() const
     250             : {
     251      189782 :     return f_severity;
     252             : }
     253             : 
     254             : 
     255           0 : void message::set_precise_time()
     256             : {
     257           0 :     clock_gettime(CLOCK_REALTIME, &f_timestamp);
     258           0 : }
     259             : 
     260             : 
     261           4 : timespec const & message::get_timestamp() const
     262             : {
     263           4 :     return f_timestamp;
     264             : }
     265             : 
     266             : 
     267           2 : std::string const & message::get_filename() const
     268             : {
     269           2 :     return f_filename;
     270             : }
     271             : 
     272             : 
     273           2 : std::string const & message::get_function() const
     274             : {
     275           2 :     return f_funcname;
     276             : }
     277             : 
     278             : 
     279           2 : int message::get_line() const
     280             : {
     281           2 :     return f_line;
     282             : }
     283             : 
     284             : 
     285       48250 : bool message::get_recursive_message() const
     286             : {
     287       48250 :     return f_recursive_message;
     288             : }
     289             : 
     290             : 
     291           0 : bool message::has_component(component::pointer_t c) const
     292             : {
     293           0 :     return f_components.find(c) != f_components.end();
     294             : }
     295             : 
     296             : 
     297      143107 : component::set_t const & message::get_components() const
     298             : {
     299      143107 :     return f_components;
     300             : }
     301             : 
     302             : 
     303          47 : environment::pointer_t message::get_environment() const
     304             : {
     305          47 :     return f_environment;
     306             : }
     307             : 
     308             : 
     309       48248 : std::string message::get_message() const
     310             : {
     311       48248 :     std::string s(str());
     312             : 
     313       96496 :     if(!s.empty()
     314       48248 :     && s.back() == '\n')
     315             :     {
     316           4 :         s.pop_back();
     317             :     }
     318             : 
     319       96496 :     if(!s.empty()
     320       48248 :     && s.back() == '\r')
     321             :     {
     322           2 :         s.pop_back();
     323             :     }
     324             : 
     325       48248 :     return s;
     326             : }
     327             : 
     328             : 
     329           0 : char const * message::get_system_field_name(system_field_t field)
     330             : {
     331           0 :     std::size_t const idx(static_cast<std::size_t>(field));
     332           0 :     if(idx >= static_cast<std::size_t>(system_field_t::SYSTEM_FIELD_max))
     333             :     {
     334           0 :         return "_unknown";
     335             :     }
     336           0 :     return g_system_field_names[idx];
     337             : }
     338             : 
     339             : 
     340           0 : system_field_t message::get_system_field_from_name(std::string const & name)
     341             : {
     342           0 :     if(name.length() >= 2
     343           0 :     && name[0] == '_')
     344             :     {
     345           0 :         switch(name[1])
     346             :         {
     347           0 :         case 'f':
     348           0 :             if(name == "_filename")
     349             :             {
     350           0 :                 return system_field_t::SYSTEM_FIELD_FILENAME;
     351             :             }
     352           0 :             if(name == "_function_name")
     353             :             {
     354           0 :                 return system_field_t::SYSTEM_FIELD_FUNCTION_NAME;
     355             :             }
     356           0 :             break;
     357             : 
     358           0 :         case 'l':
     359           0 :             if(name == "_line")
     360             :             {
     361           0 :                 return system_field_t::SYSTEM_FIELD_LINE;
     362             :             }
     363           0 :             break;
     364             : 
     365           0 :         case 'm':
     366           0 :             if(name == "_message")
     367             :             {
     368           0 :                 return system_field_t::SYSTEM_FIELD_MESSAGE;
     369             :             }
     370           0 :             break;
     371             : 
     372           0 :         case 's':
     373           0 :             if(name == "_severity")
     374             :             {
     375           0 :                 return system_field_t::SYSTEM_FIELD_SEVERITY;
     376             :             }
     377           0 :             break;
     378             : 
     379           0 :         case 't':
     380           0 :             if(name == "_timestamp")
     381             :             {
     382           0 :                 return system_field_t::SYSTEM_FIELD_TIMESTAMP;
     383             :             }
     384           0 :             break;
     385             : 
     386             :         }
     387             :     }
     388             : 
     389           0 :     return system_field_t::SYSTEM_FIELD_UNDEFINED;
     390             : }
     391             : 
     392             : 
     393           1 : std::string message::get_field(std::string const & name) const
     394             : {
     395           2 :     if(!name.empty()
     396           1 :     && name[0] == '_')
     397             :     {
     398           0 :         switch(get_system_field_from_name(name))
     399             :         {
     400           0 :         case system_field_t::SYSTEM_FIELD_MESSAGE:
     401           0 :             return get_message();
     402             : 
     403           0 :         case system_field_t::SYSTEM_FIELD_TIMESTAMP:
     404             :             // TODO: offer ways to get the date & time converted to strings
     405             :             {
     406           0 :                 std::string timestamp(std::to_string(f_timestamp.tv_sec));
     407           0 :                 if(f_timestamp.tv_nsec != 0)
     408             :                 {
     409           0 :                     std::string nsec(std::to_string(f_timestamp.tv_nsec));
     410           0 :                     while(nsec.length() < 9)
     411             :                     {
     412           0 :                         nsec = '0' + nsec;
     413             :                     }
     414           0 :                     while(nsec.back() == '0')
     415             :                     {
     416           0 :                         nsec.pop_back();
     417             :                     }
     418           0 :                     timestamp += '.';
     419           0 :                     timestamp += nsec;
     420             :                 }
     421           0 :                 return timestamp;
     422             :             }
     423             : 
     424           0 :         case system_field_t::SYSTEM_FIELD_SEVERITY:
     425             :             {
     426           0 :                 severity::pointer_t sev(snaplogger::get_severity(f_severity));
     427           0 :                 return sev == nullptr ? "<unknown>" : sev->get_name();
     428             :             }
     429             : 
     430           0 :         case system_field_t::SYSTEM_FIELD_FILENAME:
     431           0 :             return f_filename;
     432             : 
     433           0 :         case system_field_t::SYSTEM_FIELD_FUNCTION_NAME:
     434           0 :             return f_funcname;
     435             : 
     436           0 :         case system_field_t::SYSTEM_FIELD_LINE:
     437           0 :             return std::to_string(f_line);
     438             : 
     439           0 :         default:
     440           0 :             return std::string();
     441             : 
     442             :         }
     443             :     }
     444             : 
     445           1 :     auto it(f_fields.find(name));
     446           1 :     if(it == f_fields.end())
     447             :     {
     448           0 :         return std::string();
     449             :     }
     450           1 :     return it->second;
     451             : }
     452             : 
     453             : 
     454           1 : field_map_t message::get_fields() const
     455             : {
     456           1 :     return f_fields;
     457             : }
     458             : 
     459             : 
     460       94845 : void send_message(std::basic_ostream<char> & out)
     461             : {
     462       94845 :     message * msg(dynamic_cast<message *>(&out));
     463       94845 :     if(msg == nullptr)
     464             :     {
     465           1 :         throw not_a_message("the 'out' parameter to the send_message() function is expected to be a snaplogger::message object.");
     466             :     }
     467             : 
     468       94845 :     logger::get_instance()->log_message(*msg);
     469       94843 : }
     470             : 
     471             : 
     472             : 
     473             : 
     474           6 : } // snaplogger namespace
     475             : // vim: ts=4 sw=4 et

Generated by: LCOV version 1.13