Added constructor with create info struct

This commit is contained in:
matthias@arch 2022-10-14 23:36:02 +02:00
parent 2b1c034a55
commit a58e324d7a
2 changed files with 167 additions and 56 deletions

View File

@ -5,7 +5,6 @@
#include <ctime> #include <ctime>
namespace gz { namespace gz {
namespace fs = std::filesystem; namespace fs = std::filesystem;
const char* COLORS[] = { const char* COLORS[] = {
@ -52,8 +51,8 @@ namespace gz {
#ifdef LOG_MULTITHREAD #ifdef LOG_MULTITHREAD
std::mutex Log::mtx; std::mutex Log::mtx;
#endif #endif
Log::Log(std::string logfile, bool showLog, bool storeLog, std::string&& prefix_, Color prefixColor, Color timeColor, bool clearLogfileOnRestart, unsigned int writeAfterLines) Log::Log(std::string logfile, bool showLog, bool storeLog, std::string&& prefix_, Color prefixColor, bool showTime, Color timeColor, bool clearLogfileOnRestart, unsigned int writeAfterLines)
: iter(0), writeToFileAfterLines(writeAfterLines), showLog(showLog), storeLog(storeLog), prefixColor(prefixColor), prefix(prefix_ + ": "), prefixLength(prefix.size() + LOG_TIMESTAMP_CHAR_COUNT - 1), timeColor(timeColor) { : iter(0), writeToFileAfterLines(writeAfterLines), storeLog(storeLog), showLog(showLog), prefixColor(prefixColor), prefix(prefix_ + ": "), prefixLength(prefix.size() + LOG_TIMESTAMP_CHAR_COUNT - 1), timeColor(timeColor) {
// get absolute path to the logfile // get absolute path to the logfile
fs::path logpath(logfile); fs::path logpath(logfile);
if (!logpath.is_absolute()) { if (!logpath.is_absolute()) {
@ -80,6 +79,59 @@ namespace gz {
} }
} }
if (showTime) {
prefixLength = prefix.size() + LOG_TIMESTAMP_CHAR_COUNT - 1;
}
else {
prefixLength = prefix.size();
}
/* log("Initialising log with settings: logFile: " + logFile + */
/* ", showLog - " + boolToString(showLog) + ", storeLog - " + boolToString(storeLog)); */
}
Log::Log(LogCreateInfo&& ci)
: iter(0),
writeToFileAfterLines(ci.writeAfterLines), storeLog(ci.storeLog),
showLog(ci.showLog),
prefixColor(ci.prefixColor),
prefix(std::move(ci.prefix) + ": "),
showTime(ci.showTime), timeColor(ci.timeColor)
{
// get absolute path to the logfile
fs::path logpath(ci.logfile);
if (!logpath.is_absolute()) {
logpath = fs::current_path() / logpath;
}
// create directory of logfile
if (!fs::is_directory(logpath.parent_path())) {
fs::create_directory(logpath.parent_path());
}
logFile = logpath.string();
// if clearLogfileOnRestart, open the file to clear it
if (ci.clearLogfileOnRestart and fs::is_regular_file(logpath)) {
std::ofstream file(logFile, std::ofstream::trunc);
file.close();
}
if (writeToFileAfterLines == 0) { writeToFileAfterLines = 1; }
logLines.resize(writeToFileAfterLines);
// reserve memory for strings
if (LOG_RESERVE_STRING_SIZE > 0) {
for (size_t i = 0; i < logLines.size(); i++) {
logLines[i].reserve(LOG_RESERVE_STRING_SIZE);
}
}
if (showTime) {
prefixLength = prefix.size() + LOG_TIMESTAMP_CHAR_COUNT - 1;
}
else {
prefixLength = prefix.size();
}
/* log("Initialising log with settings: logFile: " + logFile + */ /* log("Initialising log with settings: logFile: " + logFile + */
/* ", showLog - " + boolToString(showLog) + ", storeLog - " + boolToString(storeLog)); */ /* ", showLog - " + boolToString(showLog) + ", storeLog - " + boolToString(storeLog)); */
} }

View File

@ -63,6 +63,30 @@ namespace gz {
template<typename T> template<typename T>
concept Logable = ConvertibleToString<T>; concept Logable = ConvertibleToString<T>;
/**
* @brief Create info for a Log object
*/
struct LogCreateInfo {
/// @brief Absolute or relative path to the logfile
std::string logfile = "log.log";
/// @brief Wether to print the messages to stdout
bool showLog = true;
/// @brief Wether to save the messages to the logfile
bool storeLog = true;
/// @brief A prefix that comes between the timestamp and the message. ": " is automatically appended to the prefix
std::string prefix = "";
/// @brief The color of the prefix
Color prefixColor = RESET;
/// @brief Wether to prepend a timestamp to the message
bool showTime = true;
/// @brief The color of the timestamp
Color timeColor = RESET;
/// @brief If true, clear the logfile when initializing the log. That means only the log of most recent run is stored
bool clearLogfileOnRestart = true;
/// @brief Actually write the log to the logfile after so many lines. Must be at least 1
unsigned int writeAfterLines = 100;
};
/** /**
* @brief Manages printing messages to stdout and to logfiles. * @brief Manages printing messages to stdout and to logfiles.
* @details * @details
@ -94,23 +118,27 @@ class Log {
public: public:
/** /**
* @brief Creates a log object, which can print messages to stdout and/or write them to a log file * @brief Creates a log object, which can print messages to stdout and/or write them to a log file
* @details By creating multiple instances with different parameters, logs can be easily turned on/off for different usages. * @details
* If not existent, the parent directory of the logfile and the file itself will be created when initializing a log. * By creating multiple instances with different parameters, logs can be easily turned on/off for different usages.
*
* @param logfile: Absolute or relative path to the logfile
* @param showLog: Wether to print the messages to stdout
* @param storeLog: Wether to save the messages to the logfile
* @param prefix: A prefix that comes between the timestamp and the message. ": " is automatically appended to the prefix
* @param prefixColor: The color of the prefix
* @param clearLogfileOnRestart: If true, clear the logfile when initializing the log. That means only the log of most recent run is stored
* @param writeAfterLines: Actually write the log to the logfile after so many lines. Must be at least 1
* *
* The overload using LogCreateInfo might be more clear, so I recommend using that.
* @note Colors will only be shown when written to stdout, not in the logfile. * @note Colors will only be shown when written to stdout, not in the logfile.
* @deprecated Use the overload using the LogCreateInfo struct
*/ */
Log(std::string logfile="log.log", bool showLog=true, bool storeLog=true, std::string&& prefix="", Color prefixColor=RESET, Color timeColor=RESET, bool clearLogfileOnRestart=true, unsigned int writeAfterLines=100); Log(std::string logfile="log.log", bool showLog=true, bool storeLog=true, std::string&& prefix="", Color prefixColor=RESET, bool showTime=true, Color timeColor=RESET, bool clearLogfileOnRestart=true, unsigned int writeAfterLines=100);
/**
* @brief Creates a log object, which can print messages to stdout and/or write them to a log file
* @details
* By creating multiple instances with different parameters, logs can be easily turned on/off for different usages.
*/
Log(LogCreateInfo&& createInfo);
~Log(); ~Log();
//
// ACTUAL LOGGING
//
/** /**
* @brief Logs a message * @brief Logs a message
* @details Depending on the settings of the log instance, the message will be printed to stdout and/or written to the logfile. * @details Depending on the settings of the log instance, the message will be printed to stdout and/or written to the logfile.
@ -125,8 +153,13 @@ class Log {
#ifdef LOG_MULTITHREAD #ifdef LOG_MULTITHREAD
mtx.lock(); mtx.lock();
#endif #endif
getTime(); if (showTime) {
logLines[iter] = time; getTime();
logLines[iter] = time;
}
else {
logLines[iter].clear();
}
logLines[iter] += prefix; logLines[iter] += prefix;
vlog(" ", std::forward<Args>(args)...); vlog(" ", std::forward<Args>(args)...);
logLines[iter] += "\n"; logLines[iter] += "\n";
@ -145,40 +178,6 @@ class Log {
#endif #endif
} }
/**
* @brief Logs a message. Overload for convenience, same behavior as log()
*/
template<Logable... Args>
void operator() (Args&&... args) {
log(std::forward<Args>(args)...);
}
/**
* @brief Log an error
* @details Prints the message with a red "Error: " prefix.
* The message will look like this:
* <time>: <prefix>: Error: <message>
* where time will be white, prefix in prefixColor, Error in red and message white.
* @param args Any number of arguments that satisfy concept Logable
*/
template<Logable... Args>
void error(Args&&... args) {
clog(RED, "Error", WHITE, std::forward<Args>(args)...);
}
/**
* @brief Log a warnign
* @details Prints the message with a yellow "Warning: " prefix.
* The message will look like this:
* <time>: <prefix>: Warning: <message>
* where time will be white, prefix in prefixColor, Warning in yellow and message white.
* @param args Any number of arguments that satisfy concept Logable
*/
template<Logable... Args>
void warning(Args&&... args) {
clog(YELLOW, "Warning", WHITE, std::forward<Args>(args)...);
}
/** /**
* @brief Log a message in a certain color and with a colored type * @brief Log a message in a certain color and with a colored type
* @details * @details
@ -192,8 +191,13 @@ class Log {
#ifdef LOG_MULTITHREAD #ifdef LOG_MULTITHREAD
mtx.lock(); mtx.lock();
#endif #endif
getTime(); if (showTime) {
logLines[iter] = std::string(time); getTime();
logLines[iter] = std::string(time);
}
else {
logLines[iter].clear();
}
logLines[iter] += prefix + type + ": "; logLines[iter] += prefix + type + ": ";
vlog(" ", std::forward<Args>(args)...); vlog(" ", std::forward<Args>(args)...);
logLines[iter] += "\n"; logLines[iter] += "\n";
@ -230,8 +234,13 @@ class Log {
#endif #endif
argsBegin.clear(); argsBegin.clear();
argsBegin.emplace_back(0); argsBegin.emplace_back(0);
getTime(); if (showTime) {
logLines[iter] = std::string(time); getTime();
logLines[iter] = std::string(time);
}
else {
logLines.clear();
}
argsBegin.emplace_back(logLines[iter].size()); argsBegin.emplace_back(logLines[iter].size());
logLines[iter] += prefix; logLines[iter] += prefix;
@ -265,6 +274,44 @@ class Log {
#endif #endif
}; };
//
// CONVENCIENCE
//
/**
* @brief Logs a message. Overload for convenience, same behavior as log()
*/
template<Logable... Args>
void operator() (Args&&... args) {
log(std::forward<Args>(args)...);
}
/**
* @brief Log an error
* @details Prints the message with a red "Error: " prefix.
* The message will look like this:
* <time>: <prefix>: Error: <message>
* where time will be white, prefix in prefixColor, Error in red and message white.
* @param args Any number of arguments that satisfy concept Logable
*/
template<Logable... Args>
void error(Args&&... args) {
clog(RED, "Error", WHITE, std::forward<Args>(args)...);
}
/**
* @brief Log a warnign
* @details Prints the message with a yellow "Warning: " prefix.
* The message will look like this:
* <time>: <prefix>: Warning: <message>
* where time will be white, prefix in prefixColor, Warning in yellow and message white.
* @param args Any number of arguments that satisfy concept Logable
*/
template<Logable... Args>
void warning(Args&&... args) {
clog(YELLOW, "Warning", WHITE, std::forward<Args>(args)...);
}
private: private:
// vlog for variadic log // vlog for variadic log
/// Log anything that can be appendend to std::string /// Log anything that can be appendend to std::string
@ -293,23 +340,35 @@ class Log {
std::vector<std::string::size_type> argsBegin; std::vector<std::string::size_type> argsBegin;
/// The current position in logLines /// The current position in logLines
size_t iter = 0; size_t iter = 0;
/**
* @name Writing to file
*/
/// @{
/// When iter reaches writeToFileAfterLines, write log to file /// When iter reaches writeToFileAfterLines, write log to file
unsigned int writeToFileAfterLines; unsigned int writeToFileAfterLines;
/// Absolute path to the logfile /// Absolute path to the logfile
std::string logFile; std::string logFile;
bool showLog;
bool storeLog; bool storeLog;
void writeLog(); void writeLog();
/// @}
bool showLog;
Color prefixColor; Color prefixColor;
std::string prefix; std::string prefix;
std::string::size_type prefixLength; std::string::size_type prefixLength;
Color timeColor;
/**
* @name Time
*/
/// @{
bool showTime;
Color timeColor;
/// Stores the current time in yyyy-mm-dd hh:mm:ss format /// Stores the current time in yyyy-mm-dd hh:mm:ss format
char time[LOG_TIMESTAMP_CHAR_COUNT]; char time[LOG_TIMESTAMP_CHAR_COUNT];
/// Store the current time in yyyy-mm-dd hh:mm:ss format in time member /// Store the current time in yyyy-mm-dd hh:mm:ss format in time member
void getTime(); void getTime();
/// @}
#ifdef LOG_MULTITHREAD #ifdef LOG_MULTITHREAD
/// Lock for std::cout /// Lock for std::cout
static std::mutex mtx; static std::mutex mtx;