Log/Log.cpp

152 lines
3.8 KiB
C++

#include "Log.h"
/*
* class Log
*/
// static members
std::vector<Log::Output*> Log::outputs;
Log::LeveledSink Log::fatal(Log::Level::FATAL);
Log::LeveledSink Log::error(Log::Level::ERROR);
Log::LeveledSink Log::warn(Log::Level::WARN);
Log::LeveledSink Log::note(Log::Level::NOTE);
Log::LeveledSink Log::info(Log::Level::INFO);
Log::LeveledSink Log::debug(Log::Level::DEBUG);
Log::LeveledSink Log::trace(Log::Level::TRACE);
void Log::init() {
// add default console logger
if (outputs.empty())
outputs.push_back(new Log::ConsoleOutput());
}
void Log::stop() {
for (auto output : outputs)
delete output;
outputs.clear();
}
void Log::addLogfile(const std::string& filename, Level max) {
outputs.push_back(new Log::FileOutput(filename, max));
}
void Log::addLogfile(const std::string& filename, Level min, Level max) {
outputs.push_back(new Log::FileOutput(filename, min, max));
}
void Log::setConsoleLogLevel(Level lvl) {
outputs.at(0)->setLogLevel(lvl); // has to exist
}
void Log::setColoredOutput(bool enabled) {
((Log::ConsoleOutput*) outputs.at(0))->setColoredOutput(enabled); // has to exist
}
void Log::log(Level lvl, std::stringbuf* strb) {
for (Output* out : outputs) {
out->log(lvl, strb);
// reset stringbuffer read pointer to the beginning
strb->pubseekpos(0);
}
}
/*
* abstract class Output
* default implementations
*/
Log::Output::Output() {}
Log::Output::Output(Log::Level lvl_max) : lvl_max(lvl_max) {}
Log::Output::~Output() {}
void Log::Output::log(Log::Level lvl, std::stringbuf* sbuf) {
std::ostream* os = getOs(lvl);
if (os) {
printLogHeader(os, lvl);
*os << sbuf << std::endl;
}
}
void Log::Output::setLogLevel(Log::Level lvl) {
lvl_max = lvl;
}
void Log::Output::printLogHeader(std::ostream* os, Level lvl) {
static const char* LevelTag[] = {"", "[FATAL] ", "[ERROR] ", "[WARN ] ",
"[NOTE ] ", "[INFO ] ", "[DEBUG] ", "[TRACE] "};
// get current date/time
auto now = std::chrono::system_clock::now();
std::time_t now_c = std::chrono::system_clock::to_time_t(now);
*os << "[" << std::put_time(std::localtime(&now_c), "%F %T") << "]" << LevelTag[lvl];
}
/*
* class ConsoleOutput
*/
Log::ConsoleOutput::ConsoleOutput() : Output() {}
bool Log::ConsoleOutput::setColoredOutput(bool enabled) {
// TODO: check the terminals compatibility for colors
coloredOutput = enabled;
return true;
}
void Log::ConsoleOutput::log(Log::Level lvl, std::stringbuf* sbuf) {
static const char* esc_seq_start = "\033[";
static const char* esc_seq_reset = "\033[0m";
// OFF FATAL ERROR WARN NOTE INFO DEBUG TRACE
static const char* color_codes[] = {"", "1;31;40m", "31m", "33m", "96m", "32m", "0m", "0m"};
std::ostream* os = getOs(lvl);
if (os) {
// print colors if enabled
if (coloredOutput)
*os << esc_seq_start << color_codes[lvl];
Output::printLogHeader(os, lvl);
*os << sbuf;
// reset color at end of the line
if (coloredOutput)
*os << esc_seq_reset;
*os << std::endl;
}
}
std::ostream* Log::ConsoleOutput::getOs(Log::Level lvl) {
// out of scope?
if (!lvl || lvl > lvl_max)
return nullptr;
// stderr for FATAL, ERROR, WARN
if (lvl <= Log::Level::WARN)
return osErr;
else
return osStd;
}
/*
* class FileOutput
* logging to file
*/
Log::FileOutput::FileOutput(const std::string& filename, Log::Level lvl_max)
: Output(lvl_max), filename(filename), ofs(filename, std::ofstream::out | std::ofstream::app) {}
Log::FileOutput::FileOutput(const std::string& filename, Log::Level lvl_min, Log::Level lvl_max)
: Output(lvl_max), filename(filename), ofs(filename, std::ofstream::out | std::ofstream::app), lvl_min(lvl_min) {}
std::ostream* Log::FileOutput::getOs(Log::Level lvl) {
if (lvl_min <= lvl && lvl <= lvl_max)
return &ofs;
return nullptr;
}
Log::LeveledSink::LeveledSink(Log::Level level) : level(level) {}