Added log levels

This commit is contained in:
matthias@arch 2022-10-19 13:05:59 +02:00
parent d52da6976a
commit a5a42e8e77
3 changed files with 257 additions and 101 deletions

View File

@ -1,7 +1,7 @@
# Maintainer: Matthias Quintern <matthiasqui@protonmail.com> # Maintainer: Matthias Quintern <matthiasqui@protonmail.com>
pkgname=gz-cpp-util pkgname=gz-cpp-util
pkgver=1.3 pkgver=1.3
pkgrel=1 pkgrel=2
pkgdesc="Utility library for c++" pkgdesc="Utility library for c++"
arch=('any') arch=('any')
url="https://github.com/MatthiasQuintern/gz-cpp-util" url="https://github.com/MatthiasQuintern/gz-cpp-util"

View File

@ -48,10 +48,12 @@ Replace `firefox` with your web browser
## Changelog ## Changelog
### 2022-10-14 ### 2022-10-19 [1.3.1] [1.3.2]
- Added create info struct constructor to log - Changes to logger (log.hpp):
- Timestamp can be disabled in log - Added create info struct constructor
### 2022-09-26 - Timestamp can be disabled
- Added different log levels that can be turned off/on at compile time
### 2022-09-26 [1.3]
- Added SettingsManager - Added SettingsManager
- Renamed getXXX to getXXXOr - Renamed getXXX to getXXXOr
- Added more type conversion utility - Added more type conversion utility
@ -60,10 +62,10 @@ Replace `firefox` with your web browser
- Logger now uses to_string - Logger now uses to_string
- Restructured files - Restructured files
- Added more documentation - Added more documentation
### 2022-09-17 ### 2022-09-17 [1.2]
- Moved math part to its own repository/library [here](https://github.com/MatthiasQuintern/gzm) - Moved math part to its own repository/library [here](https://github.com/MatthiasQuintern/gzm)
### 2022-09-10 ### 2022-09-10 [1.1]
- Added matrices to math lib - Added matrices to math lib
- Improved logger - Improved logger
### 2022-09-05 ### 2022-09-05 [1.0]
- initial version - initial version

View File

@ -1,7 +1,6 @@
#pragma once #pragma once
#include <vector> #include <vector>
#define LOG_MULTITHREAD
#include "util/string_conversion.hpp" #include "util/string_conversion.hpp"
@ -12,6 +11,19 @@
#include <mutex> #include <mutex>
#endif #endif
// the higher level needs to include the lower ones
#ifdef LOG_LEVEL_3
#define LOG_LEVEL_2
#endif
#ifdef LOG_LEVEL_2
#define LOG_LEVEL_1
#endif
#ifdef LOG_LEVEL_1
#define LOG_LEVEL_0
#endif
namespace gz { namespace gz {
/// Reserve a string size for each string in logArray. Set to 0 if you do not want to reserve memory for strings. /// Reserve a string size for each string in logArray. Set to 0 if you do not want to reserve memory for strings.
constexpr unsigned int LOG_RESERVE_STRING_SIZE = 100; constexpr unsigned int LOG_RESERVE_STRING_SIZE = 100;
@ -101,18 +113,29 @@ namespace gz {
* Alternatively, or if the type is not a class overload <code> std::string toString(const T& t) </code> in global or gz namespace. * Alternatively, or if the type is not a class overload <code> std::string toString(const T& t) </code> in global or gz namespace.
* *
* @subsection log_threads Thread safety * @subsection log_threads Thread safety
* Log can use a static mutex for thread safety. To use this feature, you have to #define LOG_MULTITHREAD at the top of log.hpp. * Log can use a static mutex for thread safety. To use this feature, you have to `#define LOG_MULTITHREAD` @b before including `log.hpp`.
* Note that log uses the default std::cout buffer, so you should make sure it is not being used while logging something. * Note that log uses the default std::cout buffer, so you should make sure it is not being used while logging something.
* *
* @subsection log_logfile Logfile * @subsection log_logfile Logfile
* The logs can be written to a logfile, which can be specified in the constructor. * The logs can be written to a logfile, which can be specified in the constructor.
* The logs are not continuously written to the logfile, since file operations are expensive. * The logs are not continuously written to the logfile, since file operations are expensive.
* Instead, the log is stored in memory and written to the file if a certain number of lines is reached, which you can specify in the constructor. * Instead, the log is stored in memory and written to the file if a certain number of lines is reached, which you can specify in the constructor.
* If you want the the log to be continuously written to the file, set writeAfterLines=1. * If you want the log to be continuously written to the file, set `writeAfterLines` to 1.
*
* @subsection log_levels Loglevels
* There are 4 different log levels (0-3), where the higher ones include the lower ones.
* To set the log level to `X`, where `X` is one of {0, 1, 2, 3},
* define `#define LOG_LEVEL_X` @b before including `log.hpp`.
* You can then use @ref log0 "logX" or @ref clog0 "clogX".
*
* If @ref log0 "logX" function log level is higher than the set log level,
* the function call will be a noop and thus optimized away be the compiler.
*
* @note operator(), log, clog, warning and error are always 'on', regardless of which (if any) log level is defined.
* *
* @todo Exception policies * @todo Exception policies
* @todo Remove vec2 or add vec3, vec4 * @todo Use own ostream and not std::cout
* * @todo Make colors cross platform
*/ */
class Log { class Log {
public: public:
@ -139,6 +162,10 @@ class Log {
// //
// ACTUAL LOGGING // ACTUAL LOGGING
// //
/**
* @name 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.
@ -149,41 +176,7 @@ class Log {
* @param args Any number of arguments that satisfy concept Logable * @param args Any number of arguments that satisfy concept Logable
*/ */
template<Logable... Args> template<Logable... Args>
void log(Args&&... args) { void log(Args&&... args);
#ifdef LOG_MULTITHREAD
mtx.lock();
#endif
argsBegin.clear();
if (showTime) {
getTime();
logLines[iter] = time;
}
else {
logLines.clear();
}
argsBegin.emplace_back(logLines[iter].size());
logLines[iter] += prefix;
vlog(" ", std::forward<Args>(args)...);
logLines[iter] += "\n";
argsBegin.emplace_back(logLines[iter].size());
if (showLog) {
// time
std::cout << COLORS[timeColor] << std::string_view(logLines[iter].begin(), logLines[iter].begin() + argsBegin[0])
// prefix
<< COLORS[prefixColor] << std::string_view(logLines[iter].begin() + argsBegin[0], logLines[iter].begin() + argsBegin[1]) << COLORS[RESET]
// message
<< std::string_view(logLines[iter].begin() + argsBegin[1], logLines[iter].end());
}
if (++iter >= writeToFileAfterLines) {
iter = 0;
writeLog();
}
#ifdef LOG_MULTITHREAD
mtx.unlock();
#endif
}
/** /**
* @brief Log a message in a certain color * @brief Log a message in a certain color
@ -196,46 +189,7 @@ class Log {
* @param colors Vector of colors, where the nth color refers to the nth arg * @param colors Vector of colors, where the nth color refers to the nth arg
*/ */
template<Logable... Args> template<Logable... Args>
void clog(const std::vector<Color>& colors, Args&&... args) { void clog(const std::vector<Color>& colors, Args&&... args);
#ifdef LOG_MULTITHREAD
mtx.lock();
#endif
argsBegin.clear();
if (showTime) {
getTime();
logLines[iter] = std::string(time);
}
else {
logLines.clear();
}
argsBegin.emplace_back(logLines[iter].size());
logLines[iter] += prefix;
vlog(" ", std::forward<Args>(args)...);
logLines[iter] += "\n";
argsBegin.emplace_back(logLines[iter].size());
if (showLog) {
// time
std::cout << COLORS[timeColor] << std::string_view(logLines[iter].begin(), logLines[iter].begin() + argsBegin[0])
// prefix
<< COLORS[prefixColor] << std::string_view(logLines[iter].begin() + argsBegin[0], logLines[iter].begin() + argsBegin[1]) << COLORS[RESET];
// max index where i can be used for colors and i+2 can be used for currentViews
size_t maxI = std::min(colors.size(), argsBegin.size() - 2);
for (size_t i = 0; i < maxI; i++) {
std::cout << COLORS[colors[i]] << std::string_view(logLines[iter].begin() + argsBegin[i+1], logLines[iter].begin() + argsBegin[i+2]);
}
// log the rest, maxI is now <= argsBegin.size() - 2
std::cout << std::string_view(logLines[iter].begin() + argsBegin[maxI+1], logLines[iter].end()) << COLORS[RESET];
}
if (++iter >= writeToFileAfterLines) {
iter = 0;
writeLog();
}
#ifdef LOG_MULTITHREAD
mtx.unlock();
#endif
};
// //
@ -263,7 +217,7 @@ class Log {
} }
/** /**
* @brief Log a warnign * @brief Log a warning
* @details Prints the message with a yellow "Warning: " prefix. * @details Prints the message with a yellow "Warning: " prefix.
* The message will look like this: * The message will look like this:
* <time>: <prefix>: Warning: <message> * <time>: <prefix>: Warning: <message>
@ -274,26 +228,65 @@ class Log {
void warning(Args&&... args) { void warning(Args&&... args) {
clog({YELLOW, WHITE}, "Warning:", std::forward<Args>(args)...); clog({YELLOW, WHITE}, "Warning:", std::forward<Args>(args)...);
} }
/// @}
/**
* @name Logging at different levels
*/
/// @{
/**
* @brief Enabled with LOG_LEVEL_0 or higher
*/
template<Logable... Args>
inline void log0(Args&&... args);
/**
* @brief Enabled with LOG_LEVEL_1 or higher
*/
template<Logable... Args>
inline void log1(Args&&... args);
/**
* @brief Enabled with LOG_LEVEL_2 or higher
*/
template<Logable... Args>
inline void log2(Args&&... args);
/**
* @brief Enabled with LOG_LEVEL_3 or higher
*/
template<Logable... Args>
inline void log3(Args&&... args);
/**
* @brief Enabled with LOG_LEVEL_0 or higher
*/
template<Logable... Args>
inline void clog0(const std::vector<Color>& colors, Args&&... args);
/**
* @brief Enabled with LOG_LEVEL_1 or higher
*/
template<Logable... Args>
inline void clog1(const std::vector<Color>& colors, Args&&... args);
/**
* @brief Enabled with LOG_LEVEL_2 or higher
*/
template<Logable... Args>
inline void clog2(const std::vector<Color>& colors, Args&&... args);
/**
* @brief Enabled with LOG_LEVEL_3 or higher
*/
template<Logable... Args>
inline void clog3(const std::vector<Color>& colors, 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
template<util::Stringy T, Logable... Args> template<util::Stringy T, Logable... Args>
void vlog(const char* appendChars, T&& t, Args&&... args) { void vlog(const char* appendChars, T&& t, Args&&... args);
argsBegin.emplace_back(logLines[iter].size());
logLines[iter] += std::string(t);
logLines[iter] += appendChars;
vlog(" ", std::forward< Args>(args)...);
}
/// Log anything where toString exists /// Log anything where toString exists
template<ConvertibleToString T, Logable... Args> template<ConvertibleToString T, Logable... Args>
void vlog(const char* appendChars, T&& t, Args&&... args) requires (!util::Stringy<T>) { void vlog(const char* appendChars, T&& t, Args&&... args) requires (!util::Stringy<T>);
argsBegin.emplace_back(logLines[iter].size());
logLines[iter] += toString(t);
logLines[iter] += appendChars;
vlog(" ", std::forward< Args>(args)...);
}
/// End for the recursion
void vlog(const char* appendChars) {}; void vlog(const char* appendChars) {};
private: private:
@ -338,6 +331,167 @@ class Log {
static std::mutex mtx; static std::mutex mtx;
#endif #endif
}; // class Log }; // class Log
//
// DEFINITIONS
//
template<Logable... Args>
void Log::log(Args&&... args) {
#ifdef LOG_MULTITHREAD
mtx.lock();
#endif
argsBegin.clear();
if (showTime) {
getTime();
logLines[iter] = time;
}
else {
logLines.clear();
}
argsBegin.emplace_back(logLines[iter].size());
logLines[iter] += prefix;
vlog(" ", std::forward<Args>(args)...);
logLines[iter] += "\n";
argsBegin.emplace_back(logLines[iter].size());
if (showLog) {
// time
std::cout << COLORS[timeColor] << std::string_view(logLines[iter].begin(), logLines[iter].begin() + argsBegin[0])
// prefix
<< COLORS[prefixColor] << std::string_view(logLines[iter].begin() + argsBegin[0], logLines[iter].begin() + argsBegin[1]) << COLORS[RESET]
// message
<< std::string_view(logLines[iter].begin() + argsBegin[1], logLines[iter].end());
}
if (++iter >= writeToFileAfterLines) {
iter = 0;
writeLog();
}
#ifdef LOG_MULTITHREAD
mtx.unlock();
#endif
}
template<Logable... Args>
void Log::clog(const std::vector<Color>& colors, Args&&... args) {
#ifdef LOG_MULTITHREAD
mtx.lock();
#endif
argsBegin.clear();
if (showTime) {
getTime();
logLines[iter] = std::string(time);
}
else {
logLines.clear();
}
argsBegin.emplace_back(logLines[iter].size());
logLines[iter] += prefix;
vlog(" ", std::forward<Args>(args)...);
logLines[iter] += "\n";
argsBegin.emplace_back(logLines[iter].size());
if (showLog) {
// time
std::cout << COLORS[timeColor] << std::string_view(logLines[iter].begin(), logLines[iter].begin() + argsBegin[0])
// prefix
<< COLORS[prefixColor] << std::string_view(logLines[iter].begin() + argsBegin[0], logLines[iter].begin() + argsBegin[1]) << COLORS[RESET];
// max index where i can be used for colors and i+2 can be used for currentViews
size_t maxI = std::min(colors.size(), argsBegin.size() - 2);
for (size_t i = 0; i < maxI; i++) {
std::cout << COLORS[colors[i]] << std::string_view(logLines[iter].begin() + argsBegin[i+1], logLines[iter].begin() + argsBegin[i+2]);
}
// log the rest, maxI is now <= argsBegin.size() - 2
std::cout << std::string_view(logLines[iter].begin() + argsBegin[maxI+1], logLines[iter].end()) << COLORS[RESET];
}
if (++iter >= writeToFileAfterLines) {
iter = 0;
writeLog();
}
#ifdef LOG_MULTITHREAD
mtx.unlock();
#endif
};
template<util::Stringy T, Logable... Args>
void Log::vlog(const char* appendChars, T&& t, Args&&... args) {
argsBegin.emplace_back(logLines[iter].size());
logLines[iter] += std::string(t);
logLines[iter] += appendChars;
vlog(" ", std::forward<Args>(args)...);
}
/// Log anything where toString exists
template<ConvertibleToString T, Logable... Args>
void Log::vlog(const char* appendChars, T&& t, Args&&... args) requires (!util::Stringy<T>) {
argsBegin.emplace_back(logLines[iter].size());
logLines[iter] += toString(t);
logLines[iter] += appendChars;
vlog(" ", std::forward<Args>(args)...);
}
template<Logable... Args>
inline void Log::log0(Args&&... args) {
#ifdef LOG_LEVEL_0
this->log(std::forward<Args>(args)...);
#endif
}
template<Logable... Args>
inline void Log::log1(Args&&... args) {
#ifdef LOG_LEVEL_1
this->log(std::forward<Args>(args)...);
#endif
}
template<Logable... Args>
inline void Log::log2(Args&&... args) {
#ifdef LOG_LEVEL_2
this->log(std::forward<Args>(args)...);
#endif
}
template<Logable... Args>
inline void Log::log3(Args&&... args) {
#ifdef LOG_LEVEL_3
this->log(std::forward<Args>(args)...);
#endif
}
template<Logable... Args>
inline void Log::clog0(const std::vector<Color>& colors, Args&&... args) {
#ifdef LOG_LEVEL_0
this->clog(colors, std::forward<Args>(args)...);
#endif
}
template<Logable... Args>
inline void Log::clog1(const std::vector<Color>& colors, Args&&... args) {
#ifdef LOG_LEVEL_1
this->clog(colors, std::forward<Args>(args)...);
#endif
}
template<Logable... Args>
inline void Log::clog2(const std::vector<Color>& colors, Args&&... args) {
#ifdef LOG_LEVEL_2
this->clog(colors, std::forward<Args>(args)...);
#endif
}
template<Logable... Args>
inline void Log::clog3(const std::vector<Color>& colors, Args&&... args) {
#ifdef LOG_LEVEL_3
this->clog(colors, std::forward<Args>(args)...);
#endif
}
} // namespace gz } // namespace gz
/** /**