Skip to content

Instantly share code, notes, and snippets.

@6502
Created October 23, 2016 21:12
Show Gist options
  • Save 6502/817e9ec49e17ff9fcc355cec622adf23 to your computer and use it in GitHub Desktop.
Save 6502/817e9ec49e17ff9fcc355cec622adf23 to your computer and use it in GitHub Desktop.
A simple logging facility
#if !defined(LOG_H_INCLUDED)
#define LOG_H_INCLUDED
#include <stdio.h>
#include <vector>
#include <string>
#include <deque>
#include <map>
#include <functional>
#include <time.h>
#include <string.h>
#include <stdarg.h>
namespace log {
std::string stringf(const char *fmt, ...) {
std::vector<char> buffer(256);
va_list args, cp;
va_start(args, fmt);
va_copy(cp, args);
int sz = vsnprintf(&buffer[0], buffer.size(), fmt, args);
if (sz >= int(buffer.size())) {
buffer.resize(sz + 1);
vsnprintf(&buffer[0], buffer.size(), fmt, cp);
}
va_end(cp);
va_end(args);
return &buffer[0];
}
inline std::map<int, std::string>& severities(){
static std::map<int, std::string> s{
{0, "info"},
{100, "warning"},
{200, "error"},
{1000, "fatal error"}};
return s;
}
inline std::string sevname(int severity) {
auto& s = severities();
auto it = s.find(severity);
if (it == s.end()) it = s.find(severity/100*100);
if (it != s.end()) return it->second;
return stringf("severity=%i", severity);
}
struct Entry {
double time;
int severity;
std::string context;
std::string message;
};
typedef std::function<std::string(const Entry&)> Formatter;
typedef std::function<void(const Entry&)> Logger;
typedef std::function<bool(const Entry&)> Filter;
inline Formatter default_formatter() {
return [](const Entry& e) -> std::string {
char ctimebuf[30];
time_t t = e.time;
ctime_r(&t, ctimebuf); ctimebuf[strlen(ctimebuf)-1] = '\0';
return stringf("%s - %s: (%s) -- %s",
ctimebuf,
sevname(e.severity).c_str(),
e.context.c_str(),
e.message.c_str());
};
}
struct MultiLogger {
std::vector<Logger> Ls;
void operator()(const Entry& e) {
for (auto& x : Ls) x(e);
}
};
struct FilteringLogger {
Logger L;
Filter f;
void operator()(const Entry& e) {
if (f(e)) L(e);
}
};
inline FilteringLogger severityFilter(Logger L, int low, int high=-1) {
return FilteringLogger{L, [low, high](const Entry& e) {
return e.severity >= low && (high == -1 || e.severity <= high);
}};
}
struct MemLogger {
std::deque<Entry> q;
int max_size;
MemLogger(int max_size=-1) : max_size(max_size) {}
void operator()(const Entry& e) {
q.push_back(e);
while (max_size != -1 && int(q.size()) > max_size) {
q.pop_front();
}
}
};
struct FileLogger {
FILE *file;
Formatter formatter;
bool autoclose;
FileLogger(FILE *file, const Formatter& formatter = default_formatter(), bool autoclose = false)
: file(file), formatter(formatter), autoclose(autoclose)
{ }
~FileLogger() {
if (autoclose) fclose(file);
}
void operator()(const Entry& e) {
fprintf(file, "%s\n", formatter(e).c_str());
}
};
inline Logger& root() {
static Logger L = FileLogger(stderr);
return L;
}
inline double now() {
return time(0);
}
}
#define LOGSTRINGIFY(x) #x
#define LOGTOSTRING(x) LOGSTRINGIFY(x)
#define LOG(severity, ...) \
log::root()(log::Entry{log::now(), \
severity, \
__FILE__ ":" LOGTOSTRING(__LINE__), \
log::stringf(__VA_ARGS__)})
#define INFO(...) LOG( 0, __VA_ARGS__)
#define WARNING(...) LOG( 100, __VA_ARGS__)
#define ERROR(...) LOG( 200, __VA_ARGS__)
#define FATAL(...) LOG(1000, __VA_ARGS__)
#endif
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment