log: modularise the logging infrastructure
This commit is contained in:
parent
2e16e8962b
commit
67ea686753
@ -423,8 +423,22 @@ list (
|
|||||||
list/sort.hpp
|
list/sort.hpp
|
||||||
log.hpp
|
log.hpp
|
||||||
log/fwd.hpp
|
log/fwd.hpp
|
||||||
log/log.hpp
|
log/level.cpp
|
||||||
|
log/level.hpp
|
||||||
log/log.cpp
|
log/log.cpp
|
||||||
|
log/log.hpp
|
||||||
|
log/packet.cpp
|
||||||
|
log/packet.hpp
|
||||||
|
log/scoped.cpp
|
||||||
|
log/scoped.hpp
|
||||||
|
log/sink/base.cpp
|
||||||
|
log/sink/base.hpp
|
||||||
|
log/sink/console.cpp
|
||||||
|
log/sink/console.hpp
|
||||||
|
log/sink/null.cpp
|
||||||
|
log/sink/null.hpp
|
||||||
|
log/sink/ostream.cpp
|
||||||
|
log/sink/ostream.hpp
|
||||||
map/fixed.cpp
|
map/fixed.cpp
|
||||||
map/fixed.hpp
|
map/fixed.hpp
|
||||||
maths.cpp
|
maths.cpp
|
||||||
|
22
log/fwd.hpp
Normal file
22
log/fwd.hpp
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
/*
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
*
|
||||||
|
* Copyright 2019, Danny Robson <danny@nerdcruft.net>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace cruft::log {
|
||||||
|
struct packet;
|
||||||
|
|
||||||
|
namespace sink {
|
||||||
|
class base;
|
||||||
|
|
||||||
|
class console;
|
||||||
|
class noop;
|
||||||
|
class ostream;
|
||||||
|
class tee;
|
||||||
|
};
|
||||||
|
}
|
138
log/level.cpp
Normal file
138
log/level.cpp
Normal file
@ -0,0 +1,138 @@
|
|||||||
|
/*
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
*
|
||||||
|
* Copyright 2012-2016 Danny Robson <danny@nerdcruft.net>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "level.hpp"
|
||||||
|
|
||||||
|
#include "../debug/assert.hpp"
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// convert a string representation of a log-level into an enumeration value.
|
||||||
|
///
|
||||||
|
/// conversion is case insensitive
|
||||||
|
/// throws std::range_error if unable to convert
|
||||||
|
cruft::log::level_t
|
||||||
|
cruft::log::to_level (std::string_view name)
|
||||||
|
{
|
||||||
|
if (std::empty (name))
|
||||||
|
return cruft::log::EMERGENCY;
|
||||||
|
|
||||||
|
std::string upper (name.size (), char{});
|
||||||
|
std::transform (
|
||||||
|
name.cbegin (),
|
||||||
|
name.cend (),
|
||||||
|
upper.begin (),
|
||||||
|
::toupper
|
||||||
|
);
|
||||||
|
|
||||||
|
static constexpr struct {
|
||||||
|
char const *name;
|
||||||
|
cruft::log::level_t value;
|
||||||
|
} VALUES[] = {
|
||||||
|
{ "EMERGENCY", cruft::log::EMERGENCY },
|
||||||
|
{ "ALERT", cruft::log::ALERT },
|
||||||
|
{ "CRITICAL", cruft::log::CRITICAL },
|
||||||
|
{ "ERROR", cruft::log::ERROR },
|
||||||
|
{ "WARN", cruft::log::WARN },
|
||||||
|
{ "WARNING", cruft::log::WARN },
|
||||||
|
{ "NOTICE", cruft::log::NOTICE },
|
||||||
|
{ "INFO", cruft::log::INFO },
|
||||||
|
{ "INFORMATIONAL", cruft::log::INFO },
|
||||||
|
{ "DEBUG", cruft::log::DEBUG }
|
||||||
|
};
|
||||||
|
|
||||||
|
for (auto const [key, val]: VALUES)
|
||||||
|
if (!strcmp (upper.data (), key))
|
||||||
|
return val;
|
||||||
|
|
||||||
|
throw std::invalid_argument (std::string (name));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
const std::string&
|
||||||
|
cruft::log::to_string (level_t l)
|
||||||
|
{
|
||||||
|
switch (l) {
|
||||||
|
#define CASE(L) \
|
||||||
|
case cruft::log::L: { \
|
||||||
|
static const std::string STR = #L; \
|
||||||
|
return STR; \
|
||||||
|
}
|
||||||
|
|
||||||
|
MAP_LEVEL_T(CASE)
|
||||||
|
|
||||||
|
#undef CASE
|
||||||
|
}
|
||||||
|
|
||||||
|
unreachable ();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
std::ostream&
|
||||||
|
cruft::log::operator<< (std::ostream& os, level_t l)
|
||||||
|
{
|
||||||
|
return os << to_string (l);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Determine what the value for LOG_LEVEL should be at the beginning of
|
||||||
|
// execution given the system environment.
|
||||||
|
//
|
||||||
|
// Note that the LOG macros _cannot_ be used from within this function as it
|
||||||
|
// will likely result in infinite recursion.
|
||||||
|
static cruft::log::level_t
|
||||||
|
initial_log_level (void)
|
||||||
|
{
|
||||||
|
const char *env = getenv ("LOG_LEVEL");
|
||||||
|
if (!env)
|
||||||
|
return cruft::log::DEFAULT_LOG_LEVEL;
|
||||||
|
|
||||||
|
try {
|
||||||
|
return cruft::log::to_level (env);
|
||||||
|
} catch (...) {
|
||||||
|
std::clog << "Invalid environment LOG_LEVEL: '" << env << "'\n";
|
||||||
|
return cruft::log::DEFAULT_LOG_LEVEL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// We shouldn't ever actually get to use the default value, but we set it to
|
||||||
|
// the most verbose option just in case we've made a mistake elsewhere.
|
||||||
|
|
||||||
|
static bool s_log_level_done;
|
||||||
|
static cruft::log::level_t s_log_level_value;
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
cruft::log::level_t
|
||||||
|
cruft::log::log_level (level_t _level)
|
||||||
|
{
|
||||||
|
s_log_level_value = _level;
|
||||||
|
s_log_level_done = true;
|
||||||
|
return s_log_level_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
cruft::log::level_t
|
||||||
|
cruft::log::log_level (void)
|
||||||
|
{
|
||||||
|
if (!s_log_level_done) {
|
||||||
|
s_log_level_value = initial_log_level ();
|
||||||
|
s_log_level_done = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return s_log_level_value;
|
||||||
|
}
|
76
log/level.hpp
Normal file
76
log/level.hpp
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
/*
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
*
|
||||||
|
* Copyright 2012-2019 Danny Robson <danny@nerdcruft.net>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cruft/util/preprocessor.hpp>
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
|
||||||
|
namespace cruft::log {
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
// rfc5424 log levels. It is assumed they are contiguous to simplify array
|
||||||
|
// indexing in logging code.
|
||||||
|
enum level_t {
|
||||||
|
EMERGENCY, /** system is unusable */
|
||||||
|
ALERT, /** action must be taken immediately */
|
||||||
|
CRITICAL, /** critical conditions */
|
||||||
|
ERROR, /** error conditions */
|
||||||
|
WARNING,
|
||||||
|
WARN = WARNING, /** warning conditions */
|
||||||
|
NOTICE, /** normal but significant condition */
|
||||||
|
INFORMATIONAL,
|
||||||
|
INFO = INFORMATIONAL, /** informational messages */
|
||||||
|
DEBUG /** debug-level messages */
|
||||||
|
};
|
||||||
|
|
||||||
|
#define MAP_LEVEL_T(F) \
|
||||||
|
MAP0(F, \
|
||||||
|
EMERGENCY, \
|
||||||
|
ALERT, \
|
||||||
|
CRITICAL, \
|
||||||
|
ERROR, \
|
||||||
|
WARN, \
|
||||||
|
NOTICE, \
|
||||||
|
INFO, \
|
||||||
|
DEBUG \
|
||||||
|
)
|
||||||
|
|
||||||
|
constexpr auto DEFAULT_LOG_LEVEL = NOTICE;
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------
|
||||||
|
std::string const& to_string (level_t);
|
||||||
|
level_t to_level (std::string_view);
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------
|
||||||
|
std::ostream&
|
||||||
|
operator<< (std::ostream&, level_t);
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
// Query or set the global logging level filter. If the severity passed to
|
||||||
|
// a logging call is less than this then the output is discarded.
|
||||||
|
//
|
||||||
|
// The initial logging level can be controlled by setting the environment
|
||||||
|
// variable LOG_LEVEL to a string corresponding to the names of the values
|
||||||
|
// in level_t.
|
||||||
|
//
|
||||||
|
// Otherwise we fall back to the hard coded default from above.
|
||||||
|
//
|
||||||
|
// As a special case, a blank value for the environment variable LOG_LEVEL
|
||||||
|
// corresponds to the maximum log level. It indicates a preference for
|
||||||
|
// minimum output, and may be changed to disable all output in future
|
||||||
|
// updates.
|
||||||
|
level_t log_level (void);
|
||||||
|
level_t log_level (level_t);
|
||||||
|
|
||||||
|
|
||||||
|
bool needs_break (level_t);
|
||||||
|
|
||||||
|
}
|
267
log/log.cpp
267
log/log.cpp
@ -9,161 +9,21 @@
|
|||||||
|
|
||||||
#include "log.hpp"
|
#include "log.hpp"
|
||||||
|
|
||||||
#include "../term.hpp"
|
|
||||||
#include "../time.hpp"
|
|
||||||
#include "../cast.hpp"
|
#include "../cast.hpp"
|
||||||
#include "../string.hpp"
|
#include "../string.hpp"
|
||||||
|
|
||||||
#include <cstring>
|
#include "sink/console.hpp"
|
||||||
#include <ctime>
|
|
||||||
#include <iomanip>
|
|
||||||
#include <iostream>
|
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
|
||||||
static constexpr
|
|
||||||
cruft::log::level_t
|
|
||||||
ALL_LEVELS[] = {
|
|
||||||
cruft::log::EMERGENCY,
|
|
||||||
cruft::log::ALERT,
|
|
||||||
cruft::log::CRITICAL,
|
|
||||||
cruft::log::ERROR,
|
|
||||||
cruft::log::WARN,
|
|
||||||
cruft::log::NOTICE,
|
|
||||||
cruft::log::INFO,
|
|
||||||
cruft::log::DEBUG,
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
/// convert a string representation of a log-level into an enumeration value.
|
bool
|
||||||
///
|
cruft::log::needs_break (level_t level)
|
||||||
/// conversion is case insensitive
|
|
||||||
/// throws std::range_error if unable to convert
|
|
||||||
cruft::log::level_t
|
|
||||||
cruft::log::to_level (std::string_view name)
|
|
||||||
{
|
{
|
||||||
if (std::empty (name))
|
static level_t break_level;
|
||||||
return cruft::log::EMERGENCY;
|
|
||||||
|
|
||||||
std::string upper (name.size (), char{});
|
|
||||||
std::transform (
|
|
||||||
name.cbegin (),
|
|
||||||
name.cend (),
|
|
||||||
upper.begin (),
|
|
||||||
::toupper
|
|
||||||
);
|
|
||||||
|
|
||||||
static constexpr struct {
|
|
||||||
char const *name;
|
|
||||||
cruft::log::level_t value;
|
|
||||||
} VALUES[] = {
|
|
||||||
{ "EMERGENCY", cruft::log::EMERGENCY },
|
|
||||||
{ "ALERT", cruft::log::ALERT },
|
|
||||||
{ "CRITICAL", cruft::log::CRITICAL },
|
|
||||||
{ "ERROR", cruft::log::ERROR },
|
|
||||||
{ "WARN", cruft::log::WARN },
|
|
||||||
{ "WARNING", cruft::log::WARN },
|
|
||||||
{ "NOTICE", cruft::log::NOTICE },
|
|
||||||
{ "INFO", cruft::log::INFO },
|
|
||||||
{ "INFORMATIONAL", cruft::log::INFO },
|
|
||||||
{ "DEBUG", cruft::log::DEBUG }
|
|
||||||
};
|
|
||||||
|
|
||||||
for (auto const [key, val]: VALUES)
|
|
||||||
if (!strcmp (upper.data (), key))
|
|
||||||
return val;
|
|
||||||
|
|
||||||
throw std::invalid_argument (std::string (name));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
|
||||||
const std::string&
|
|
||||||
cruft::log::to_string (level_t l)
|
|
||||||
{
|
|
||||||
switch (l) {
|
|
||||||
#define CASE(L) \
|
|
||||||
case cruft::log::L: { \
|
|
||||||
static const std::string STR = #L; \
|
|
||||||
return STR; \
|
|
||||||
}
|
|
||||||
|
|
||||||
MAP_LEVEL_T(CASE)
|
|
||||||
|
|
||||||
#undef CASE
|
|
||||||
}
|
|
||||||
|
|
||||||
unreachable ();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
std::ostream&
|
|
||||||
cruft::log::operator<< (std::ostream& os, level_t l)
|
|
||||||
{
|
|
||||||
return os << to_string (l);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
|
||||||
// Determine what the value for LOG_LEVEL should be at the beginning of
|
|
||||||
// execution given the system environment.
|
|
||||||
//
|
|
||||||
// Note that the LOG macros _cannot_ be used from within this function as it
|
|
||||||
// will likely result in infinite recursion.
|
|
||||||
static cruft::log::level_t
|
|
||||||
initial_log_level (void)
|
|
||||||
{
|
|
||||||
const char *env = getenv ("LOG_LEVEL");
|
|
||||||
if (!env)
|
|
||||||
return cruft::log::DEFAULT_LOG_LEVEL;
|
|
||||||
|
|
||||||
try {
|
|
||||||
return cruft::log::to_level (env);
|
|
||||||
} catch (...) {
|
|
||||||
std::clog << "Invalid environment LOG_LEVEL: '" << env << "'\n";
|
|
||||||
return cruft::log::DEFAULT_LOG_LEVEL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
// We shouldn't ever actually get to use the default value, but we set it to
|
|
||||||
// the most verbose option just in case we've made a mistake elsewhere.
|
|
||||||
|
|
||||||
static bool s_log_level_done;
|
|
||||||
static cruft::log::level_t s_log_level_value;
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
cruft::log::level_t
|
|
||||||
cruft::log::log_level (level_t _level)
|
|
||||||
{
|
|
||||||
s_log_level_value = _level;
|
|
||||||
s_log_level_done = true;
|
|
||||||
return s_log_level_value;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
cruft::log::level_t
|
|
||||||
cruft::log::log_level (void)
|
|
||||||
{
|
|
||||||
if (!s_log_level_done) {
|
|
||||||
s_log_level_value = initial_log_level ();
|
|
||||||
s_log_level_done = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return s_log_level_value;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
static bool
|
|
||||||
needs_break (cruft::log::level_t level)
|
|
||||||
{
|
|
||||||
static cruft::log::level_t break_level;
|
|
||||||
static bool has_level = [&] (void) {
|
static bool has_level = [&] (void) {
|
||||||
const char *env = getenv ("BREAK_LEVEL");
|
const char *env = getenv ("BREAK_LEVEL");
|
||||||
if (!env)
|
if (!env)
|
||||||
@ -181,50 +41,12 @@ needs_break (cruft::log::level_t level)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
static
|
cruft::log::sink::base&
|
||||||
cruft::term::csi::graphics
|
cruft::log::default_sink ()
|
||||||
level_colour (cruft::log::level_t level)
|
|
||||||
{
|
{
|
||||||
using cruft::term::csi::graphics;
|
static sink::console s_default_sink (PACKAGE_NAME);
|
||||||
|
return s_default_sink;
|
||||||
switch (level) {
|
|
||||||
case cruft::log::EMERGENCY:
|
|
||||||
case cruft::log::ALERT:
|
|
||||||
case cruft::log::CRITICAL:
|
|
||||||
case cruft::log::ERROR:
|
|
||||||
return graphics (graphics::FOREGROUND, graphics::RED);
|
|
||||||
|
|
||||||
case cruft::log::WARNING:
|
|
||||||
return graphics (graphics::FOREGROUND, graphics::YELLOW);
|
|
||||||
|
|
||||||
case cruft::log::NOTICE:
|
|
||||||
case cruft::log::INFORMATIONAL:
|
|
||||||
return graphics (graphics::FOREGROUND, graphics::GREEN);
|
|
||||||
|
|
||||||
case cruft::log::DEBUG:
|
|
||||||
return graphics (graphics::FOREGROUND, graphics::WHITE);
|
|
||||||
}
|
|
||||||
|
|
||||||
unreachable ();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
static
|
|
||||||
size_t
|
|
||||||
level_width (void)
|
|
||||||
{
|
|
||||||
static size_t width = [] {
|
|
||||||
size_t hi = 0;
|
|
||||||
|
|
||||||
for (auto i: ALL_LEVELS)
|
|
||||||
hi = cruft::max (to_string (i).size (), hi);
|
|
||||||
|
|
||||||
return hi;
|
|
||||||
} ();
|
|
||||||
|
|
||||||
return width;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -248,72 +70,7 @@ cruft::log::write (level_t level, char const *msg)
|
|||||||
void
|
void
|
||||||
cruft::log::write (level_t level, std::string_view msg)
|
cruft::log::write (level_t level, std::string_view msg)
|
||||||
{
|
{
|
||||||
if (level <= log_level ()) {
|
return default_sink ().write (
|
||||||
static const size_t time_len = strlen("YYYY-mm-dd HHMMhSS") + 1;
|
packet (level, msg)
|
||||||
std::string time_string (time_len - 1, '\0');
|
|
||||||
time_t unix_time = time (nullptr);
|
|
||||||
|
|
||||||
if (0 == strftime (&time_string[0],
|
|
||||||
time_len,
|
|
||||||
"%Y-%m-%d %H%Mh%S",
|
|
||||||
localtime (&unix_time))) {
|
|
||||||
warn ("failed to log time");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::clog << time_string << " ["
|
|
||||||
<< level_colour (level)
|
|
||||||
<< std::setw (cruft::cast::lossless<int> (level_width ()))
|
|
||||||
<< std::left
|
|
||||||
<< level
|
|
||||||
<< std::setw (0)
|
|
||||||
<< cruft::term::csi::graphics::RESET
|
|
||||||
<< "] " << msg << std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (needs_break (level))
|
|
||||||
breakpoint ();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
|
||||||
cruft::log::scoped_logger::scoped_logger (
|
|
||||||
level_t _level,
|
|
||||||
std::string _message
|
|
||||||
):
|
|
||||||
m_level (_level),
|
|
||||||
m_message (std::move (_message))
|
|
||||||
{ ; }
|
|
||||||
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
cruft::log::scoped_logger::~scoped_logger ()
|
|
||||||
{
|
|
||||||
write (m_level, m_message);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
|
||||||
cruft::log::scoped_timer::scoped_timer (
|
|
||||||
cruft::log::level_t _level,
|
|
||||||
std::string _message
|
|
||||||
):
|
|
||||||
m_level (_level),
|
|
||||||
m_message (std::move (_message)),
|
|
||||||
m_start (cruft::nanoseconds ())
|
|
||||||
{ ; }
|
|
||||||
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
cruft::log::scoped_timer::~scoped_timer ()
|
|
||||||
{
|
|
||||||
auto finish = cruft::nanoseconds ();
|
|
||||||
auto duration = finish - m_start;
|
|
||||||
|
|
||||||
write (
|
|
||||||
m_level,
|
|
||||||
"%fs, %s",
|
|
||||||
float (duration) / 1'000'000'000.f,
|
|
||||||
m_message
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
109
log/log.hpp
109
log/log.hpp
@ -8,9 +8,11 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "level.hpp"
|
||||||
|
#include "packet.hpp"
|
||||||
|
#include "sink/base.hpp"
|
||||||
#include "../format.hpp"
|
#include "../format.hpp"
|
||||||
|
|
||||||
#include <cruft/util/preprocessor.hpp>
|
|
||||||
|
|
||||||
#include <iosfwd>
|
#include <iosfwd>
|
||||||
#include <string>
|
#include <string>
|
||||||
@ -22,52 +24,8 @@
|
|||||||
|
|
||||||
namespace cruft::log {
|
namespace cruft::log {
|
||||||
///////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////
|
||||||
// rfc5424 log levels. It is assumed they are contiguous to simplify array
|
sink::base& default_sink (void);
|
||||||
// indexing in logging code.
|
|
||||||
enum level_t {
|
|
||||||
EMERGENCY, /** system is unusable */
|
|
||||||
ALERT, /** action must be taken immediately */
|
|
||||||
CRITICAL, /** critical conditions */
|
|
||||||
ERROR, /** error conditions */
|
|
||||||
WARNING,
|
|
||||||
WARN = WARNING, /** warning conditions */
|
|
||||||
NOTICE, /** normal but significant condition */
|
|
||||||
INFORMATIONAL,
|
|
||||||
INFO = INFORMATIONAL, /** informational messages */
|
|
||||||
DEBUG /** debug-level messages */
|
|
||||||
};
|
|
||||||
|
|
||||||
#define MAP_LEVEL_T(F) MAP0(F, EMERGENCY, ALERT, CRITICAL, ERROR, WARN, NOTICE, INFO, DEBUG)
|
|
||||||
|
|
||||||
constexpr auto DEFAULT_LOG_LEVEL = NOTICE;
|
|
||||||
|
|
||||||
//-------------------------------------------------------------------------
|
|
||||||
const std::string& to_string (level_t);
|
|
||||||
level_t to_level (std::string_view);
|
|
||||||
|
|
||||||
//-------------------------------------------------------------------------
|
|
||||||
std::ostream&
|
|
||||||
operator<< (std::ostream&, level_t);
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
// Query or set the global logging level filter. If the severity passed to
|
|
||||||
// a logging call is less than this then the output is discarded.
|
|
||||||
//
|
|
||||||
// The initial logging level can be controlled by setting the environment
|
|
||||||
// variable LOG_LEVEL to a string corresponding to the names of the values
|
|
||||||
// in level_t.
|
|
||||||
//
|
|
||||||
// Otherwise we fall back to the hard coded default from above.
|
|
||||||
//
|
|
||||||
// As a special case, a blank value for the environment variable LOG_LEVEL
|
|
||||||
// corresponds to the maximum log level. It indicates a preference for
|
|
||||||
// minimum output, and may be changed to disable all output in future
|
|
||||||
// updates.
|
|
||||||
level_t log_level (void);
|
|
||||||
level_t log_level (level_t);
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
void write (level_t, std::string const &msg);
|
void write (level_t, std::string const &msg);
|
||||||
void write (level_t, char const *msg);
|
void write (level_t, char const *msg);
|
||||||
void write (level_t, std::string_view msg);
|
void write (level_t, std::string_view msg);
|
||||||
@ -78,30 +36,12 @@ namespace cruft::log {
|
|||||||
void
|
void
|
||||||
write (level_t l, FormatT fmt, ArgsT &&...args)
|
write (level_t l, FormatT fmt, ArgsT &&...args)
|
||||||
{
|
{
|
||||||
write (
|
default_sink ().write (
|
||||||
|
packet (
|
||||||
l,
|
l,
|
||||||
to_string (
|
|
||||||
format::printf (
|
|
||||||
std::forward<FormatT> (fmt),
|
std::forward<FormatT> (fmt),
|
||||||
std::forward<ArgsT> (args)...
|
std::forward<ArgsT> (args)...
|
||||||
)
|
)
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//-------------------------------------------------------------------------
|
|
||||||
template <typename ...Args, size_t N>
|
|
||||||
void
|
|
||||||
write (level_t l, const char (&fmt)[N], Args &&...args)
|
|
||||||
{
|
|
||||||
write (
|
|
||||||
l,
|
|
||||||
to_string (
|
|
||||||
format::printf (fmt) (
|
|
||||||
std::forward<Args> (args)...
|
|
||||||
)
|
|
||||||
)
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -126,41 +66,4 @@ namespace cruft::log {
|
|||||||
#else
|
#else
|
||||||
#define LOG_DEBUG(...) do { ; } while (0)
|
#define LOG_DEBUG(...) do { ; } while (0)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
class scoped_logger {
|
|
||||||
public:
|
|
||||||
scoped_logger (level_t, std::string);
|
|
||||||
~scoped_logger ();
|
|
||||||
|
|
||||||
scoped_logger (scoped_logger const&) = delete;
|
|
||||||
scoped_logger& operator= (scoped_logger const&) = delete;
|
|
||||||
|
|
||||||
scoped_logger (scoped_logger &&) = delete;
|
|
||||||
scoped_logger& operator= (scoped_logger &&) = delete;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
const level_t m_level;
|
|
||||||
const std::string m_message;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
class scoped_timer {
|
|
||||||
public:
|
|
||||||
scoped_timer (level_t, std::string);
|
|
||||||
~scoped_timer ();
|
|
||||||
|
|
||||||
scoped_timer (scoped_timer const&) = delete;
|
|
||||||
scoped_timer& operator= (scoped_timer const&) = delete;
|
|
||||||
|
|
||||||
scoped_timer (scoped_timer &&) = delete;
|
|
||||||
scoped_timer& operator= (scoped_timer &&) = delete;
|
|
||||||
|
|
||||||
private:
|
|
||||||
const level_t m_level;
|
|
||||||
const std::string m_message;
|
|
||||||
uint64_t m_start;
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
0
log/packet.cpp
Normal file
0
log/packet.cpp
Normal file
43
log/packet.hpp
Normal file
43
log/packet.hpp
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "level.hpp"
|
||||||
|
#include "../format.hpp"
|
||||||
|
|
||||||
|
#include <chrono>
|
||||||
|
|
||||||
|
#include <cstddef>
|
||||||
|
|
||||||
|
|
||||||
|
namespace cruft::log {
|
||||||
|
struct packet {
|
||||||
|
using clock = std::chrono::high_resolution_clock;
|
||||||
|
|
||||||
|
packet (level_t _level, std::string _message)
|
||||||
|
: level (_level)
|
||||||
|
, message (std::move (_message))
|
||||||
|
, timestamp (clock::now ())
|
||||||
|
{ ; }
|
||||||
|
|
||||||
|
|
||||||
|
template <typename FormatT, typename ...ArgsT>
|
||||||
|
packet (
|
||||||
|
level_t _level,
|
||||||
|
FormatT _format,
|
||||||
|
ArgsT &&..._args
|
||||||
|
) : packet (
|
||||||
|
_level,
|
||||||
|
cruft::format::to_string (
|
||||||
|
cruft::format::printf (
|
||||||
|
std::forward<FormatT> (_format)
|
||||||
|
) (
|
||||||
|
std::forward<ArgsT> (_args)...
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
{ ; }
|
||||||
|
|
||||||
|
level_t level;
|
||||||
|
std::string message;
|
||||||
|
clock::time_point timestamp;
|
||||||
|
};
|
||||||
|
}
|
57
log/scoped.cpp
Normal file
57
log/scoped.cpp
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
/*
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
*
|
||||||
|
* Copyright 2012-2019 Danny Robson <danny@nerdcruft.net>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "scoped.hpp"
|
||||||
|
|
||||||
|
#include "../time.hpp"
|
||||||
|
|
||||||
|
using cruft::log::scoped_logger;
|
||||||
|
using cruft::log::scoped_timer;
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
cruft::log::scoped_logger::scoped_logger (
|
||||||
|
level_t _level,
|
||||||
|
std::string _message
|
||||||
|
):
|
||||||
|
m_level (_level),
|
||||||
|
m_message (std::move (_message))
|
||||||
|
{ ; }
|
||||||
|
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
cruft::log::scoped_logger::~scoped_logger ()
|
||||||
|
{
|
||||||
|
write (m_level, m_message);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
cruft::log::scoped_timer::scoped_timer (
|
||||||
|
cruft::log::level_t _level,
|
||||||
|
std::string _message
|
||||||
|
):
|
||||||
|
m_level (_level),
|
||||||
|
m_message (std::move (_message)),
|
||||||
|
m_start (cruft::nanoseconds ())
|
||||||
|
{ ; }
|
||||||
|
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
cruft::log::scoped_timer::~scoped_timer ()
|
||||||
|
{
|
||||||
|
auto finish = cruft::nanoseconds ();
|
||||||
|
auto duration = finish - m_start;
|
||||||
|
|
||||||
|
write (
|
||||||
|
m_level,
|
||||||
|
"%fs, %s",
|
||||||
|
float (duration) / 1'000'000'000.f,
|
||||||
|
m_message
|
||||||
|
);
|
||||||
|
}
|
52
log/scoped.hpp
Normal file
52
log/scoped.hpp
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
/*
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
*
|
||||||
|
* Copyright 2012-2019 Danny Robson <danny@nerdcruft.net>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "log.hpp"
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
namespace cruft::log {
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
class scoped_logger {
|
||||||
|
public:
|
||||||
|
scoped_logger (level_t, std::string);
|
||||||
|
~scoped_logger ();
|
||||||
|
|
||||||
|
scoped_logger (scoped_logger const&) = delete;
|
||||||
|
scoped_logger& operator= (scoped_logger const&) = delete;
|
||||||
|
|
||||||
|
scoped_logger (scoped_logger &&) = delete;
|
||||||
|
scoped_logger& operator= (scoped_logger &&) = delete;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
const level_t m_level;
|
||||||
|
const std::string m_message;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
class scoped_timer {
|
||||||
|
public:
|
||||||
|
scoped_timer (level_t, std::string);
|
||||||
|
~scoped_timer ();
|
||||||
|
|
||||||
|
scoped_timer (scoped_timer const&) = delete;
|
||||||
|
scoped_timer& operator= (scoped_timer const&) = delete;
|
||||||
|
|
||||||
|
scoped_timer (scoped_timer &&) = delete;
|
||||||
|
scoped_timer& operator= (scoped_timer &&) = delete;
|
||||||
|
|
||||||
|
private:
|
||||||
|
const level_t m_level;
|
||||||
|
const std::string m_message;
|
||||||
|
uint64_t m_start;
|
||||||
|
};
|
||||||
|
}
|
9
log/sink/base.cpp
Normal file
9
log/sink/base.cpp
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
#include "base.hpp"
|
||||||
|
|
||||||
|
using cruft::log::sink::base;
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
base::base (std::string _name)
|
||||||
|
: m_name (std::move (_name))
|
||||||
|
{ ; }
|
32
log/sink/base.hpp
Normal file
32
log/sink/base.hpp
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "../fwd.hpp"
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
|
||||||
|
namespace cruft::log::sink {
|
||||||
|
class base {
|
||||||
|
public:
|
||||||
|
virtual ~base () = default;
|
||||||
|
|
||||||
|
base (std::string name);
|
||||||
|
|
||||||
|
std::string const& name (void);
|
||||||
|
|
||||||
|
virtual void write (packet const&) = 0;
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string m_name;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
template <typename DerivedT>
|
||||||
|
class crtp : public base {
|
||||||
|
public:
|
||||||
|
template <typename ...ArgsT>
|
||||||
|
crtp (ArgsT &&...args)
|
||||||
|
: base (std::forward<ArgsT> (args)...)
|
||||||
|
{ ; }
|
||||||
|
};
|
||||||
|
}
|
122
log/sink/console.cpp
Normal file
122
log/sink/console.cpp
Normal file
@ -0,0 +1,122 @@
|
|||||||
|
/*
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
*
|
||||||
|
* Copyright 2019, Danny Robson <danny@nerdcruft.net>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "console.hpp"
|
||||||
|
|
||||||
|
#include "../level.hpp"
|
||||||
|
#include "../packet.hpp"
|
||||||
|
|
||||||
|
#include "../../term.hpp"
|
||||||
|
#include "../../debug/assert.hpp"
|
||||||
|
#include "../../cast.hpp"
|
||||||
|
|
||||||
|
#include <iomanip>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
#include <ctime>
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
|
using cruft::log::sink::console;
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
static std::size_t
|
||||||
|
level_width (void)
|
||||||
|
{
|
||||||
|
static constexpr
|
||||||
|
cruft::log::level_t
|
||||||
|
ALL_LEVELS[] = {
|
||||||
|
cruft::log::EMERGENCY,
|
||||||
|
cruft::log::ALERT,
|
||||||
|
cruft::log::CRITICAL,
|
||||||
|
cruft::log::ERROR,
|
||||||
|
cruft::log::WARN,
|
||||||
|
cruft::log::NOTICE,
|
||||||
|
cruft::log::INFO,
|
||||||
|
cruft::log::DEBUG,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
static size_t width = [] {
|
||||||
|
size_t hi = 0;
|
||||||
|
|
||||||
|
for (auto i: ALL_LEVELS)
|
||||||
|
hi = cruft::max (to_string (i).size (), hi);
|
||||||
|
|
||||||
|
return hi;
|
||||||
|
} ();
|
||||||
|
|
||||||
|
return width;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
static
|
||||||
|
cruft::term::csi::graphics
|
||||||
|
level_colour (cruft::log::level_t level)
|
||||||
|
{
|
||||||
|
using cruft::term::csi::graphics;
|
||||||
|
|
||||||
|
switch (level) {
|
||||||
|
case cruft::log::EMERGENCY:
|
||||||
|
case cruft::log::ALERT:
|
||||||
|
case cruft::log::CRITICAL:
|
||||||
|
case cruft::log::ERROR:
|
||||||
|
return graphics (graphics::FOREGROUND, graphics::RED);
|
||||||
|
|
||||||
|
case cruft::log::WARNING:
|
||||||
|
return graphics (graphics::FOREGROUND, graphics::YELLOW);
|
||||||
|
|
||||||
|
case cruft::log::NOTICE:
|
||||||
|
case cruft::log::INFORMATIONAL:
|
||||||
|
return graphics (graphics::FOREGROUND, graphics::GREEN);
|
||||||
|
|
||||||
|
case cruft::log::DEBUG:
|
||||||
|
return graphics (graphics::FOREGROUND, graphics::WHITE);
|
||||||
|
}
|
||||||
|
|
||||||
|
unreachable ();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
console::console (std::string name)
|
||||||
|
: crtp (std::move (name))
|
||||||
|
{ ; }
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
void
|
||||||
|
console::write (packet const &val)
|
||||||
|
{
|
||||||
|
if (val.level <= log_level ()) {
|
||||||
|
static const size_t time_len = strlen("YYYY-mm-dd HHMMhSS") + 1;
|
||||||
|
std::string time_string (time_len - 1, '\0');
|
||||||
|
time_t unix_time = time (nullptr);
|
||||||
|
|
||||||
|
if (0 == strftime (&time_string[0],
|
||||||
|
time_len,
|
||||||
|
"%Y-%m-%d %H%Mh%S",
|
||||||
|
localtime (&unix_time))) {
|
||||||
|
warn ("failed to log time");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::clog << time_string << " ["
|
||||||
|
<< level_colour (val.level)
|
||||||
|
<< std::setw (cruft::cast::lossless<int> (level_width ()))
|
||||||
|
<< std::left
|
||||||
|
<< val.level
|
||||||
|
<< std::setw (0)
|
||||||
|
<< cruft::term::csi::graphics::RESET
|
||||||
|
<< "] " << val.message << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (needs_break (val.level))
|
||||||
|
breakpoint ();
|
||||||
|
}
|
22
log/sink/console.hpp
Normal file
22
log/sink/console.hpp
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
/*
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
*
|
||||||
|
* Copyright 2019, Danny Robson <danny@nerdcruft.net>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "base.hpp"
|
||||||
|
|
||||||
|
#include "ostream.hpp"
|
||||||
|
|
||||||
|
namespace cruft::log::sink {
|
||||||
|
class console : public crtp<console> {
|
||||||
|
public:
|
||||||
|
console (std::string name);
|
||||||
|
|
||||||
|
virtual void write (packet const&);
|
||||||
|
};
|
||||||
|
}
|
0
log/sink/null.cpp
Normal file
0
log/sink/null.cpp
Normal file
0
log/sink/null.hpp
Normal file
0
log/sink/null.hpp
Normal file
0
log/sink/ostream.cpp
Normal file
0
log/sink/ostream.cpp
Normal file
0
log/sink/ostream.hpp
Normal file
0
log/sink/ostream.hpp
Normal file
0
log/sink/tee.cpp
Normal file
0
log/sink/tee.cpp
Normal file
0
log/sink/tee.hpp
Normal file
0
log/sink/tee.hpp
Normal file
@ -8,7 +8,7 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "log.hpp"
|
#include "log/log.hpp"
|
||||||
#include "introspection.hpp"
|
#include "introspection.hpp"
|
||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
|
Loading…
Reference in New Issue
Block a user