Created
April 19, 2019 14:15
-
-
Save jo-makar/3a8e379ae45e256ae33e30739d02487a to your computer and use it in GitHub Desktop.
Logging framework implemented as an input stream
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "logstream.hpp" | |
#include <chrono> | |
#include <ctime> | |
#include <mutex> | |
#include <thread> | |
using namespace std; | |
unsigned int thread_id() { | |
static unsigned int idx = 0; | |
static mutex mtx; | |
static map<thread::id, unsigned int> ids; | |
lock_guard<mutex> lock(mtx); | |
thread::id id = this_thread::get_id(); | |
auto it = ids.find(id); | |
if (it != ids.end()) | |
return it->second; | |
return ids[id] = idx++; | |
} | |
ostringstream &Logstream::get(unsigned int level, | |
const char *func, const char *file, unsigned int line) { | |
for (auto it = fmt.cbegin(); it != fmt.cend(); it++) { | |
if (*it == "timestamp") { | |
// Use chrono::system_clock::now() because time() only provides second-resolution | |
auto n1 = chrono::time_point_cast<chrono::milliseconds>(chrono::system_clock::now()); | |
unsigned int ms = n1.time_since_epoch().count() % 1000; | |
time_t n2 = chrono::system_clock::to_time_t(n1); | |
struct tm n3; | |
localtime_r(&n2, &n3); | |
char s[128]; | |
size_t rv; | |
rv = strftime(s, sizeof(s)-1, "%Y-%m-%d %H:%M:%S", &n3); | |
snprintf(s + rv, sizeof(s)-rv, ".%03u", ms); | |
s[sizeof(s)-1] = 0; | |
os << s << ":"; | |
} | |
else if (*it == "thread") { | |
os << "thread-" << thread_id() << ":"; | |
} | |
else if (*it == "levelname") { | |
os << levelname.at(level) << ":"; | |
} | |
else if (*it == "function") { | |
os << func << ":"; | |
} | |
else if (*it == "filename") { | |
os << file << ":"; | |
} | |
else if (*it == "fileline") { | |
os << line << ":"; | |
} | |
} | |
return os; | |
} | |
const map<unsigned int, string> Logstream::levelname = {{DEBUG, "debug"}, {INFO, "info"}, {WARNING, "warning"}, {ERROR, "error"}}; | |
unsigned int Logstream::loglevel = Logstream::INFO; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// This framework is based on Petru Marginean's design: | |
// http://www.drdobbs.com/cpp/logging-in-c/201804215 | |
#include <iostream> | |
#include <list> | |
#include <map> | |
#include <sstream> | |
using namespace std; | |
#define logstream(level) \ | |
if (Logstream::level > Logstream::loglevel) \ | |
; \ | |
else \ | |
Logstream().get(Logstream::level, __FUNCTION__, __FILE__, __LINE__) | |
class Logstream { | |
public: | |
enum { DEBUG=3, INFO=2, WARNING=1, ERROR=0 }; | |
const static map<unsigned int, string> levelname; | |
static unsigned int loglevel; | |
#define FORMAT "timestamp", "thread", "levelname", "function" | |
Logstream(const list<string> &fmt={FORMAT}) { this->fmt = fmt; } | |
ostringstream &get(unsigned int level, | |
const char *func, const char *file, unsigned int line); | |
~Logstream() { | |
cerr << os.str() << endl; | |
} | |
private: | |
list<string> fmt; | |
ostringstream os; | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment