From ffc53a7ad58382380dbacc4527ac9cb584c713c1 Mon Sep 17 00:00:00 2001 From: mbandic Date: Fri, 22 Mar 2024 13:50:25 +0000 Subject: [PATCH] Add log level --- README.md | 9 ++++++-- lib/log.hpp | 43 +++++++++++++++++++++++++++++++++---- src/log.cpp | 58 ++++++++++++++++++++++++++++++++++++++++++++------ test/test.cpp | 11 +++++----- test/test.o | Bin 45856 -> 46592 bytes 5 files changed, 104 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index becfe07..014082f 100644 --- a/README.md +++ b/README.md @@ -10,6 +10,7 @@ Logging errors to a file, daily file rotation, date and time stamps. Configurabl - Customizable directory for files - Daily file rotation - Protection of recording consecutive errors +- Log levels - Thread safe - Exceptions - The possibility of printing logs in the console @@ -31,12 +32,16 @@ using namespace marcelb; /** * Initialization and declaration */ -log mylog("../log"); +log mylog("../log", Level::INFO); /** * Put log in file */ -mylog.put("[EVENT] Start loging"); +mylog.debug("Debug loging"); +mylog.info("Info loging"); +mylog.warning("Warning loging"); +mylog.error("Error loging"); +mylog.fatal("Fatal loging"); ``` ## License diff --git a/lib/log.hpp b/lib/log.hpp index 88b98b6..a90ebbb 100644 --- a/lib/log.hpp +++ b/lib/log.hpp @@ -17,11 +17,20 @@ namespace marcelb { using namespace std; +typedef enum { + DEBUG = 0, + INFO, + WARNING, + ERROR, + FATAL, +} Level; + /** * Log class - used at the level of one log directory */ class log { string dir; + Level loglevel; bool isKeepOpen; bool printInConsole; ofstream logfile; @@ -58,7 +67,12 @@ class log { /** * Set log line time prefix */ - void setPrefix(string &logline); + void setPrefix(string &logline, Level &_level); + + /** + * Put string log in file + */ + void put(string logline, Level _level); public: @@ -68,12 +82,33 @@ class log { * optional: a bool variable if it keeps the file open, * and a bool variable if it prints log lines to the console */ - log (string _dir, bool _isKeepOpen = true, bool _printInConsole = false); + log (string _dir, Level loglevel = WARNING, bool _isKeepOpen = true, bool _printInConsole = false); + /** - * Put string log in file + * Debug log line + */ + void debug(string logline); + + /** + * Info log line + */ + void info(string logline); + + /** + * Warning log line + */ + void warning(string logline); + + /** + * Error log line + */ + void error(string logline); + + /** + * Fatal log line */ - void put(string logline); + void fatal(string logline); /** * Destruktor, close log files diff --git a/src/log.cpp b/src/log.cpp index 624b4c1..0bf6bfa 100644 --- a/src/log.cpp +++ b/src/log.cpp @@ -1,7 +1,8 @@ #include "../lib/log.hpp" -marcelb::log::log(string _dir, bool _isKeepOpen, bool _printInConsole) { +marcelb::log::log(string _dir, Level _loglevel, bool _isKeepOpen, bool _printInConsole) { dir = _dir; + loglevel = _loglevel; isKeepOpen = _isKeepOpen; printInConsole = _printInConsole; @@ -42,14 +43,17 @@ void marcelb::log::setMoment() { moment = localtime (&rawtime); } -void marcelb::log::put(string logline) { +void marcelb::log::put(string logline, Level _level) { + if (_level < loglevel) { + return; + } io.lock(); if (printInConsole) { cout << logline << endl; } setMoment(); - setPrefix(logline); + setPrefix(logline, _level); if (day != moment->tm_mday) { if (isKeepOpen && logfile.is_open()) { @@ -90,16 +94,58 @@ void marcelb::log::setPath() { path = dir + to_string(moment->tm_year+1900) + '-' + mon.str() + '-' + _day.str() + ".log"; } -void marcelb::log::setPrefix(string &logline) { +void marcelb::log::setPrefix(string &logline, Level &_level) { stringstream hour, min, sec; hour << setw(2) << setfill('0') << moment->tm_hour; min << setw(2) << setfill('0') << moment->tm_min; sec << setw(2) << setfill('0') << moment->tm_sec; - string _logline = hour.str() + ':' + min.str() + ':' + sec.str() + ' ' + logline; - logline = _logline; + string _logline = hour.str() + ':' + min.str() + ':' + sec.str();// + logline; + switch (_level) { + case DEBUG: + _logline += " [DEBUG] "; + break; + case INFO: + _logline += " [INFO] "; + break; + case WARNING: + _logline += " [WARNING] "; + break; + case ERROR: + _logline += " [ERROR] "; + break; + case FATAL: + _logline += " [FATAL] "; + break; + default: + _logline += " [UNAKOWN] "; + break; + + } + logline = _logline + logline; +} + +void marcelb::log::debug(string logline) { + put(logline, DEBUG); +} + +void marcelb::log::info(string logline) { + put(logline, INFO); } +void marcelb::log::warning(string logline) { + put(logline, WARNING); +} + +void marcelb::log::error(string logline) { + put(logline, ERROR); +} + +void marcelb::log::fatal(string logline) { + put(logline, FATAL); +} + + marcelb::log::~log() { loose(); } diff --git a/test/test.cpp b/test/test.cpp index f609f90..7e27e24 100644 --- a/test/test.cpp +++ b/test/test.cpp @@ -5,13 +5,14 @@ using namespace std; using namespace marcelb; -log mylog("../example", false); +log mylog("../example", Level::FATAL, false); int main() { - -// log mylog("../example", false); - - mylog.put("[EVENT] Start loging"); + mylog.debug("Start debug loging"); + mylog.info("Start info loging"); + mylog.warning("Start warning loging"); + mylog.error("Start error loging"); + mylog.fatal("Start fatal loging"); return 0; } diff --git a/test/test.o b/test/test.o index 5f885335c35fd459e239361e62676fdf4849c8a2..f09cdcbdb066e718a971d581a956c273c5f637e2 100755 GIT binary patch literal 46592 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 delta 11580 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