Squashed 'vendor/spdlog/' content from commit 47c17be

git-subtree-dir: vendor/spdlog
git-subtree-split: 47c17be9a111ab20123e1bd8e6c6717aa2adfea2
This commit is contained in:
2017-11-02 12:46:32 +10:00
commit a4163d8b1b
104 changed files with 24050 additions and 0 deletions

View File

@@ -0,0 +1,90 @@
//
// Copyright(c) 2015 Gabi Melman.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
//
#pragma once
#if defined(__ANDROID__)
#include "spdlog/sinks/sink.h"
#include <mutex>
#include <string>
#include <android/log.h>
#include <thread>
#include <chrono>
#if !defined(SPDLOG_ANDROID_RETRIES)
#define SPDLOG_ANDROID_RETRIES 2
#endif
namespace spdlog
{
namespace sinks
{
/*
* Android sink (logging using __android_log_write)
* __android_log_write is thread-safe. No lock is needed.
*/
class android_sink : public sink
{
public:
explicit android_sink(const std::string& tag = "spdlog", bool use_raw_msg = false): _tag(tag), _use_raw_msg(use_raw_msg) {}
void log(const details::log_msg& msg) override
{
const android_LogPriority priority = convert_to_android(msg.level);
const char *msg_output = (_use_raw_msg ? msg.raw.c_str() : msg.formatted.c_str());
// See system/core/liblog/logger_write.c for explanation of return value
int ret = __android_log_write(priority, _tag.c_str(), msg_output);
int retry_count = 0;
while ((ret == -11/*EAGAIN*/) && (retry_count < SPDLOG_ANDROID_RETRIES))
{
std::this_thread::sleep_for(std::chrono::milliseconds(5));
ret = __android_log_write(priority, _tag.c_str(), msg_output);
retry_count++;
}
if (ret < 0)
{
throw spdlog_ex("__android_log_write() failed", ret);
}
}
void flush() override
{
}
private:
static android_LogPriority convert_to_android(spdlog::level::level_enum level)
{
switch(level)
{
case spdlog::level::trace:
return ANDROID_LOG_VERBOSE;
case spdlog::level::debug:
return ANDROID_LOG_DEBUG;
case spdlog::level::info:
return ANDROID_LOG_INFO;
case spdlog::level::warn:
return ANDROID_LOG_WARN;
case spdlog::level::err:
return ANDROID_LOG_ERROR;
case spdlog::level::critical:
return ANDROID_LOG_FATAL;
default:
return ANDROID_LOG_DEFAULT;
}
}
std::string _tag;
bool _use_raw_msg;
};
}
}
#endif

View File

