/** * @Project: Mercury * @Description: Lightweight & Colorful Singleton logger * @Version: 1.0.0 * * This is a single header lib, get the latest build from the following * link. Include this file in your project to start using Mercury! * https://raw.githubusercontent.com/dgisolfi/Mercury/master/single_include/mercury.hpp * * @Date: 2020-7-20 * @Author Daniel Nicolas Gisolfi * @License: MIT * @Contact: Daniel.Gisolfi1@marist.edu * @Website: https://dgisolfi.xyz * @Copyright Copyright © Daniel Gisolfi 2020 - Present */ #pragma once #ifndef MERCURY_HPP #define MERCURY_HPP #include <iostream> #include <time.h> #include <string> #include <stdexcept> #define LEVEL_TRACE 0 #define LEVEL_DEBUG 1 #define LEVEL_INFO 2 #define LEVEL_WARN 3 #define LEVEL_CRITICAL 4 #define LEVEL_ERR 5 #define LEVEL_OFF 6 namespace mercury { enum Level { trace = LEVEL_TRACE, debug = LEVEL_DEBUG, info = LEVEL_INFO, warn = LEVEL_WARN, critical = LEVEL_CRITICAL, err = LEVEL_ERR, off = LEVEL_OFF }; const std::string level_names[7] = { /* * I have added the needed spaces to make the * names line up vertically even if the max * length is set * */ "TRACE ", "DEBUG ", "INFO ", "WARN ", "CRITICAL", "ERROR ", "OFF " }; }; namespace mercury { /** * A two value vector for storing theme modifers */ struct Vector2 { int color; int style; }; /** * Implementation of a Theme * * The theme class stores all colors and style changes to * each logging levels messages. It also stores the seperator characters * and the additional settings about the look of the logs */ class Theme { private: Vector2 trace; Vector2 debug; Vector2 info; Vector2 warn; Vector2 critical; Vector2 error; std::string seperator; bool is_timestamp_visible; int level_name_len; public: Theme() : trace {34, 0}, // blue, no style debug {36, 0}, // cyan, no style info {37, 0}, // white, no style warn {33, 1}, // yellow, bold critical {35, 1}, // magenta, bold error {31, 1}, // red, bold seperator(" - "), is_timestamp_visible(true), level_name_len(4) {} ~Theme(){} /** * Get the Vector2 struct that defines the style modifiers * for the trace logging level * * @returns Vector2 Trace Level Theme */ Vector2 getTrace(); /** * Set the Vector2 struct that defines the style modifiers * for the trace logging level * * @param Vector2 Trace Level Theme */ void setTrace(Vector2 v); /** * Get the Vector2 struct that defines the style modifiers * for the debug logging level * * @returns Vector2 Debug Level Theme */ Vector2 getDebug(); /** * Set the Vector2 struct that defines the style modifiers * for the debug logging level * * @param Vector2 Debug Level Theme */ void setDebug(Vector2 v); /** * Get the Vector2 struct that defines the style modifiers * for the info logging level * * @returns Vector2 Info Level Theme */ Vector2 getInfo(); /** * Set the Vector2 struct that defines the style modifiers * for the info logging level * * @param Vector2 Info Level Theme */ void setInfo(Vector2 v); /** * Get the Vector2 struct that defines the style modifiers * for the warn logging level * * @returns Vector2 Warn Level Theme */ Vector2 getWarn(); /** * Set the Vector2 struct that defines the style modifiers * for the warn logging level * * @param Vector2 Warn Level Theme */ void setWarn(Vector2 v); /** * Get the Vector2 struct that defines the style modifiers * for the critical logging level * * @returns Vector2 Critical Level Theme */ Vector2 getCritical(); /** * Set the Vector2 struct that defines the style modifiers * for the critical logging level * * @param Vector2 Critical Level Theme */ void setCritical(Vector2 v); /** * Get the Vector2 struct that defines the style modifiers * for the error logging level * * @returns Vector2 Error Level Theme */ Vector2 getError(); /** * Set the Vector2 struct that defines the style modifiers * for the error logging level * * @param Vector2 Error Level Theme */ void setError(Vector2 v); /** * Set string that be used to seperate components of a log * * @param std::string log component seperator */ void setSeperator(std::string s); /** * Get the string that is used to seperate components * of a log * * @returns std::string log component seperator */ std::string getSeperator(); /** * Gets the theme for a given level * * @param Level level to find theme for * * @returns Vector2 theme of specified level */ Vector2 getLevelTheme(Level l); /** * Sets boolean for timestamp visibility * * @param is_visible boolean value to set visibility to */ void setIsTimestampVisibile(bool is_visible); /** * Gets the theme for a given level * * @returns Bool visibility */ bool getIsTimestampVisibile(); /** * Sets the length of the Level Name in the output * * @throws invalid_argument Length must be between 1 and 8 * * @params Int number of characters desired */ void setLevelNameLen(int len); /** * Gets the length of the Level Name in the output * * @returns Int length in number of characters */ int getLevelNameLen(); /** * Applys the theme to a log * * Will only apply a theme if the platform is unix like * Otherwise will return the given string, unmodified * * @params Level the level of the log * @params std::string The string to be styled * * @returns std::string the final log */ std::string apply(Level l, std::string s); }; }; namespace mercury { /** * Implementation of a singleton logger * * The logger class supports 6 logging levels and the off level. In * Addition the output can be styled using the Theme class. */ class Logger { private: Logger(): level(Level::debug) { theme = new Theme(); log(Level::debug, "Mercury Enabled"); } Logger(Level l): level(l) { theme = new Theme(); log(Level::debug, "Mercury Enabled"); } ~Logger() { delete theme; } Level level; // The single instance static Logger mercury; Theme *theme; /** * Logs messages according to Logging Level. * * @param level - A Level enum value * @param msg - The msg to be logged */ void log(Level level, std::string msg); /** * Gets current time in H:M:S format. * * @returns time - a string of the current time. */ const std::string lTime(); /** * Builds the final log * * Handles the timestamp and Level Name length application * to the log * * @param level - A Level enum value * @param msg - The msg to be logged * * @returns the final log message */ const std::string buildLog(Level level, std::string msg); /** * Checks if a level is within a range of levels * * * @param low The low end of the range * @param high The high end of the range * @param l The level to check * * @returns wether l is within the given range */ const bool inLevel(int low, int high, int l); public: // mark the copy constructor to delete Logger(const Logger&) = delete; /** * Gets the singleton instance of mercury * * @returns the single instance of mercury */ static Logger& get(); /** * Gets the Level name * * @param level * * @returns string name of Level */ std::string getLevelName(Level level); /** * Gets the current logging level * * @returns Level */ Level getLevel(); /** * Sets the current logging level * * @param l the level to be set */ void setLevel(Level l); /** * Gets the pointer to Mercury's theme object * * @returns Theme pointer to theme */ Theme *getTheme(); /** * Logs a message at the trace Logging Level * * @params msg message to be logged at applicable level */ void trace(std::string msg); /** * Logs a message at the debug Logging Level * * @params msg message to be logged at applicable level */ void debug(std::string msg); /** * Logs a message at the info Logging Level * * @params msg message to be logged at applicable level */ void info(std::string msg); /** * Logs a message at the warn Logging Level * * @params msg message to be logged at applicable level */ void warn(std::string msg); /** * Logs a message at the critical Logging Level * * @params msg message to be logged at applicable level */ void critical(std::string msg); /** * Logs a message at the error Logging Level and exits program * * @params msg message to be logged at applicable level */ void error(std::string msg); /** * Disables Logging */ void off(); }; }; #endif // MERCURY_HPP #ifdef _WIN64 #define THEME_SUPPORT false #elif _WIN32 #define THEME_SUPPORT false #else #define THEME_SUPPORT true #endif namespace mercury { Vector2 Theme::getTrace() { return Theme::trace; }; void Theme::setTrace(Vector2 v) { Theme::trace = v; }; Vector2 Theme::getDebug() { return Theme::debug; }; void Theme::setDebug(Vector2 v){ Theme::debug = v; }; Vector2 Theme::getInfo() { return Theme::info; }; void Theme::setInfo(Vector2 v) { Theme::info = v; }; Vector2 Theme::getWarn() { return Theme::warn; }; void Theme::setWarn(Vector2 v) { Theme::warn = v; }; Vector2 Theme::getCritical() { return Theme::critical; }; void Theme::setCritical(Vector2 v) { Theme::critical = v; }; Vector2 Theme::getError() { return Theme::error; }; void Theme::setError(Vector2 v) { Theme::error = v; }; void Theme::setSeperator(std::string s) { Theme::seperator = s; }; std::string Theme::getSeperator() { return Theme::seperator; }; Vector2 Theme::getLevelTheme(Level l) { Vector2 t; switch (l){ case Level::trace: t = Theme::getTrace(); break; case Level::debug: t = Theme::getDebug(); break; case Level::info: t = Theme::getInfo(); break; case Level::warn: t = Theme::getWarn(); break; case Level::critical: t = Theme::getCritical(); break; case Level::err: t = Theme::getError(); break; default: t = Theme::getInfo(); break; } return t; }; void Theme::setIsTimestampVisibile(bool is_visible){ Theme::is_timestamp_visible = is_visible; }; bool Theme::getIsTimestampVisibile(){ return Theme::is_timestamp_visible; }; void Theme::setLevelNameLen(int len) { if (len > 8 || len < 1) { throw std::invalid_argument("Length must be between 1 and 8"); } else { Theme::level_name_len = len; }; }; int Theme::getLevelNameLen() { return Theme::level_name_len; }; std::string Theme::apply(Level l, std::string s) { std::string o; if (THEME_SUPPORT) { Vector2 t = Theme::getLevelTheme(l); o += "\033["; o += std::to_string(t.style) + ";"; o += std::to_string(t.color) + "m"; o += s; o += "\033[0m"; } else { o = s; } return o; }; }; namespace mercury { /* * PRIVATE */ void Logger::log(Level level, std::string msg){ if (Logger::getLevel() != Level::off) { /* * info = [ "INFO", "WARN", "CRITICAL"] * debug = info + [ "DEBUG" ] * trace = debug + [ "TRACE" ] * err => throws error and exits program * off => disables logging */ if (Logger::inLevel(Logger::getLevel(), Level::err, level)) { std::cout << Logger::buildLog(level, msg) << std::endl; } }; }; const std::string Logger::lTime() { time_t now = time(0); struct tm tstruct; char buf[80]; tstruct = *localtime(&now); strftime(buf, sizeof(buf), "%X", &tstruct); return buf; } const std::string Logger::buildLog(Level level, std::string msg) { Theme *t = Logger::getTheme(); std::string log; if (t -> getIsTimestampVisibile()) { log += Logger::lTime() + t -> getSeperator(); }; log += Logger::getLevelName(level).substr(0, t -> getLevelNameLen()) + t -> getSeperator(); log += msg; return t -> apply(level, log); } const bool Logger::inLevel(int low, int high, int l) { return ((l-high)*(l-low) <= 0); }; /* * PUBLIC */ // Create the single instance of the logger Logger Logger::mercury; Logger& Logger::get() { return mercury; }; std::string Logger::getLevelName(Level level) { return level_names[level]; }; Level Logger::getLevel() { return Logger::level; }; void Logger::setLevel(Level l) { Logger::level = l; }; Theme *Logger::getTheme() { return Logger::theme; }; void Logger::trace(std::string msg) { Logger::log(Level::trace, msg); }; void Logger::debug(std::string msg) { Logger::log(Level::debug, msg); }; void Logger::info(std::string msg) { Logger::log(Level::info, msg); }; void Logger::warn(std::string msg) { Logger::log(Level::warn, msg); }; void Logger::critical(std::string msg) { Logger::log(Level::critical, msg); }; void Logger::error(std::string msg) { Logger::log(Level::err, msg); exit(EXIT_FAILURE); }; void Logger::off() { Logger::setLevel(Level::off); Logger::log(Level::debug, "Mercury Disabled"); }; };