Log/Log.h

124 lines
3.1 KiB
C
Raw Normal View History

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;
}
};
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);
};