@@ -0,0 +1,133 @@
//
// Copyright(c) 2017 spdlog authors.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
//
#pragma once
#include "spdlog/sinks/base_sink.h"
#include "spdlog/common.h"
#include "spdlog/details/os.h"
#include <string>
#include <map>
namespace spdlog
{
namespace sinks
{
/**
* This sink prefixes the output with an ANSI escape sequence color code depending on the severity
* of the message.
* If no color terminal detected, omit the escape codes.
*/
template <class Mutex>
class ansicolor_sink: public base_sink<Mutex>
{
public:
ansicolor_sink(FILE* file): target_file_(file)
{
should_do_colors_ = details::os::in_terminal(file) && details::os::is_color_terminal();
colors_[level::trace] = cyan;
colors_[level::debug] = cyan;
colors_[level::info] = reset;
colors_[level::warn] = yellow + bold;
colors_[level::err] = red + bold;
colors_[level::critical] = bold + on_red;
colors_[level::off] = reset;
}
virtual ~ansicolor_sink()
{
_flush();
}
void set_color(level::level_enum color_level, const std::string& color)
{
std::lock_guard<Mutex> lock(base_sink<Mutex>::_mutex);
colors_[color_level] = color;
}
/// Formatting codes
const std::string reset = "\033[00m";
const std::string bold = "\033[1m";
const std::string dark = "\033[2m";
const std::string underline = "\033[4m";
const std::string blink = "\033[5m";
const std::string reverse = "\033[7m";
const std::string concealed = "\033[8m";
// Foreground colors
const std::string grey = "\033[30m";
const std::string red = "\033[31m";
const std::string green = "\033[32m";
const std::string yellow = "\033[33m";
const std::string blue = "\033[34m";
const std::string magenta = "\033[35m";
const std::string cyan = "\033[36m";
const std::string white = "\033[37m";
/// Background colors
const std::string on_grey = "\033[40m";
const std::string on_red = "\033[41m";
const std::string on_green = "\033[42m";
const std::string on_yellow = "\033[43m";
const std::string on_blue = "\033[44m";
const std::string on_magenta = "\033[45m";
const std::string on_cyan = "\033[46m";
const std::string on_white = "\033[47m";
protected:
virtual void _sink_it(const details::log_msg& msg) override
{
// Wrap the originally formatted message in color codes.
// If color is not supported in the terminal, log as is instead.
if (should_do_colors_)
{
const std::string& prefix = colors_[msg.level];
fwrite(prefix.data(), sizeof(char), prefix.size(), target_file_);
fwrite(msg.formatted.data(), sizeof(char), msg.formatted.size(), target_file_);
fwrite(reset.data(), sizeof(char), reset.size(), target_file_);
}
else
{
fwrite(msg.formatted.data(), sizeof(char), msg.formatted.size(), target_file_);
}
_flush();
}
void _flush() override
{
fflush(target_file_);
}
FILE* target_file_;
bool should_do_colors_;
std::map<level::level_enum, std::string> colors_;
};
template<class Mutex>
class ansicolor_stdout_sink: public ansicolor_sink<Mutex>
{
public:
ansicolor_stdout_sink(): ansicolor_sink<Mutex>(stdout)
{}
};
template<class Mutex>
class ansicolor_stderr_sink: public ansicolor_sink<Mutex>
{
public:
ansicolor_stderr_sink(): ansicolor_sink<Mutex>(stderr)
{}
};
typedef ansicolor_stdout_sink<std::mutex> ansicolor_stdout_sink_mt;
typedef ansicolor_stdout_sink<details::null_mutex> ansicolor_stdout_sink_st;
typedef ansicolor_stderr_sink<std::mutex> ansicolor_stderr_sink_mt;
typedef ansicolor_stderr_sink<details::null_mutex> ansicolor_stderr_sink_st;
} // namespace sinks
} // namespace spdlog

View File

@@ -0,0 +1,50 @@
//
// Copyright(c) 2015 Gabi Melman.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
//
#pragma once
//
// base sink templated over a mutex (either dummy or real)
// concrete implementation should only override the _sink_it method.
// all locking is taken care of here so no locking needed by the implementers..
//
#include "spdlog/sinks/sink.h"
#include "spdlog/formatter.h"
#include "spdlog/common.h"
#include "spdlog/details/log_msg.h"
#include <mutex>
namespace spdlog
{
namespace sinks
{
template<class Mutex>
class base_sink:public sink
{
public:
base_sink():_mutex() {}
virtual ~base_sink() = default;
base_sink(const base_sink&) = delete;
base_sink& operator=(const base_sink&) = delete;
void log(const details::log_msg& msg) SPDLOG_FINAL override
{
std::lock_guard<Mutex> lock(_mutex);
_sink_it(msg);
}
void flush() SPDLOG_FINAL override
{
_flush();
}
protected:
virtual void _sink_it(const details::log_msg& msg) = 0;
virtual void _flush() = 0;
Mutex _mutex;
};
}
}

View File

