#include "logging.h" #include #include using namespace logging; using std::string; using std::vector; using std::tuple; using std::make_tuple; using std::shared_ptr; using std::lock_guard; template <> const string& getEnumTypeName() { static const string name = "LogLevel"; return name; } template <> const vector>& getEnumMembers() { static const vector> values = { make_tuple(Level::Trace, "Trace"), make_tuple(Level::Debug, "Debug"), make_tuple(Level::Info, "Info"), make_tuple(Level::Warn, "Warn"), make_tuple(Level::Error, "Error"), make_tuple(Level::Fatal, "Fatal") }; return values; } std::ostream& operator<<(std::ostream& stream, Level value) { return stream << enumToString(value); } std::istream& operator>>(std::istream& stream, Level& value) { string name; stream >> name; value = parseEnum(name); return stream; } Entry::Entry(Level level, const string& message) : level(level), message(message) { time(×tamp); } string SimpleConsoleFormatter::format(const Entry& entry) { return fmt::format("[{0}] {1}", entry.level, entry.message); } string SimpleFileFormatter::format(const Entry& entry) { return fmt::format("[{0}] {1}", formatTime(entry.timestamp, "%F %H:%M:%S"), consoleFormatter.format(entry)); } LevelFilter::LevelFilter(shared_ptr innerSink, Level minLevel) : innerSink(innerSink), minLevel(minLevel) {} void LevelFilter::receive(const Entry& entry) { if (entry.level >= minLevel) { innerSink->receive(entry); } } StreamSink::StreamSink(shared_ptr stream, shared_ptr formatter) : stream(stream), formatter(formatter) {} void StreamSink::receive(const Entry& entry) { string line = formatter->format(entry); *stream << line << std::endl; } StdErrSink::StdErrSink(shared_ptr formatter) : StreamSink(std::shared_ptr(&std::cerr, [](void*){}), formatter) {} PausableSink::PausableSink(shared_ptr innerSink) : innerSink(innerSink) {} void PausableSink::receive(const Entry& entry) { lock_guard lock(mutex); if (isPaused) { buffer.push_back(entry); } else { innerSink->receive(entry); } } void PausableSink::pause() { lock_guard lock(mutex); isPaused = true; } void PausableSink::resume() { lock_guard lock(mutex); isPaused = false; for (const Entry& entry : buffer) { innerSink->receive(entry); } buffer.clear(); } std::mutex& getLogMutex() { static std::mutex mutex; return mutex; } vector>& getSinks() { static vector> sinks; return sinks; } void logging::addSink(shared_ptr sink) { lock_guard lock(getLogMutex()); getSinks().push_back(sink); } void logging::log(Level level, const string& message) { lock_guard lock(getLogMutex()); for (auto& sink : getSinks()) { sink->receive(Entry(level, message)); } }