diff --git a/src/log.cpp b/src/log.cpp index fdd286e..ca8adcd 100755 --- a/src/log.cpp +++ b/src/log.cpp @@ -5,7 +5,6 @@ #include namespace gz { - namespace fs = std::filesystem; const char* COLORS[] = { @@ -52,8 +51,8 @@ namespace gz { #ifdef LOG_MULTITHREAD std::mutex Log::mtx; #endif - Log::Log(std::string logfile, bool showLog, bool storeLog, std::string&& prefix_, Color prefixColor, 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) { + 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), storeLog(storeLog), showLog(showLog), prefixColor(prefixColor), prefix(prefix_ + ": "), prefixLength(prefix.size() + LOG_TIMESTAMP_CHAR_COUNT - 1), timeColor(timeColor) { // get absolute path to the logfile fs::path logpath(logfile); 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 + */ /* ", showLog - " + boolToString(showLog) + ", storeLog - " + boolToString(storeLog)); */ } diff --git a/src/log.hpp b/src/log.hpp index d34369d..86f5aa2 100755 --- a/src/log.hpp +++ b/src/log.hpp @@ -63,6 +63,30 @@ namespace gz { template concept Logable = ConvertibleToString; + /** + * @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. * @details @@ -94,23 +118,27 @@ class Log { public: /** * @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. - * If not existent, the parent directory of the logfile and the file itself will be created when initializing a log. - * - * @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 + * @details + * By creating multiple instances with different parameters, logs can be easily turned on/off for different usages. * + * 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. + * @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(); + // + // ACTUAL LOGGING + // /** * @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. @@ -125,8 +153,13 @@ class Log { #ifdef LOG_MULTITHREAD mtx.lock(); #endif - getTime(); - logLines[iter] = time; + if (showTime) { + getTime(); + logLines[iter] = time; + } + else { + logLines[iter].clear(); + } logLines[iter] += prefix; vlog(" ", std::forward(args)...); logLines[iter] += "\n"; @@ -145,40 +178,6 @@ class Log { #endif } - /** - * @brief Logs a message. Overload for convenience, same behavior as log() - */ - template - void operator() (Args&&... args) { - log(std::forward(args)...); - } - - /** - * @brief Log an error - * @details Prints the message with a red "Error: " prefix. - * The message will look like this: - *