@@ -0,0 +1,73 @@
//
// Copyright (c) 2015 David Schury, Gabi Melman
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
//
#pragma once
#include "spdlog/details/log_msg.h"
#include "spdlog/details/null_mutex.h"
#include "spdlog/sinks/base_sink.h"
#include "spdlog/sinks/sink.h"
#include <algorithm>
#include <mutex>
#include <memory>
#include <vector>
// Distribution sink (mux). Stores a vector of sinks which get called when log is called
namespace spdlog
{
namespace sinks
{
template<class Mutex>
class dist_sink: public base_sink<Mutex>
{
public:
explicit dist_sink() :_sinks() {}
dist_sink(const dist_sink&) = delete;
dist_sink& operator=(const dist_sink&) = delete;
virtual ~dist_sink() = default;
protected:
std::vector<std::shared_ptr<sink>> _sinks;
void _sink_it(const details::log_msg& msg) override
{
for (auto &sink : _sinks)
{
if( sink->should_log( msg.level))
{
sink->log(msg);
}
}
}
void _flush() override
{
std::lock_guard<Mutex> lock(base_sink<Mutex>::_mutex);
for (auto &sink : _sinks)
sink->flush();
}
public:
void add_sink(std::shared_ptr<sink> sink)
{
std::lock_guard<Mutex> lock(base_sink<Mutex>::_mutex);
_sinks.push_back(sink);
}
void remove_sink(std::shared_ptr<sink> sink)
{
std::lock_guard<Mutex> lock(base_sink<Mutex>::_mutex);
_sinks.erase(std::remove(_sinks.begin(), _sinks.end(), sink), _sinks.end());
}
};
typedef dist_sink<std::mutex> dist_sink_mt;
typedef dist_sink<details::null_mutex> dist_sink_st;
}
}

View File

@@ -0,0 +1,242 @@
//
// Copyright(c) 2015 Gabi Melman.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
//
#pragma once
#include "spdlog/sinks/base_sink.h"
#include "spdlog/details/null_mutex.h"
#include "spdlog/details/file_helper.h"
#include "spdlog/fmt/fmt.h"
#include <algorithm>
#include <chrono>
#include <cstdio>
#include <ctime>
#include <mutex>
#include <string>
#include <cerrno>
namespace spdlog
{
namespace sinks
{
/*
* Trivial file sink with single file as target
*/
template<class Mutex>
class simple_file_sink SPDLOG_FINAL : public base_sink < Mutex >
{
public:
explicit simple_file_sink(const filename_t &filename, bool truncate = false):_force_flush(false)
{
_file_helper.open(filename, truncate);
}
void set_force_flush(bool force_flush)
{
_force_flush = force_flush;
}
protected:
void _sink_it(const details::log_msg& msg) override
{
_file_helper.write(msg);
if(_force_flush)
_file_helper.flush();
}
void _flush() override
{
_file_helper.flush();
}
private:
details::file_helper _file_helper;
bool _force_flush;
};
typedef simple_file_sink<std::mutex> simple_file_sink_mt;
typedef simple_file_sink<details::null_mutex> simple_file_sink_st;
/*
* Rotating file sink based on size
*/
template<class Mutex>
class rotating_file_sink SPDLOG_FINAL : public base_sink < Mutex >
{
public:
rotating_file_sink(const filename_t &base_filename,
std::size_t max_size, std::size_t max_files) :
_base_filename(base_filename),
_max_size(max_size),
_max_files(max_files),
_current_size(0),
_file_helper()
{
_file_helper.open(calc_filename(_base_filename, 0));
_current_size = _file_helper.size(); //expensive. called only once
}
protected:
void _sink_it(const details::log_msg& msg) override
{
_current_size += msg.formatted.size();
if (_current_size > _max_size)
{
_rotate();
_current_size = msg.formatted.size();
}
_file_helper.write(msg);
}
void _flush() override
{
_file_helper.flush();
}
private:
static filename_t calc_filename(const filename_t& filename, std::size_t index)
{
std::conditional<std::is_same<filename_t::value_type, char>::value, fmt::MemoryWriter, fmt::WMemoryWriter>::type w;
if (index)
w.write(SPDLOG_FILENAME_T("{}.{}"), filename, index);
else
w.write(SPDLOG_FILENAME_T("{}"), filename);
return w.str();
}
// Rotate files:
// log.txt -> log.txt.1
// log.txt.1 -> log.txt.2
// log.txt.2 -> log.txt.3
// lo3.txt.3 -> delete
void _rotate()
{
using details::os::filename_to_str;
_file_helper.close();
for (auto i = _max_files; i > 0; --i)
{
filename_t src = calc_filename(_base_filename, i - 1);
filename_t target = calc_filename(_base_filename, i);
if (details::file_helper::file_exists(target))
{
if (details::os::remove(target) != 0)
{
throw spdlog_ex("rotating_file_sink: failed removing " + filename_to_str(target), errno);
}
}
if (details::file_helper::file_exists(src) && details::os::rename(src, target))
{
throw spdlog_ex("rotating_file_sink: failed renaming " + filename_to_str(src) + " to " + filename_to_str(target), errno);
}
}
_file_helper.reopen(true);
}
filename_t _base_filename;
std::size_t _max_size;
std::size_t _max_files;
std::size_t _current_size;
details::file_helper _file_helper;
};
typedef rotating_file_sink<std::mutex> rotating_file_sink_mt;
typedef rotating_file_sink<details::null_mutex>rotating_file_sink_st;
/*
* Default generator of daily log file names.
*/
struct default_daily_file_name_calculator
{
// Create filename for the form basename.YYYY-MM-DD_hh-mm
static filename_t calc_filename(const filename_t& basename)
{
std::tm tm = spdlog::details::os::localtime();
std::conditional<std::is_same<filename_t::value_type, char>::value, fmt::MemoryWriter, fmt::WMemoryWriter>::type w;
w.write(SPDLOG_FILENAME_T("{}_{:04d}-{:02d}-{:02d}_{:02d}-{:02d}"), basename, tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min);
return w.str();
}
};
/*
* Generator of daily log file names in format basename.YYYY-MM-DD
*/
struct dateonly_daily_file_name_calculator
{
// Create filename for the form basename.YYYY-MM-DD
static filename_t calc_filename(const filename_t& basename)
{
std::tm tm = spdlog::details::os::localtime();
std::conditional<std::is_same<filename_t::value_type, char>::value, fmt::MemoryWriter, fmt::WMemoryWriter>::type w;
w.write(SPDLOG_FILENAME_T("{}_{:04d}-{:02d}-{:02d}"), basename, tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday);
return w.str();
}
};
/*
* Rotating file sink based on date. rotates at midnight
*/
template<class Mutex, class FileNameCalc = default_daily_file_name_calculator>
class daily_file_sink SPDLOG_FINAL :public base_sink < Mutex >
{
public:
//create daily file sink which rotates on given time
daily_file_sink(
const filename_t& base_filename,
int rotation_hour,
int rotation_minute) : _base_filename(base_filename),
_rotation_h(rotation_hour),
_rotation_m(rotation_minute)
{
if (rotation_hour < 0 || rotation_hour > 23 || rotation_minute < 0 || rotation_minute > 59)
throw spdlog_ex("daily_file_sink: Invalid rotation time in ctor");
_rotation_tp = _next_rotation_tp();
_file_helper.open(FileNameCalc::calc_filename(_base_filename));
}
protected:
void _sink_it(const details::log_msg& msg) override
{
if (std::chrono::system_clock::now() >= _rotation_tp)
{
_file_helper.open(FileNameCalc::calc_filename(_base_filename));
_rotation_tp = _next_rotation_tp();
}
_file_helper.write(msg);
}
void _flush() override
{
_file_helper.flush();
}
private:
std::chrono::system_clock::time_point _next_rotation_tp()
{
auto now = std::chrono::system_clock::now();
time_t tnow = std::chrono::system_clock::to_time_t(now);
tm date = spdlog::details::os::localtime(tnow);
date.tm_hour = _rotation_h;
date.tm_min = _rotation_m;
date.tm_sec = 0;
auto rotation_time = std::chrono::system_clock::from_time_t(std::mktime(&date));
if (rotation_time > now)
return rotation_time;
else
return std::chrono::system_clock::time_point(rotation_time + std::chrono::hours(24));
}
filename_t _base_filename;
int _rotation_h;
int _rotation_m;
std::chrono::system_clock::time_point _rotation_tp;
details::file_helper _file_helper;
};
typedef daily_file_sink<std::mutex> daily_file_sink_mt;
typedef daily_file_sink<details::null_mutex> daily_file_sink_st;
}
}

View File

@@ -0,0 +1,51 @@
//
// Copyright(c) 2016 Alexander Dalshov.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
//
#pragma once
#if defined(_MSC_VER)
#include "spdlog/sinks/base_sink.h"
#include "spdlog/details/null_mutex.h"
#include <WinBase.h>
#include <mutex>
#include <string>
namespace spdlog
{
namespace sinks
{
/*
* MSVC sink (logging using OutputDebugStringA)
*/
template<class Mutex>
class msvc_sink : public base_sink < Mutex >
{
public:
explicit msvc_sink()
{
}
protected:
void _sink_it(const details::log_msg& msg) override
{
OutputDebugStringA(msg.formatted.c_str());
}
void _flush() override
{}
};
typedef msvc_sink<std::mutex> msvc_sink_mt;
typedef msvc_sink<details::null_mutex> msvc_sink_st;
}
}
#endif

View File

@@ -0,0 +1,34 @@
//
// Copyright(c) 2015 Gabi Melman.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
//
#pragma once
#include "spdlog/sinks/base_sink.h"
#include "spdlog/details/null_mutex.h"
#include <mutex>
namespace spdlog
{
namespace sinks
{
template <class Mutex>
class null_sink : public base_sink < Mutex >
{
protected:
void _sink_it(const details::log_msg&) override
{}
void _flush() override
{}
};
typedef null_sink<details::null_mutex> null_sink_st;
typedef null_sink<details::null_mutex> null_sink_mt;
}
}

View File

@@ -0,0 +1,47 @@
//
// Copyright(c) 2015 Gabi Melman.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
//
#pragma once
#include "spdlog/details/null_mutex.h"
#include "spdlog/sinks/base_sink.h"
#include <ostream>
#include <mutex>
namespace spdlog
{
namespace sinks
{
template<class Mutex>
class ostream_sink: public base_sink<Mutex>
{
public:
explicit ostream_sink(std::ostream& os, bool force_flush=false) :_ostream(os), _force_flush(force_flush) {}
ostream_sink(const ostream_sink&) = delete;
ostream_sink& operator=(const ostream_sink&) = delete;
virtual ~ostream_sink() = default;
protected:
void _sink_it(const details::log_msg& msg) override
{
_ostream.write(msg.formatted.data(), msg.formatted.size());
if (_force_flush)
_ostream.flush();
}
void _flush() override
{
_ostream.flush();
}
std::ostream& _ostream;
bool _force_flush;
};
typedef ostream_sink<std::mutex> ostream_sink_mt;
typedef ostream_sink<details::null_mutex> ostream_sink_st;
}
}

View File

@@ -0,0 +1,53 @@
//
// Copyright(c) 2015 Gabi Melman.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
//
#pragma once
#include "spdlog/details/log_msg.h"
namespace spdlog
{
namespace sinks
{
class sink
{
public:
sink()
{
_level = level::trace;
}
virtual ~sink() {}
virtual void log(const details::log_msg& msg) = 0;
virtual void flush() = 0;
bool should_log(level::level_enum msg_level) const;
void set_level(level::level_enum log_level);
level::level_enum level() const;
private:
level_t _level;
};
inline bool sink::should_log(level::level_enum msg_level) const
{
return msg_level >= _level.load(std::memory_order_relaxed);
}
inline void sink::set_level(level::level_enum log_level)
{
_level.store(log_level);
}
inline level::level_enum sink::level() const
{
return static_cast<spdlog::level::level_enum>(_level.load(std::memory_order_relaxed));
}
}
}

