Skip to content

Instantly share code, notes, and snippets.

@Vivian-A
Last active March 24, 2025 01:38
Show Gist options
  • Save Vivian-A/8a0bfc5292eeb9182bd8e1f069b01dc0 to your computer and use it in GitHub Desktop.
Save Vivian-A/8a0bfc5292eeb9182bd8e1f069b01dc0 to your computer and use it in GitHub Desktop.
Really lightweight, header only, console, C++ logger
#ifndef LUMBERJACK_H
#define LUMBERJACK_H
#include <iostream>
#include <sstream>
#include <mutex>
#include <string>
#include <ctime>
#include <iomanip>
enum class LogLevel {
TRACE,
DEBUG,
INFO,
WARN,
ERROR,
FATAL
};
class lumberjack {
public:
inline static auto currentLevel = LogLevel::INFO;
inline static std::mutex logMutex;
inline static bool colorEnabled = true;
static void setLevel(const LogLevel level) { currentLevel = level; }
static LogLevel getLevel() { return currentLevel; }
static void enableColor() { colorEnabled = true; }
static void disableColor() { colorEnabled = false; }
template<typename... Args>
static void log(const LogLevel level, const Args&... args) {
if (level >= currentLevel) {
std::lock_guard lock(logMutex);
std::ostringstream stream;
// Timestamp
const auto t = std::time(nullptr);
const auto tm = *std::localtime(&t);
stream << std::put_time(&tm, "%H:%M:%S") << " ";
// Colored level tag
if (colorEnabled) {
switch(level) {
case LogLevel::TRACE: stream << "\033[37m"; break;
case LogLevel::DEBUG: stream << "\033[36m"; break;
case LogLevel::INFO: stream << "\033[32m"; break;
case LogLevel::WARN: stream << "\033[33m"; break;
case LogLevel::ERROR: stream << "\033[31m"; break;
case LogLevel::FATAL: stream << "\033[31;1m"; break;
}
}
stream << levelToString(level);
if (colorEnabled) {
stream << "\033[0m"; // Reset color
}
// Message
(stream << ... << args) << '\n';
// Output
(level >= LogLevel::ERROR ? std::cerr : std::cout) << stream.str();
}
}
lumberjack() = delete;
private:
static const char* levelToString(const LogLevel level) {
switch(level) {
case LogLevel::TRACE: return "[TRACE] ";
case LogLevel::DEBUG: return "[DEBUG] ";
case LogLevel::INFO: return "[INFO] ";
case LogLevel::WARN: return "[WARN] ";
case LogLevel::ERROR: return "[ERROR] ";
case LogLevel::FATAL: return "[FATAL] ";
default: return "[UNKNOWN] ";
}
}
};
// Helper macros
#define LOG_TRACE(...) lumberjack::log(LogLevel::TRACE, __VA_ARGS__)
#define LOG_DEBUG(...) lumberjack::log(LogLevel::DEBUG, __VA_ARGS__)
#define LOG_INFO(...) lumberjack::log(LogLevel::INFO, __VA_ARGS__)
#define LOG_WARN(...) lumberjack::log(LogLevel::WARN, __VA_ARGS__)
#define LOG_ERROR(...) lumberjack::log(LogLevel::ERROR, __VA_ARGS__)
#define LOG_FATAL(...) lumberjack::log(LogLevel::FATAL, __VA_ARGS__)
#endif // LUMBERJACK_H
@Vivian-A
Copy link
Author

Wrote this for my 3d engine, figured I might as well put it up.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment