File EasyLogging.hpp
File List > core > EasyLogging.hpp
Go to the documentation of this file
#pragma once
#include <fstream>
#include <iostream>
#include <map>
#include <sstream>
namespace clogged {
enum class LogLevel { DEBUG, INFO, WARNING, ERR, NA };
enum class Team {
TEAM_1,
TEAM_2,
TEAM_3,
TEAM_4,
TEAM_5,
TEAM_6,
TEAM_7,
TEAM_8,
TEAM_9,
GENERAL,
NA
};
enum class Color { RESET = 0, BLUE = 34, GREEN = 32, RED = 31 };
const LogLevel LOGLEVEL = LogLevel::DEBUG;
#ifndef NDEBUG
#define LOGLINE "File: " << __FILE__ << "::->::Line(" << __LINE__ << ")"
#define RELATIVE_PATH(file) \
(std::string(file).find_last_of("/\\") != std::string::npos \
? std::string(file).substr(std::string(file).find_last_of("/\\") + 1) \
: std::string(file))
#define LOG_RELLINE "File: " << RELATIVE_PATH(__FILE__) << "::->::Line(" << __LINE__ << ")"
#define LOG_FNC "Function: " << __func__ << " "
class Logger {
public:
Logger &operator<<(Team team) {
currentTeam = team;
metaPrinted = false;
// std::cout << endl; //TODO: Might have to enable this so that we
// can have same line logging when endl is not used
return *this;
}
Logger &operator<<(LogLevel logLevel) {
currentLogLevel = logLevel;
metaPrinted = false;
return *this;
}
Logger &operator<<(Color color) {
currentColor = color;
return *this;
}
Logger &operator<<(std::ostream &(*manipulator)(std::ostream &)) {
typedef std::ostream &(*EndlManipulator)(std::ostream &);
// Compare the function pointers
if (manipulator == static_cast<EndlManipulator>(std::endl) || manipulator == endl) {
// Handle std::endl here
currentTeam = Team::NA;
currentLogLevel = LogLevel::DEBUG;
currentColor = Color::RESET;
std::cout << std::endl;
metaPrinted = false;
}
return *this;
}
template <typename T>
Logger &operator<<(const T &value) {
// TODO: Define when to log by loglevel comparison. Goal is to send it in as
// a flag in the CMakeLists.txt
if (currentLogLevel >= LOGLEVEL) {
// added additional flag in case one wants to compile without colors (or)
// if the terminal does not support colors
#ifndef D_ANSI_COLOR_CODES
std::string colorStart = "\033[" + std::to_string(static_cast<int>(currentColor)) + "m";
std::string colorEnd = "\033[0m";
#else
std::string colorStart = "";
std::string colorEnd = "";
#endif
std::ostringstream logMessage;
logMessage << colorStart;
if (!metaPrinted) {
logMessage << teamToString(currentTeam) << logToString(currentLogLevel);
metaPrinted = true;
}
logMessage << value << colorEnd;
std::cout << logMessage.str(); // << std::endl; //TODO: Might have to
// make enable this so that we can have
// same line logging when endl is not used
}
return *this;
}
static Logger &Log() {
static Logger instance; // Guaranteed to be initialized only once.
return instance;
}
template <typename T, typename... EXTRA_Ts>
static Logger &Log(T &&arg1, EXTRA_Ts &&...extra_args) {
Log() << std::forward<T>(arg1); // Log the first argument.
if constexpr (sizeof...(EXTRA_Ts) == 0) { // No arguments left.
return Log() << Logger::endl; // Trigger a flush.
} else {
return Log(std::forward<EXTRA_Ts>(extra_args)...); // Log remaining arguments.
}
}
static std::ostream &endl(std::ostream &os) {
Log() << std::endl; // Call the custom Logger::endl to reset values
return os;
}
private:
Team currentTeam = Team::NA;
LogLevel currentLogLevel = LogLevel::DEBUG;
Color currentColor = Color::RESET;
bool metaPrinted = false;
std::map<Team, std::string> teamToStringMap = {
{Team::TEAM_1, "Team 1"}, {Team::TEAM_2, "Team 2"}, {Team::TEAM_3, "Team 3"},
{Team::TEAM_4, "Team 4"}, {Team::TEAM_5, "Team 5"}, {Team::TEAM_6, "Team 6"},
{Team::TEAM_7, "Team 7"}, {Team::TEAM_8, "Team 8"}, {Team::TEAM_9, "Team 9"},
{Team::GENERAL, "General"}};
std::string teamToString(Team team) {
auto it = teamToStringMap.find(team);
if (it != teamToStringMap.end()) {
return "[" + it->second + "]";
}
return "";
}
std::string logToString(LogLevel logLevel) {
if (logLevel == LogLevel::DEBUG) {
return "(DEBUG) ";
} else if (logLevel == LogLevel::INFO) {
return "(INFO) ";
} else if (logLevel == LogLevel::WARNING) {
return "(WARNING) ";
} else if (logLevel == LogLevel::ERR) {
return "(ERROR) ";
} else {
return "";
}
}
};
#else
#define LOGLINE ""
#define LOG_RELLINE ""
#define LOG_FNC ""
// #define log Log()
class Logger {
public:
template <typename T>
Logger &operator<<(const T & /*value*/) {
return *this;
}
Logger &operator<<(std::ostream &(* /*manipulator*/)(std::ostream &)) { return *this; }
static std::ostream &endl(std::ostream &os) { return os; }
static Logger &Log() {
static Logger instance; // Guaranteed to be initialized only once.
return instance;
}
};
// Logger Logger::log;
#endif
} // namespace clogged