View File

@@ -0,0 +1,77 @@
//
// Copyright(c) 2015 Gabi Melman.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
//
#pragma once
#include "spdlog/details/null_mutex.h"
#include "spdlog/sinks/base_sink.h"
#include <cstdio>
#include <memory>
#include <mutex>
namespace spdlog
{
namespace sinks
{
template <class Mutex>
class stdout_sink SPDLOG_FINAL : public base_sink<Mutex>
{
using MyType = stdout_sink<Mutex>;
public:
stdout_sink()
{}
static std::shared_ptr<MyType> instance()
{
static std::shared_ptr<MyType> instance = std::make_shared<MyType>();
return instance;
}
protected:
void _sink_it(const details::log_msg& msg) override
{
fwrite(msg.formatted.data(), sizeof(char), msg.formatted.size(), stdout);
_flush();
}
void _flush() override
{
fflush(stdout);
}
};
typedef stdout_sink<details::null_mutex> stdout_sink_st;
typedef stdout_sink<std::mutex> stdout_sink_mt;
template <class Mutex>
class stderr_sink SPDLOG_FINAL : public base_sink<Mutex>
{
using MyType = stderr_sink<Mutex>;
public:
stderr_sink()
{}
static std::shared_ptr<MyType> instance()
{
static std::shared_ptr<MyType> instance = std::make_shared<MyType>();
return instance;
}
protected:
void _sink_it(const details::log_msg& msg) override
{
fwrite(msg.formatted.data(), sizeof(char), msg.formatted.size(), stderr);
_flush();
}
void _flush() override
{
fflush(stderr);
}
};
typedef stderr_sink<std::mutex> stderr_sink_mt;
typedef stderr_sink<details::null_mutex> stderr_sink_st;
}
}

View File

@@ -0,0 +1,81 @@
//
// Copyright(c) 2015 Gabi Melman.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
//
#pragma once
#include "spdlog/common.h"
#ifdef SPDLOG_ENABLE_SYSLOG
#include "spdlog/sinks/sink.h"
#include "spdlog/details/log_msg.h"
#include <array>
#include <string>
#include <syslog.h>
namespace spdlog
{
namespace sinks
{
/**
* Sink that write to syslog using the `syscall()` library call.
*
* Locking is not needed, as `syslog()` itself is thread-safe.
*/
class syslog_sink : public sink
{
public:
//
syslog_sink(const std::string& ident = "", int syslog_option=0, int syslog_facility=LOG_USER):
_ident(ident)
{
_priorities[static_cast<int>(level::trace)] = LOG_DEBUG;
_priorities[static_cast<int>(level::debug)] = LOG_DEBUG;
_priorities[static_cast<int>(level::info)] = LOG_INFO;
_priorities[static_cast<int>(level::warn)] = LOG_WARNING;
_priorities[static_cast<int>(level::err)] = LOG_ERR;
_priorities[static_cast<int>(level::critical)] = LOG_CRIT;
_priorities[static_cast<int>(level::off)] = LOG_INFO;
//set ident to be program name if empty
::openlog(_ident.empty()? nullptr:_ident.c_str(), syslog_option, syslog_facility);
}
~syslog_sink()
{
::closelog();
}
syslog_sink(const syslog_sink&) = delete;
syslog_sink& operator=(const syslog_sink&) = delete;
void log(const details::log_msg &msg) override
{
::syslog(syslog_prio_from_level(msg), "%s", msg.raw.str().c_str());
}
void flush() override
{
}
private:
std::array<int, 7> _priorities;
//must store the ident because the man says openlog might use the pointer as is and not a string copy
const std::string _ident;
//
// Simply maps spdlog's log level to syslog priority level.
//
int syslog_prio_from_level(const details::log_msg &msg) const
{
return _priorities[static_cast<int>(msg.level)];
}
};
}
}
#endif

