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>
pkgname=gz-cpp-util
pkgver=1.3
pkgrel=1
pkgrel=2
pkgdesc="Utility library for c++"
arch=('any')
url="https://github.com/MatthiasQuintern/gz-cpp-util"

View File

@ -48,10 +48,12 @@ Replace `firefox` with your web browser
## Changelog
### 2022-10-14
- Added create info struct constructor to log
- Timestamp can be disabled in log
### 2022-09-26
### 2022-10-19 [1.3.1] [1.3.2]
- Changes to logger (log.hpp):
- Added create info struct constructor
- Timestamp can be disabled
- Added different log levels that can be turned off/on at compile time
### 2022-09-26 [1.3]
- Added SettingsManager
- Renamed getXXX to getXXXOr
- Added more type conversion utility
@ -60,10 +62,10 @@ Replace `firefox` with your web browser
- Logger now uses to_string
- Restructured files
- 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)
### 2022-09-10
### 2022-09-10 [1.1]
- Added matrices to math lib
- Improved logger
### 2022-09-05
### 2022-09-05 [1.0]
- initial version

View File

@ -1,7 +1,6 @@
#pragma once
#include <vector>
#define LOG_MULTITHREAD
#include "util/string_conversion.hpp"
@ -12,6 +11,19 @@
#include <mutex>
#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 {
/// 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;
@ -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.
*
* @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.
*
* @subsection log_logfile Logfile
* 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.
* 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 Remove vec2 or add vec3, vec4
*
* @todo Use own ostream and not std::cout
* @todo Make colors cross platform
*/
class Log {
public:
@ -139,6 +162,10 @@ class Log {
//
// ACTUAL LOGGING
//
/**
* @name 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.
@ -149,41 +176,7 @@ class Log {
* @param args Any number of arguments that satisfy concept Logable
*/
template<Logable... 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
}
void log(Args&&... args);
/**
* @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
*/
template<Logable... 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
};
void clog(const std::vector<Color>& colors, Args&&... args);
//
@ -263,7 +217,7 @@ class Log {
}
/**
* @brief Log a warnign
* @brief Log a warning
* @details Prints the message with a yellow "Warning: " prefix.
* The message will look like this:
* <time>: <prefix>: Warning: <message>
@ -274,26 +228,65 @@ class Log {
void warning(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:
// vlog for variadic log
/// Log anything that can be appendend to std::string
template<util::Stringy T, Logable... 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)...);
}
void vlog(const char* appendChars, T&& t, Args&&... args);
/// Log anything where toString exists
template<ConvertibleToString T, Logable... Args>
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)...);
}
void vlog(const char* appendChars, T&& t, Args&&... args) requires (!util::Stringy<T>);
/// End for the recursion
void vlog(const char* appendChars) {};
private:
@ -338,6 +331,167 @@ class Log {
static std::mutex mtx;
#endif
}; // 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
/**