summaryrefslogtreecommitdiff
path: root/lib/spdlog/sinks
diff options
context:
space:
mode:
Diffstat (limited to 'lib/spdlog/sinks')
-rw-r--r--lib/spdlog/sinks/android_sink.h91
-rw-r--r--lib/spdlog/sinks/ansicolor_sink.h150
-rw-r--r--lib/spdlog/sinks/base_sink.h49
-rw-r--r--lib/spdlog/sinks/dist_sink.h77
-rw-r--r--lib/spdlog/sinks/file_sinks.h255
-rw-r--r--lib/spdlog/sinks/msvc_sink.h44
-rw-r--r--lib/spdlog/sinks/null_sink.h29
-rw-r--r--lib/spdlog/sinks/ostream_sink.h49
-rw-r--r--lib/spdlog/sinks/sink.h44
-rw-r--r--lib/spdlog/sinks/stdout_sinks.h79
-rw-r--r--lib/spdlog/sinks/syslog_sink.h76
-rw-r--r--lib/spdlog/sinks/wincolor_sink.h144
-rw-r--r--lib/spdlog/sinks/windebug_sink.h27
13 files changed, 1114 insertions, 0 deletions
diff --git a/lib/spdlog/sinks/android_sink.h b/lib/spdlog/sinks/android_sink.h
new file mode 100644
index 0000000..dd81163
--- /dev/null
+++ b/lib/spdlog/sinks/android_sink.h
@@ -0,0 +1,91 @@
+//
+// Copyright(c) 2015 Gabi Melman.
+// Distributed under the MIT License (http://opensource.org/licenses/MIT)
+//
+
+#pragma once
+
+#if defined(__ANDROID__)
+
+#include "../details/os.h"
+#include "sink.h"
+
+#include <android/log.h>
+#include <chrono>
+#include <mutex>
+#include <string>
+#include <thread>
+
+#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))
+ {
+ details::os::sleep_for_millis(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;
+};
+
+} // namespace sinks
+} // namespace spdlog
+
+#endif
diff --git a/lib/spdlog/sinks/ansicolor_sink.h b/lib/spdlog/sinks/ansicolor_sink.h
new file mode 100644
index 0000000..e74389c
--- /dev/null
+++ b/lib/spdlog/sinks/ansicolor_sink.h
@@ -0,0 +1,150 @@
+//
+// Copyright(c) 2017 spdlog authors.
+// Distributed under the MIT License (http://opensource.org/licenses/MIT)
+//
+
+#pragma once
+
+#include "../common.h"
+#include "../details/os.h"
+#include "base_sink.h"
+
+#include <string>
+#include <unordered_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:
+ explicit ansicolor_sink(FILE *file)
+ : target_file_(file)
+ {
+ should_do_colors_ = details::os::in_terminal(file) && details::os::is_color_terminal();
+ colors_[level::trace] = white;
+ colors_[level::debug] = cyan;
+ colors_[level::info] = green;
+ colors_[level::warn] = yellow + bold;
+ colors_[level::err] = red + bold;
+ colors_[level::critical] = bold + on_red;
+ colors_[level::off] = reset;
+ }
+
+ ~ansicolor_sink() override
+ {
+ _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[m";
+ 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";
+ const std::string clear_line = "\033[K";
+
+ // Foreground colors
+ const std::string black = "\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_black = "\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:
+ 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_ && msg.color_range_end > msg.color_range_start)
+ {
+ // before color range
+ _print_range(msg, 0, msg.color_range_start);
+ // in color range
+ _print_ccode(colors_[msg.level]);
+ _print_range(msg, msg.color_range_start, msg.color_range_end);
+ _print_ccode(reset);
+ // after color range
+ _print_range(msg, msg.color_range_end, msg.formatted.size());
+ }
+ else
+ {
+ _print_range(msg, 0, msg.formatted.size());
+ }
+ _flush();
+ }
+
+ void _flush() override
+ {
+ fflush(target_file_);
+ }
+
+private:
+ void _print_ccode(const std::string &color_code)
+ {
+ fwrite(color_code.data(), sizeof(char), color_code.size(), target_file_);
+ }
+ void _print_range(const details::log_msg &msg, size_t start, size_t end)
+ {
+ fwrite(msg.formatted.data() + start, sizeof(char), end - start, target_file_);
+ }
+ FILE *target_file_;
+ bool should_do_colors_;
+ std::unordered_map<level::level_enum, std::string, level::level_hasher> colors_;
+};
+
+template<class Mutex>
+class ansicolor_stdout_sink : public ansicolor_sink<Mutex>
+{
+public:
+ ansicolor_stdout_sink()
+ : ansicolor_sink<Mutex>(stdout)
+ {
+ }
+};
+
+using ansicolor_stdout_sink_mt = ansicolor_stdout_sink<std::mutex>;
+using ansicolor_stdout_sink_st = ansicolor_stdout_sink<details::null_mutex>;
+
+template<class Mutex>
+class ansicolor_stderr_sink : public ansicolor_sink<Mutex>
+{
+public:
+ ansicolor_stderr_sink()
+ : ansicolor_sink<Mutex>(stderr)
+ {
+ }
+};
+
+using ansicolor_stderr_sink_mt = ansicolor_stderr_sink<std::mutex>;
+using ansicolor_stderr_sink_st = ansicolor_stderr_sink<details::null_mutex>;
+
+} // namespace sinks
+} // namespace spdlog
diff --git a/lib/spdlog/sinks/base_sink.h b/lib/spdlog/sinks/base_sink.h
new file mode 100644
index 0000000..96cd001
--- /dev/null
+++ b/lib/spdlog/sinks/base_sink.h
@@ -0,0 +1,49 @@
+//
+// 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 "../common.h"
+#include "../details/log_msg.h"
+#include "../formatter.h"
+#include "sink.h"
+
+#include <mutex>
+
+namespace spdlog {
+namespace sinks {
+template<class Mutex>
+class base_sink : public sink
+{
+public:
+ 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
+ {
+ std::lock_guard<Mutex> lock(_mutex);
+ _flush();
+ }
+
+protected:
+ virtual void _sink_it(const details::log_msg &msg) = 0;
+ virtual void _flush() = 0;
+ Mutex _mutex;
+};
+} // namespace sinks
+} // namespace spdlog
diff --git a/lib/spdlog/sinks/dist_sink.h b/lib/spdlog/sinks/dist_sink.h
new file mode 100644
index 0000000..b4a7b6a
--- /dev/null
+++ b/lib/spdlog/sinks/dist_sink.h
@@ -0,0 +1,77 @@
+//
+// Copyright (c) 2015 David Schury, Gabi Melman
+// Distributed under the MIT License (http://opensource.org/licenses/MIT)
+//
+
+#pragma once
+
+#include "../details/log_msg.h"
+#include "../details/null_mutex.h"
+#include "base_sink.h"
+#include "sink.h"
+
+#include <algorithm>
+#include <memory>
+#include <mutex>
+#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;
+
+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
+ {
+ 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());
+ }
+
+ void remove_all_sinks()
+ {
+ std::lock_guard<Mutex> lock(base_sink<Mutex>::_mutex);
+ _sinks.clear();
+ }
+};
+
+using dist_sink_mt = dist_sink<std::mutex>;
+using dist_sink_st = dist_sink<details::null_mutex>;
+
+} // namespace sinks
+} // namespace spdlog
diff --git a/lib/spdlog/sinks/file_sinks.h b/lib/spdlog/sinks/file_sinks.h
new file mode 100644
index 0000000..109c493
--- /dev/null
+++ b/lib/spdlog/sinks/file_sinks.h
@@ -0,0 +1,255 @@
+//
+// Copyright(c) 2015 Gabi Melman.
+// Distributed under the MIT License (http://opensource.org/licenses/MIT)
+//
+
+#pragma once
+
+#include "../details/file_helper.h"
+#include "../details/null_mutex.h"
+#include "../fmt/fmt.h"
+#include "base_sink.h"
+
+#include <algorithm>
+#include <cerrno>
+#include <chrono>
+#include <cstdio>
+#include <ctime>
+#include <mutex>
+#include <string>
+
+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;
+};
+
+using simple_file_sink_mt = simple_file_sink<std::mutex>;
+using simple_file_sink_st = simple_file_sink<details::null_mutex>;
+
+/*
+ * Rotating file sink based on size
+ */
+template<class Mutex>
+class rotating_file_sink SPDLOG_FINAL : public base_sink<Mutex>
+{
+public:
+ rotating_file_sink(filename_t base_filename, std::size_t max_size, std::size_t max_files)
+ : _base_filename(std::move(base_filename))
+ , _max_size(max_size)
+ , _max_files(max_files)
+ {
+ _file_helper.open(calc_filename(_base_filename, 0));
+ _current_size = _file_helper.size(); // expensive. called only once
+ }
+
+ // calc filename according to index and file extension if exists.
+ // e.g. calc_filename("logs/mylog.txt, 3) => "logs/mylog.3.txt".
+ static filename_t calc_filename(const filename_t &filename, std::size_t index)
+ {
+ typename std::conditional<std::is_same<filename_t::value_type, char>::value, fmt::MemoryWriter, fmt::WMemoryWriter>::type w;
+ if (index != 0u)
+ {
+ filename_t basename, ext;
+ std::tie(basename, ext) = details::file_helper::split_by_extenstion(filename);
+ w.write(SPDLOG_FILENAME_T("{}.{}{}"), basename, index, ext);
+ }
+ else
+ {
+ w.write(SPDLOG_FILENAME_T("{}"), filename);
+ }
+ return w.str();
+ }
+
+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:
+ // Rotate files:
+ // log.txt -> log.1.txt
+ // log.1.txt -> log.2.txt
+ // log.2.txt -> log.3.txt
+ // log.3.txt -> 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) != 0)
+ {
+ 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;
+};
+
+using rotating_file_sink_mt = rotating_file_sink<std::mutex>;
+using rotating_file_sink_st = rotating_file_sink<details::null_mutex>;
+
+/*
+ * Default generator of daily log file names.
+ */
+struct default_daily_file_name_calculator
+{
+ // Create filename for the form filename.YYYY-MM-DD_hh-mm.ext
+ static filename_t calc_filename(const filename_t &filename)
+ {
+ std::tm tm = spdlog::details::os::localtime();
+ filename_t basename, ext;
+ std::tie(basename, ext) = details::file_helper::split_by_extenstion(filename);
+ 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, ext);
+ return w.str();
+ }
+};
+
+/*
+ * Generator of daily log file names in format basename.YYYY-MM-DD.ext
+ */
+struct dateonly_daily_file_name_calculator
+{
+ // Create filename for the form basename.YYYY-MM-DD
+ static filename_t calc_filename(const filename_t &filename)
+ {
+ std::tm tm = spdlog::details::os::localtime();
+ filename_t basename, ext;
+ std::tie(basename, ext) = details::file_helper::split_by_extenstion(filename);
+ 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, ext);
+ 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(filename_t base_filename, int rotation_hour, int rotation_minute)
+ : _base_filename(std::move(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;
+ }
+ return {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;
+};
+
+using daily_file_sink_mt = daily_file_sink<std::mutex>;
+using daily_file_sink_st = daily_file_sink<details::null_mutex>;
+
+} // namespace sinks
+} // namespace spdlog
diff --git a/lib/spdlog/sinks/msvc_sink.h b/lib/spdlog/sinks/msvc_sink.h
new file mode 100644
index 0000000..09a5d67
--- /dev/null
+++ b/lib/spdlog/sinks/msvc_sink.h
@@ -0,0 +1,44 @@
+//
+// Copyright(c) 2016 Alexander Dalshov.
+// Distributed under the MIT License (http://opensource.org/licenses/MIT)
+//
+
+#pragma once
+
+#if defined(_WIN32)
+
+#include "../details/null_mutex.h"
+#include "base_sink.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 {}
+};
+
+using msvc_sink_mt = msvc_sink<std::mutex>;
+using msvc_sink_st = msvc_sink<details::null_mutex>;
+
+} // namespace sinks
+} // namespace spdlog
+
+#endif
diff --git a/lib/spdlog/sinks/null_sink.h b/lib/spdlog/sinks/null_sink.h
new file mode 100644
index 0000000..c254bc5
--- /dev/null
+++ b/lib/spdlog/sinks/null_sink.h
@@ -0,0 +1,29 @@
+//
+// Copyright(c) 2015 Gabi Melman.
+// Distributed under the MIT License (http://opensource.org/licenses/MIT)
+//
+
+#pragma once
+
+#include "../details/null_mutex.h"
+#include "base_sink.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 {}
+};
+
+using null_sink_mt = null_sink<details::null_mutex>;
+using null_sink_st = null_sink<details::null_mutex>;
+
+} // namespace sinks
+} // namespace spdlog
diff --git a/lib/spdlog/sinks/ostream_sink.h b/lib/spdlog/sinks/ostream_sink.h
new file mode 100644
index 0000000..9728138
--- /dev/null
+++ b/lib/spdlog/sinks/ostream_sink.h
@@ -0,0 +1,49 @@
+//
+// Copyright(c) 2015 Gabi Melman.
+// Distributed under the MIT License (http://opensource.org/licenses/MIT)
+//
+
+#pragma once
+
+#include "../details/null_mutex.h"
+#include "base_sink.h"
+
+#include <mutex>
+#include <ostream>
+
+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;
+
+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;
+};
+
+using ostream_sink_mt = ostream_sink<std::mutex>;
+using ostream_sink_st = ostream_sink<details::null_mutex>;
+
+} // namespace sinks
+} // namespace spdlog
diff --git a/lib/spdlog/sinks/sink.h b/lib/spdlog/sinks/sink.h
new file mode 100644
index 0000000..b4e3806
--- /dev/null
+++ b/lib/spdlog/sinks/sink.h
@@ -0,0 +1,44 @@
+//
+// Copyright(c) 2015 Gabi Melman.
+// Distributed under the MIT License (http://opensource.org/licenses/MIT)
+//
+
+#pragma once
+
+#include "../details/log_msg.h"
+
+namespace spdlog {
+namespace sinks {
+class sink
+{
+public:
+ virtual ~sink() = default;
+
+ 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{level::trace};
+};
+
+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));
+}
+
+} // namespace sinks
+} // namespace spdlog
diff --git a/lib/spdlog/sinks/stdout_sinks.h b/lib/spdlog/sinks/stdout_sinks.h
new file mode 100644
index 0000000..b15d080
--- /dev/null
+++ b/lib/spdlog/sinks/stdout_sinks.h
@@ -0,0 +1,79 @@
+//
+// Copyright(c) 2015 Gabi Melman.
+// Distributed under the MIT License (http://opensource.org/licenses/MIT)
+//
+
+#pragma once
+
+#include "../details/null_mutex.h"
+#include "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:
+ explicit stdout_sink() = default;
+
+ 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);
+ }
+};
+
+using stdout_sink_mt = stdout_sink<std::mutex>;
+using stdout_sink_st = stdout_sink<details::null_mutex>;
+
+template<class Mutex>
+class stderr_sink SPDLOG_FINAL : public base_sink<Mutex>
+{
+ using MyType = stderr_sink<Mutex>;
+
+public:
+ explicit stderr_sink() = default;
+
+ 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);
+ }
+};
+
+using stderr_sink_mt = stderr_sink<std::mutex>;
+using stderr_sink_st = stderr_sink<details::null_mutex>;
+
+} // namespace sinks
+} // namespace spdlog
diff --git a/lib/spdlog/sinks/syslog_sink.h b/lib/spdlog/sinks/syslog_sink.h
new file mode 100644
index 0000000..17bbb1d
--- /dev/null
+++ b/lib/spdlog/sinks/syslog_sink.h
@@ -0,0 +1,76 @@
+//
+// Copyright(c) 2015 Gabi Melman.
+// Distributed under the MIT License (http://opensource.org/licenses/MIT)
+//
+
+#pragma once
+
+#include "../common.h"
+
+#ifdef SPDLOG_ENABLE_SYSLOG
+
+#include "../details/log_msg.h"
+#include "sink.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<size_t>(level::trace)] = LOG_DEBUG;
+ _priorities[static_cast<size_t>(level::debug)] = LOG_DEBUG;
+ _priorities[static_cast<size_t>(level::info)] = LOG_INFO;
+ _priorities[static_cast<size_t>(level::warn)] = LOG_WARNING;
+ _priorities[static_cast<size_t>(level::err)] = LOG_ERR;
+ _priorities[static_cast<size_t>(level::critical)] = LOG_CRIT;
+ _priorities[static_cast<size_t>(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() override
+ {
+ ::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<size_t>(msg.level)];
+ }
+};
+} // namespace sinks
+} // namespace spdlog
+
+#endif
diff --git a/lib/spdlog/sinks/wincolor_sink.h b/lib/spdlog/sinks/wincolor_sink.h
new file mode 100644
index 0000000..402fa12
--- /dev/null
+++ b/lib/spdlog/sinks/wincolor_sink.h
@@ -0,0 +1,144 @@
+//
+// Copyright(c) 2016 spdlog
+// Distributed under the MIT License (http://opensource.org/licenses/MIT)
+//
+
+#pragma once
+
+#include "../common.h"
+#include "../details/null_mutex.h"
+#include "base_sink.h"
+
+#include <mutex>
+#include <string>
+#include <unordered_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 GREEN = FOREGROUND_GREEN;
+ 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] = WHITE;
+ colors_[level::debug] = CYAN;
+ colors_[level::info] = GREEN;
+ 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;
+ }
+
+ ~wincolor_sink() override
+ {
+ this->flush();
+ }
+
+ wincolor_sink(const wincolor_sink &other) = delete;
+ wincolor_sink &operator=(const wincolor_sink &other) = delete;
+
+ // 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;
+ }
+
+protected:
+ void _sink_it(const details::log_msg &msg) override
+ {
+ if (msg.color_range_end > msg.color_range_start)
+ {
+ // before color range
+ _print_range(msg, 0, msg.color_range_start);
+
+ // in color range
+ auto orig_attribs = set_console_attribs(colors_[msg.level]);
+ _print_range(msg, msg.color_range_start, msg.color_range_end);
+ ::SetConsoleTextAttribute(out_handle_, orig_attribs); // reset to orig colors
+ // after color range
+ _print_range(msg, msg.color_range_end, msg.formatted.size());
+ }
+ else // print without colors if color range is invalid
+ {
+ _print_range(msg, 0, msg.formatted.size());
+ }
+ }
+
+ void _flush() override
+ {
+ // windows console always flushed?
+ }
+
+private:
+ HANDLE out_handle_;
+ std::unordered_map<level::level_enum, WORD, level::level_hasher> 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 &= static_cast<WORD>(~(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
+ }
+
+ // print a range of formatted message to console
+ void _print_range(const details::log_msg &msg, size_t start, size_t end)
+ {
+ DWORD size = static_cast<DWORD>(end - start);
+ WriteConsoleA(out_handle_, msg.formatted.data() + start, size, nullptr, nullptr);
+ }
+};
+
+//
+// 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))
+ {
+ }
+};
+
+using wincolor_stdout_sink_mt = wincolor_stdout_sink<std::mutex>;
+using wincolor_stdout_sink_st = wincolor_stdout_sink<details::null_mutex>;
+
+//
+// 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))
+ {
+ }
+};
+
+using wincolor_stderr_sink_mt = wincolor_stderr_sink<std::mutex>;
+using wincolor_stderr_sink_st = wincolor_stderr_sink<details::null_mutex>;
+
+} // namespace sinks
+} // namespace spdlog
diff --git a/lib/spdlog/sinks/windebug_sink.h b/lib/spdlog/sinks/windebug_sink.h
new file mode 100644
index 0000000..2c7f1bc
--- /dev/null
+++ b/lib/spdlog/sinks/windebug_sink.h
@@ -0,0 +1,27 @@
+//
+// Copyright(c) 2017 Alexander Dalshov.
+// Distributed under the MIT License (http://opensource.org/licenses/MIT)
+//
+
+#pragma once
+
+#if defined(_WIN32)
+
+#include "msvc_sink.h"
+
+namespace spdlog {
+namespace sinks {
+
+/*
+ * Windows debug sink (logging using OutputDebugStringA, synonym for msvc_sink)
+ */
+template<class Mutex>
+using windebug_sink = msvc_sink<Mutex>;
+
+using windebug_sink_mt = msvc_sink_mt;
+using windebug_sink_st = msvc_sink_st;
+
+} // namespace sinks
+} // namespace spdlog
+
+#endif