2019-06-01 19:25:24 +02:00
|
|
|
#pragma once
|
|
|
|
#include <chrono> // date/time
|
|
|
|
#include <fstream> // ofstream (logging to file)
|
|
|
|
#include <iomanip> // std::put_time
|
|
|
|
#include <iostream> // std::ostream, std::cout, std::cin
|
|
|
|
#include <sstream> // std::stringstream (buffer for log entries)
|
|
|
|
#include <string>
|
|
|
|
#include <vector> // list of outputs
|
|
|
|
|
|
|
|
class Log {
|
2019-06-02 18:54:58 +02:00
|
|
|
public:
|
2019-06-01 19:25:24 +02:00
|
|
|
enum Level { OFF = 0, FATAL, ERROR, WARN, NOTE, INFO, DEBUG, TRACE };
|
|
|
|
|
|
|
|
// delete ctors as this class is used via static methods only
|
|
|
|
Log() = delete;
|
|
|
|
Log(const Log&) = delete;
|
|
|
|
Log& operator=(const Log&) = delete;
|
2019-06-01 23:51:14 +02:00
|
|
|
//~Log() = delete;
|
2019-06-01 19:25:24 +02:00
|
|
|
|
|
|
|
// set up the logger with a ConsoleOutput
|
|
|
|
static void init();
|
|
|
|
// close all output streams
|
|
|
|
static void stop();
|
|
|
|
|
2019-06-02 18:54:58 +02:00
|
|
|
private:
|
2019-06-01 19:25:24 +02:00
|
|
|
// abstract base class for a log sink
|
|
|
|
class Output {
|
2019-06-02 18:54:58 +02:00
|
|
|
public:
|
2019-06-01 23:51:14 +02:00
|
|
|
Output();
|
|
|
|
Output(Log::Level lvl_max);
|
|
|
|
virtual ~Output();
|
2019-06-01 19:25:24 +02:00
|
|
|
virtual void log(Log::Level lvl, std::stringbuf* sbuf);
|
2019-06-01 23:51:14 +02:00
|
|
|
virtual void setLogLevel(Log::Level lvl);
|
2019-06-01 19:25:24 +02:00
|
|
|
|
2019-06-02 18:54:58 +02:00
|
|
|
protected:
|
2019-06-01 19:25:24 +02:00
|
|
|
Log::Level lvl_max = INFO;
|
|
|
|
// returns the correct ostream for the given log-level
|
|
|
|
// or returns nullptr if no ostream is set/enabled for this level
|
|
|
|
virtual std::ostream* getOs(Log::Level lvl) = 0; // abstract
|
|
|
|
virtual void printLogHeader(std::ostream* os, Log::Level lvl);
|
|
|
|
};
|
|
|
|
|
|
|
|
// logging to stdout/stderr
|
2019-06-01 23:51:14 +02:00
|
|
|
class ConsoleOutput : public Output {
|
2019-06-02 18:54:58 +02:00
|
|
|
public:
|
2019-06-01 23:51:14 +02:00
|
|
|
ConsoleOutput();
|
2019-06-01 19:25:24 +02:00
|
|
|
virtual bool setColoredOutput(bool enabled);
|
|
|
|
|
2019-06-02 18:54:58 +02:00
|
|
|
private:
|
2019-06-01 19:25:24 +02:00
|
|
|
std::ostream* osStd = &std::cout;
|
|
|
|
std::ostream* osErr = &std::cerr;
|
|
|
|
bool coloredOutput;
|
|
|
|
virtual void log(Log::Level lvl, std::stringbuf* sbuf);
|
|
|
|
virtual std::ostream* getOs(Log::Level lvl);
|
|
|
|
};
|
|
|
|
|
|
|
|
class FileOutput : public Output {
|
2019-06-02 18:54:58 +02:00
|
|
|
public:
|
2019-06-01 19:25:24 +02:00
|
|
|
FileOutput(const std::string& filename, Log::Level lvl_max);
|
|
|
|
FileOutput(const std::string& filename, Log::Level lvl_min, Log::Level lvl_max);
|
|
|
|
|
2019-06-02 18:54:58 +02:00
|
|
|
private:
|
2019-06-01 19:25:24 +02:00
|
|
|
std::string filename;
|
|
|
|
std::ofstream ofs;
|
|
|
|
Log::Level lvl_min = FATAL;
|
|
|
|
virtual std::ostream* getOs(Log::Level lvl);
|
|
|
|
};
|
|
|
|
|
|
|
|
static std::vector<Output*> outputs;
|
|
|
|
|
2019-06-02 18:54:58 +02:00
|
|
|
public:
|
2019-06-01 19:25:24 +02:00
|
|
|
static void addLogfile(const std::string& filename, Level max);
|
|
|
|
static void addLogfile(const std::string& filename, Level min, Level max);
|
|
|
|
|
|
|
|
static void setConsoleLogLevel(Level lvl);
|
|
|
|
static void setColoredOutput(bool enabled);
|
|
|
|
|
|
|
|
// Log entry that can be formed with various mixed data types
|
|
|
|
// by concatenation with the << operator
|
|
|
|
// Inspired from https://stackoverflow.com/a/8337882
|
|
|
|
class Entry {
|
2019-06-02 18:54:58 +02:00
|
|
|
private:
|
2019-06-01 19:25:24 +02:00
|
|
|
std::stringstream ss;
|
|
|
|
Log::Level lvl;
|
|
|
|
|
2019-06-02 18:54:58 +02:00
|
|
|
public:
|
2019-06-01 19:25:24 +02:00
|
|
|
Entry(Log::Level lvl) : lvl(lvl) {}
|
|
|
|
Entry(Entry&&) = default;
|
|
|
|
~Entry() { Log::log(lvl, ss.rdbuf()); }
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
Entry& operator<<(const T& msg) {
|
|
|
|
ss << msg;
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2020-09-23 18:52:49 +02:00
|
|
|
class LeveledSink {
|
|
|
|
private:
|
|
|
|
Log::Level level;
|
|
|
|
public:
|
|
|
|
LeveledSink(Log::Level level);
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
Log::Entry operator<<(const T& msg) {
|
|
|
|
Log::Entry entry(level);
|
|
|
|
entry << msg;
|
|
|
|
return entry;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
// LeveledSinks
|
|
|
|
static LeveledSink fatal;
|
|
|
|
static LeveledSink error;
|
|
|
|
static LeveledSink warn;
|
|
|
|
static LeveledSink note;
|
|
|
|
static LeveledSink info;
|
|
|
|
static LeveledSink debug;
|
|
|
|
static LeveledSink trace;
|
|
|
|
|
|
|
|
private:
|
2019-06-01 19:25:24 +02:00
|
|
|
static void log(Level lvl, std::stringbuf* strb);
|
|
|
|
};
|