View File

@@ -0,0 +1,121 @@
//
// Copyright(c) 2016 spdlog
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
//
#pragma once
#include "spdlog/sinks/base_sink.h"
#include "spdlog/details/null_mutex.h"
#include "spdlog/common.h"
#include <mutex>
#include <string>
#include <map>
#include <wincon.h>
namespace spdlog
{
namespace sinks
{
/*
* Windows color console sink. Uses WriteConsoleA to write to the console with colors
*/
template<class Mutex>
class wincolor_sink: public base_sink<Mutex>
{
public:
const WORD BOLD = FOREGROUND_INTENSITY;
const WORD RED = FOREGROUND_RED;
const WORD CYAN = FOREGROUND_GREEN | FOREGROUND_BLUE;
const WORD WHITE = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE;
const WORD YELLOW = FOREGROUND_RED | FOREGROUND_GREEN;
wincolor_sink(HANDLE std_handle): out_handle_(std_handle)
{
colors_[level::trace] = CYAN;
colors_[level::debug] = CYAN;
colors_[level::info] = WHITE | BOLD;
colors_[level::warn] = YELLOW | BOLD;
colors_[level::err] = RED | BOLD; // red bold
colors_[level::critical] = BACKGROUND_RED | WHITE | BOLD; // white bold on red background
colors_[level::off] = 0;
}
virtual ~wincolor_sink()
{
this->flush();
}
wincolor_sink(const wincolor_sink& other) = delete;
wincolor_sink& operator=(const wincolor_sink& other) = delete;
protected:
virtual void _sink_it(const details::log_msg& msg) override
{
auto color = colors_[msg.level];
auto orig_attribs = set_console_attribs(color);
WriteConsoleA(out_handle_, msg.formatted.data(), static_cast<DWORD>(msg.formatted.size()), nullptr, nullptr);
SetConsoleTextAttribute(out_handle_, orig_attribs); //reset to orig colors
}
virtual void _flush() override
{
// windows console always flushed?
}
// change the color for the given level
void set_color(level::level_enum level, WORD color)
{
std::lock_guard<Mutex> lock(base_sink<Mutex>::_mutex);
colors_[level] = color;
}
private:
HANDLE out_handle_;
std::map<level::level_enum, WORD> colors_;
// set color and return the orig console attributes (for resetting later)
WORD set_console_attribs(WORD attribs)
{
CONSOLE_SCREEN_BUFFER_INFO orig_buffer_info;
GetConsoleScreenBufferInfo(out_handle_, &orig_buffer_info);
WORD back_color = orig_buffer_info.wAttributes;
// retrieve the current background color
back_color &= ~(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY);
// keep the background color unchanged
SetConsoleTextAttribute(out_handle_, attribs | back_color);
return orig_buffer_info.wAttributes; //return orig attribs
}
};
//
// windows color console to stdout
//
template<class Mutex>
class wincolor_stdout_sink: public wincolor_sink<Mutex>
{
public:
wincolor_stdout_sink() : wincolor_sink<Mutex>(GetStdHandle(STD_OUTPUT_HANDLE))
{}
};
typedef wincolor_stdout_sink<std::mutex> wincolor_stdout_sink_mt;
typedef wincolor_stdout_sink<details::null_mutex> wincolor_stdout_sink_st;
//
// windows color console to stderr
//
template<class Mutex>
class wincolor_stderr_sink: public wincolor_sink<Mutex>
{
public:
wincolor_stderr_sink() : wincolor_sink<Mutex>(GetStdHandle(STD_ERROR_HANDLE))
{}
};
typedef wincolor_stderr_sink<std::mutex> wincolor_stderr_sink_mt;
typedef wincolor_stderr_sink<details::null_mutex> wincolor_stderr_sink_st;
}
}