log: modularise the logging infrastructure

This commit is contained in:
Danny Robson 2019-10-10 15:52:37 +11:00
parent 2e16e8962b
commit 67ea686753
21 changed files with 610 additions and 363 deletions

View File

@ -423,8 +423,22 @@ list (
list/sort.hpp
log.hpp
log/fwd.hpp
log/log.hpp
log/level.cpp
log/level.hpp
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.hpp
maths.cpp

22
log/fwd.hpp Normal file
View 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
View 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
View 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);
}

View File

@ -9,161 +9,21 @@
#include "log.hpp"
#include "../term.hpp"
#include "../time.hpp"
#include "../cast.hpp"
#include "../string.hpp"
#include <cstring>
#include <ctime>
#include <iomanip>
#include <iostream>
#include "sink/console.hpp"
#include <map>
#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.
///
/// conversion is case insensitive
/// throws std::range_error if unable to convert
cruft::log::level_t
cruft::log::to_level (std::string_view name)
bool
cruft::log::needs_break (level_t level)
{
if (std::empty (name))
return cruft::log::EMERGENCY;
static level_t break_level;
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) {
const char *env = getenv ("BREAK_LEVEL");
if (!env)
@ -181,50 +41,12 @@ needs_break (cruft::log::level_t level)
}
//-----------------------------------------------------------------------------
static
cruft::term::csi::graphics
level_colour (cruft::log::level_t level)
///////////////////////////////////////////////////////////////////////////////
cruft::log::sink::base&
cruft::log::default_sink ()
{
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 ();
}
//-----------------------------------------------------------------------------
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;
static sink::console s_default_sink (PACKAGE_NAME);
return s_default_sink;
}
@ -248,72 +70,7 @@ cruft::log::write (level_t level, char const *msg)
void
cruft::log::write (level_t level, std::string_view msg)
{
if (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 (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
return default_sink ().write (
packet (level, msg)
);
}

View File

@ -8,9 +8,11 @@
#pragma once
#include "level.hpp"
#include "packet.hpp"
#include "sink/base.hpp"
#include "../format.hpp"
#include <cruft/util/preprocessor.hpp>
#include <iosfwd>
#include <string>
@ -22,52 +24,8 @@
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 */
};
sink::base& default_sink (void);
#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, char const *msg);
void write (level_t, std::string_view msg);
@ -78,29 +36,11 @@ namespace cruft::log {
void
write (level_t l, FormatT fmt, ArgsT &&...args)
{
write (
l,
to_string (
format::printf (
std::forward<FormatT> (fmt),
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)...
)
default_sink ().write (
packet (
l,
std::forward<FormatT> (fmt),
std::forward<ArgsT> (args)...
)
);
}
@ -126,41 +66,4 @@ namespace cruft::log {
#else
#define LOG_DEBUG(...) do { ; } while (0)
#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
View File

43
log/packet.hpp Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View File

0
log/sink/null.hpp Normal file
View File

0
log/sink/ostream.cpp Normal file
View File

0
log/sink/ostream.hpp Normal file
View File

0
log/sink/tee.cpp Normal file
View File

0
log/sink/tee.hpp Normal file
View File

View File

@ -8,7 +8,7 @@
#pragma once
#include "log.hpp"
#include "log/log.hpp"
#include "introspection.hpp"
#include <map>