Skip to content

Instantly share code, notes, and snippets.

@surt91
Last active April 11, 2018 09:08
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save surt91/7efe10037c8c06d8e23de4cfe6e1e2dd to your computer and use it in GitHub Desktop.
Save surt91/7efe10037c8c06d8e23de4cfe6e1e2dd to your computer and use it in GitHub Desktop.
#include "Logging.hpp"
bool Logger::quiet = false; ///< Log only to file or also to stdout
int Logger::verbosity = 0; ///< global verbosity level to use
std::string Logger::logfilename = ""; ///< Filename to write the messenges to
Logger::Logger(log_level_t level, std::string file, int line, std::string function)
: level(level),
ss(),
file(file),
line(line),
function(function)
{
if(level <= verbosity)
{
ss.precision(12);
#ifdef __unix__
if(isatty(fileno(stdout))) // Terminal -> use colors
label = CLABEL[level];
else
#endif
label = LABEL[level]; // Windows or file -> do not use color
}
}
/// Writes the message to the logfile and flushes it to stdout, according to settings.
Logger::~Logger()
{
if(level <= verbosity)
{
// write current thread, if we are multithreaded
#ifdef _OPENMP
if(omp_get_num_threads() > 1)
ss << " (thread " << omp_get_thread_num() << ")";
#endif
if(level <= LOG_WARNING)
ss << " (" << file << ":" << line << " [" << function << "()]) ";
if(!quiet)
std::cout << label << ss.str() << std::endl;
if(!logfilename.empty())
{
std::ofstream logfile(logfilename, std::ofstream::app);
logfile << LABEL[level] << ss.str() << "\n";
}
}
}
/*! \file */
#ifndef LOGGING_H
#define LOGGING_H
#ifdef __unix__
#include <cstdio>
#include <unistd.h>
#endif
#include <sstream>
#include <iostream>
#include <fstream>
#include <iomanip>
#include <vector>
#ifdef _OPENMP
#include <omp.h>
#endif
#ifdef NLOG
// if compiled with -DNLOG, the compiler hopefully optimizes everything after the else away
#define LOG(level) \
if(true) {} \
else Logger(level)
#else
/** Low overhead logging macro.
*
* Prevents construction of the Logger object and evaluation of << operators
* if the Logger::verbosity level is lower than the \a level of the message.
* This also enables the output of Filename, Line and Function for every output
*
* Inspired by: \n
* http://stackoverflow.com/a/11826787/1698412 \n
* http://stackoverflow.com/questions/1255576/what-is-good-practice-for-generating-verbose-output
*/
#define LOG(level) \
if(level > Logger::verbosity) {} \
else Logger(level, __FILE__, __LINE__, __func__)
#endif
/// Enum defining which verbosity level to use, i.e. which events to output
enum log_level_t {
LOG_QUIET = 0, ///< Do not log anything
LOG_ALWAYS, ///< Do log things that should always be logged
LOG_ERROR, ///< Do log critical error messages which terminate the process
LOG_WARNING, ///< Do log warnings (recommended level)
LOG_INFO, ///< Do log interesting informations
LOG_TIMING, ///< Do log measured timings
LOG_DEBUG, ///< Do log debug messages
LOG_ALL, ///< Do log all messages
LOG_TOO_MUCH ///< Do log everything (this might result probably in log files measured in GB)
};
/// Labels appearing in front of messenges of the associated verbosity levels
static const std::vector<std::string> LABEL = {
"",
"",
"Error: ",
"Warning: ",
"Info: ",
"Timing: ",
"Debug: ",
"Debug2: ",
"Debug3: "
};
/// Labels appearing in front of messenges of the associated verbosity levels with color
static const std::vector<std::string> CLABEL = {
"",
"",
"\x1B[31mError: \033[0m",
"\x1B[33mWarning: \033[0m",
"\x1B[34mInfo: \033[0m",
"\x1B[34mTiming: \033[0m",
"\x1B[34mDebug: \033[0m",
"\x1B[34mDebug2: \033[0m",
"\x1B[34mDebug3: \033[0m"
};
/** Logs messages depending on a runtime set verbosity level.
*
* Use it through the #LOG(level) macro.
*/
class Logger {
public:
Logger(log_level_t level, std::string file="", int line=0, std::string function="");
~Logger();
static bool quiet;
static int verbosity;
static std::string logfilename;
template<class T>
friend std::ostream& operator<<(Logger &&l, const T &obj);
protected:
log_level_t level;
std::stringstream ss;
std::string label;
std::string file;
int line;
std::string function;
};
template<class T>
std::ostream& operator<<(Logger &&l, const T &obj)
{
l.ss << " " << obj;
return l.ss;
}
template<class T>
std::ostream& operator<<(std::ostream& os, const std::vector<T> &v)
{
for(auto i : v)
os << i << " ";
return os;
}
#endif
#include "Logging.hpp"
int main()
{
// configure Logger
Logger::quiet = false;
Logger::verbosity = 4;
Logger::logfilename = "mylogfile.log";
LOG(LOG_INFO) << "Hello World!";
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment