Lots of improvements
Log can now log any type for which to_string() exists Path to the logfile can now be specified, log attempts to create missing directories. Added option to clear logfile at start Added more documentation.
This commit is contained in:
parent
147f3aa4c0
commit
a8ec1fbc10
58
src/log.cpp
58
src/log.cpp
@ -4,9 +4,10 @@
|
|||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <ctime>
|
#include <ctime>
|
||||||
|
|
||||||
#include <SFML/System/Vector2.hpp>
|
|
||||||
|
|
||||||
namespace gz {
|
namespace gz {
|
||||||
|
|
||||||
|
namespace fs = std::filesystem;
|
||||||
|
|
||||||
const char* COLORS[] = {
|
const char* COLORS[] = {
|
||||||
"\033[0m", // RESET
|
"\033[0m", // RESET
|
||||||
"\033[30m", // BLACK
|
"\033[30m", // BLACK
|
||||||
@ -31,38 +32,65 @@ 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)
|
Log::Log(std::string logfile, bool showLog, bool storeLog, std::string&& prefix_, Color prefixColor, bool clearLogfileOnRestart, unsigned int writeAfterLines)
|
||||||
: showLog(showLog), storeLog(storeLog), prefixColor(prefixColor), prefix(prefix_ + ": "), prefixLength(prefix.size() + TIMESTAMP_CHAR_COUNT - 1) {
|
: showLog(showLog), storeLog(storeLog), prefixColor(prefixColor), prefix(prefix_ + ": "), prefixLength(prefix.size() + LOG_TIMESTAMP_CHAR_COUNT - 1), writeToFileAfterLines(writeAfterLines) {
|
||||||
// store the absolute path to the logfile
|
// get absolute path to the logfile
|
||||||
logFile = std::string(std::filesystem::current_path().parent_path()) + "/logs/" + logfile;
|
fs::path logpath(logfile);
|
||||||
log("Initialising log with settings: logFile: " + logFile +
|
if (!logpath.is_absolute()) {
|
||||||
", showLog - " + boolToString(showLog) + ", storeLog - " + boolToString(storeLog));
|
logpath = fs::current_path() / logpath;
|
||||||
}
|
}
|
||||||
|
// create directory of logfile
|
||||||
|
if (!fs::is_directory(logpath.parent_path())) {
|
||||||
|
fs::create_directory(logpath.parent_path());
|
||||||
|
}
|
||||||
|
logFile = std::move(logpath.string());
|
||||||
|
|
||||||
|
// if clearLogfileOnRestart, open the file to clear it
|
||||||
|
if (clearLogfileOnRestart and fs::is_regular_file(logfile)) {
|
||||||
|
std::ofstream file(logFile, std::ofstream::trunc);
|
||||||
|
file.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (writeToFileAfterLines == 0) { writeToFileAfterLines = 1; }
|
||||||
|
logLines.resize(writeAfterLines);
|
||||||
|
// 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* log("Initialising log with settings: logFile: " + logFile + */
|
||||||
|
/* ", showLog - " + boolToString(showLog) + ", storeLog - " + boolToString(storeLog)); */
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
Log::~Log() {
|
Log::~Log() {
|
||||||
if (storeLog) { writeLog(); }
|
if (storeLog) { writeLog(); }
|
||||||
}
|
}
|
||||||
|
|
||||||
char* Log::getTime() {
|
|
||||||
|
void Log::getTime() {
|
||||||
std::time_t t = std::time(0);
|
std::time_t t = std::time(0);
|
||||||
struct std::tm *tmp;
|
struct std::tm *tmp;
|
||||||
tmp = std::localtime(&t);
|
tmp = std::localtime(&t);
|
||||||
|
|
||||||
//returs the date and time: yyyy-mm-dd hh:mm:ss:
|
// stores the date and time in time: yyyy-mm-dd hh:mm:ss:
|
||||||
std::strftime(time, sizeof(time), "%F %T: ", tmp);
|
std::strftime(time, sizeof(time), "%F %T: ", tmp);
|
||||||
return time;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Log::writeLog() {
|
void Log::writeLog() {
|
||||||
std::ofstream file(logFile);
|
std::ofstream file(logFile);
|
||||||
if (file.is_open()) {
|
if (file.is_open()) {
|
||||||
for (std::string message : logArray) {
|
for (std::string message : logLines) {
|
||||||
file << message;
|
file << message;
|
||||||
}
|
}
|
||||||
std::string message = getTime();
|
getTime();
|
||||||
|
std::string message = time;
|
||||||
message += "Written log to file: " + logFile + "\n";
|
message += "Written log to file: " + logFile + "\n";
|
||||||
file << message;
|
/* file << message; */
|
||||||
std::cout << message;
|
if (showLog) { std::cout << message; }
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
std::cout << COLORS[RED] << "LOG ERROR: " << COLORS[RESET] << "Could not open file '" << logFile << "'." << '\n';
|
std::cout << COLORS[RED] << "LOG ERROR: " << COLORS[RESET] << "Could not open file '" << logFile << "'." << '\n';
|
||||||
|
192
src/log.hpp
192
src/log.hpp
@ -7,40 +7,50 @@
|
|||||||
#include <concepts>
|
#include <concepts>
|
||||||
#include <ranges>
|
#include <ranges>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#ifdef LOG_MULTITHREAD
|
#ifdef LOG_MULTITHREAD
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#endif
|
#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.
|
||||||
|
constexpr unsigned int LOG_RESERVE_STRING_SIZE = 100;
|
||||||
|
|
||||||
|
constexpr unsigned int LOG_TIMESTAMP_CHAR_COUNT = 22;
|
||||||
|
constexpr unsigned int LOG_POSTPREFIX_CHAR_COUNT = 2;
|
||||||
|
|
||||||
|
|
||||||
inline const char* boolToString(bool b) {
|
inline const char* boolToString(bool b) {
|
||||||
return b ? "true" : "false";
|
return b ? "true" : "false";
|
||||||
}
|
}
|
||||||
|
|
||||||
const int logLength = 100;
|
|
||||||
|
|
||||||
constexpr unsigned int TIMESTAMP_CHAR_COUNT = 22;
|
|
||||||
constexpr unsigned int POSTPREFIX_CHAR_COUNT = 2;
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// CONCEPTS
|
// CONCEPTS
|
||||||
//
|
//
|
||||||
/// is std::string or convertible to std::string
|
/// is appendable to std::string
|
||||||
template<typename T>
|
template<typename T>
|
||||||
concept Stringy = std::same_as<T, std::string> || std::convertible_to<T, std::string_view>;
|
/* concept Stringy = std::same_as<T, std::string> || std::convertible_to<T, std::string_view>; */
|
||||||
|
concept Stringy = requires(T t, std::string s) { s += t; };
|
||||||
|
|
||||||
/// has .to_string() member
|
/// has .to_string() member
|
||||||
template<typename T>
|
template<typename T>
|
||||||
concept HasToString = !Stringy<T> && requires(T t) { { t.to_string() }-> Stringy; };
|
concept HasToString = !Stringy<T> && requires(T t) { { t.to_string() }-> Stringy; };
|
||||||
|
|
||||||
|
/// an overload of Stringy to_string(const T&) exists in global or gz namespace
|
||||||
|
template<typename T>
|
||||||
|
concept ExistsToString = !Stringy<T> && !HasToString<T> && requires(const T& t) { { to_string(t) } -> Stringy; };
|
||||||
|
|
||||||
/// works with std::to_string(), except bool
|
/// works with std::to_string(), except bool
|
||||||
template<typename T>
|
template<typename T>
|
||||||
concept WorksToString = !std::same_as<T, bool> && !Stringy<T> && !HasToString<T> && requires(T t) { { std::to_string(t) } -> Stringy; };
|
concept WorksWithStdToString = !std::same_as<T, bool> && !Stringy<T> && !HasToString<T> && !ExistsToString<T> && requires(T t) { { std::to_string(t) } -> Stringy; };
|
||||||
|
|
||||||
/// string-like, has .to_string() member, works with std::to_string() or bool
|
/// string-like, has .to_string() member, to_string(const T&) exits, works with std::to_string() or bool
|
||||||
template<typename T>
|
template<typename T>
|
||||||
concept PrintableNoPtr = Stringy<T> || HasToString<T> || WorksToString<T> || std::same_as<T, bool>;
|
concept PrintableNoPtr = Stringy<T> || HasToString<T> || ExistsToString<T> || WorksWithStdToString<T> || std::same_as<T, bool>;
|
||||||
|
|
||||||
|
/// Everything from PrintableNoPtr but "behind" a pointer
|
||||||
template<typename T>
|
template<typename T>
|
||||||
concept Printable = PrintableNoPtr<T> || requires(T t) { { *(t.get()) } -> PrintableNoPtr; };
|
concept Printable = PrintableNoPtr<T> || requires(T t) { { *(t.get()) } -> PrintableNoPtr; };
|
||||||
|
|
||||||
@ -88,14 +98,17 @@ namespace gz {
|
|||||||
* @brief Define types that can be logged with Log
|
* @brief Define types that can be logged with Log
|
||||||
* @details
|
* @details
|
||||||
* As of now you can log type T with instance t:
|
* As of now you can log type T with instance t:
|
||||||
* -# Any string-like type
|
* -# Any @ref Stringy "string-like type": eg. std::string, std::string_view
|
||||||
* -# Any type that works with std::to_string()
|
* -# Any @ref WorksWithStdToString "type that works with std::to_string()"
|
||||||
* -# Any type that has a to_string() member that returns a string
|
* -# Any @ref ExistsToString "type for which an overload of" <code>Stringy to_string(const T&)</code> exists in global or gz namespace
|
||||||
* -# Any type with t.x and t.y, provided t.x and t.y satisfy one of 1-3
|
* -# Any @ref HasToString "type that has a to_string() const member that returns a string"
|
||||||
* -# Any type with t.first, t.second provided t.first satisfies one of 1-3 and t.second satisfies 1-4
|
* -# Any @ref Vector2Printable "type with t.x and t.y", provided t.x and t.y satisfy one of 1-3
|
||||||
* -# Any type that has a forward_iterator which references any one of 1-5
|
* -# Any @ref PairPrintable "type with t.first, t.second" provided t.first satisfies one of 1-3 and t.second satisfies 1-4
|
||||||
|
* -# Any @ref ContainerPrintable "type that has a forward_iterator" which references any one of 1-5
|
||||||
*
|
*
|
||||||
* 1-6 include for example:
|
* The higher number takes precedence in overload resolution for the log function.
|
||||||
|
*
|
||||||
|
* 1-7 include for example:
|
||||||
* - int, float, bool...
|
* - int, float, bool...
|
||||||
* - std::vector<std::string>, std::list<unsigned int>
|
* - std::vector<std::string>, std::list<unsigned int>
|
||||||
* - std::map<A, vec2<float>> if A.to_string() returns a string
|
* - std::map<A, vec2<float>> if A.to_string() returns a string
|
||||||
@ -104,31 +117,51 @@ namespace gz {
|
|||||||
template<typename T>
|
template<typename T>
|
||||||
concept Logable = LogableNotPointer<T> || LogableSmartPointer<T>;
|
concept Logable = LogableNotPointer<T> || LogableSmartPointer<T>;
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
class vec2; // defined in gz_math.hpp
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Manages printing messages to stdout and to logfiles.
|
* @brief Manages printing messages to stdout and to logfiles.
|
||||||
* @details
|
* @details
|
||||||
|
* @subsection log_concepts Logable types
|
||||||
|
* Log uses concepts to determine if a type is logable and how it should be logged. See the documentation for concept Logable for more details.
|
||||||
|
*
|
||||||
|
* If you want your custom data type to be logable, it easiest to provide a member function with this signature:
|
||||||
|
* @code
|
||||||
|
* public:
|
||||||
|
* std::string to_string() const;
|
||||||
|
* @endcode
|
||||||
|
* Alternatively, or if the type is not a class overload <code> std::string to_string(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 at the top of 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
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* @todo Exception policies
|
||||||
|
* @todo Remove vec2 or add vec3, vec4
|
||||||
|
*
|
||||||
*/
|
*/
|
||||||
class Log {
|
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 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: Name of the file in the logs folder
|
* @param logfile: Absolute or relative path to the logfile
|
||||||
* @param showLog: Wether to print the messages to stdout
|
* @param showLog: Wether to print the messages to stdout
|
||||||
* @param storeLog: Wether to save the messages to the logfile
|
* @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 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 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
|
||||||
*
|
*
|
||||||
* @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.
|
||||||
*/
|
*/
|
||||||
Log(std::string logfile="log.log", bool showLog=true, bool storeLog=true, std::string&& prefix="", Color prefixColor=RESET);
|
Log(std::string logfile="log.log", bool showLog=true, bool storeLog=true, std::string&& prefix="", Color prefixColor=RESET, bool clearLogfileOnRestart=true, unsigned int writeAfterLines=100);
|
||||||
|
|
||||||
~Log();
|
~Log();
|
||||||
|
|
||||||
@ -140,22 +173,21 @@ class Log {
|
|||||||
* <time>: <prefix>: <message>
|
* <time>: <prefix>: <message>
|
||||||
* where time will be white, prefix in prefixColor and message white.
|
* where time will be white, prefix in prefixColor and message white.
|
||||||
* @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
|
#ifdef LOG_MULTITHREAD
|
||||||
mtx.lock();
|
mtx.lock();
|
||||||
#endif
|
#endif
|
||||||
logArray[iter] = getTime();
|
logLines[iter] = getTime();
|
||||||
logArray[iter] += prefix;
|
logLines[iter] += prefix;
|
||||||
vlog(" ", std::forward<Args>(args)...);
|
vlog(" ", std::forward<Args>(args)...);
|
||||||
logArray[iter] += "\n";
|
logLines[iter] += "\n";
|
||||||
|
|
||||||
std::cout << std::string_view(logArray[iter].c_str(), TIMESTAMP_CHAR_COUNT - 1) <<
|
std::cout << std::string_view(logLines[iter].c_str(), LOG_TIMESTAMP_CHAR_COUNT - 1) <<
|
||||||
COLORS[prefixColor] << prefix << COLORS[RESET] <<
|
COLORS[prefixColor] << prefix << COLORS[RESET] <<
|
||||||
std::string_view(logArray[iter].begin() + prefixLength, logArray[iter].end());
|
std::string_view(logLines[iter].begin() + prefixLength, logLines[iter].end());
|
||||||
if (++iter >= logLength) {
|
if (++iter >= writeToFileAfterLines) {
|
||||||
iter = 0;
|
iter = 0;
|
||||||
writeLog();
|
writeLog();
|
||||||
}
|
}
|
||||||
@ -211,16 +243,17 @@ class Log {
|
|||||||
#ifdef LOG_MULTITHREAD
|
#ifdef LOG_MULTITHREAD
|
||||||
mtx.lock();
|
mtx.lock();
|
||||||
#endif
|
#endif
|
||||||
logArray[iter] = getTime();
|
getTime();
|
||||||
logArray[iter] += prefix + ": " + type + ": ";
|
logLines[iter] = time;
|
||||||
|
logLines[iter] += prefix + ": " + type + ": ";
|
||||||
vlog(" ", std::forward<Args>(args)...);
|
vlog(" ", std::forward<Args>(args)...);
|
||||||
logArray[iter] += "\n";
|
logLines[iter] += "\n";
|
||||||
|
|
||||||
std::cout << std::string_view(logArray[iter].c_str(), TIMESTAMP_CHAR_COUNT - 1) <<
|
std::cout << std::string_view(logLines[iter].c_str(), LOG_TIMESTAMP_CHAR_COUNT - 1) <<
|
||||||
COLORS[prefixColor] << prefix << COLORS[typeColor] <<
|
COLORS[prefixColor] << prefix << COLORS[typeColor] <<
|
||||||
std::string_view(logArray[iter].begin() + prefixLength + POSTPREFIX_CHAR_COUNT, logArray[iter].begin() + prefixLength + type.size() + 2 * POSTPREFIX_CHAR_COUNT) <<
|
std::string_view(logLines[iter].begin() + prefixLength + LOG_POSTPREFIX_CHAR_COUNT, logLines[iter].begin() + prefixLength + type.size() + 2 * LOG_POSTPREFIX_CHAR_COUNT) <<
|
||||||
COLORS[messageColor] << std::string_view(logArray[iter].begin() + prefixLength + type.size() + 2 * POSTPREFIX_CHAR_COUNT, logArray[iter].end()) << COLORS[RESET];
|
COLORS[messageColor] << std::string_view(logLines[iter].begin() + prefixLength + type.size() + 2 * LOG_POSTPREFIX_CHAR_COUNT, logLines[iter].end()) << COLORS[RESET];
|
||||||
if (++iter >= logLength) {
|
if (++iter >= writeToFileAfterLines) {
|
||||||
iter = 0;
|
iter = 0;
|
||||||
writeLog();
|
writeLog();
|
||||||
}
|
}
|
||||||
@ -230,82 +263,97 @@ class Log {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
// vlog for variadic log
|
||||||
|
/// Log anything that can be appendend to std::string
|
||||||
template<Stringy T, Logable... Args>
|
template<Stringy T, Logable... Args>
|
||||||
void vlog(const char* appendChars, T&& t, Args&&... args) {
|
void vlog(const char* appendChars, T&& t, Args&&... args) {
|
||||||
logArray[iter] += t;
|
logLines[iter] += t;
|
||||||
logArray[iter] += appendChars;
|
logLines[iter] += appendChars;
|
||||||
vlog(" ", std::forward< Args>(args)...);
|
vlog(" ", std::forward< Args>(args)...);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Log anything that has a to_string() member
|
||||||
template<HasToString T, Logable... Args>
|
template<HasToString T, Logable... Args>
|
||||||
void vlog(const char* appendChars, T&& t, Args&&... args) {
|
void vlog(const char* appendChars, T&& t, Args&&... args) {
|
||||||
logArray[iter] += t.to_string();
|
logLines[iter] += t.to_string();
|
||||||
logArray[iter] += appendChars;
|
logLines[iter] += appendChars;
|
||||||
vlog(" ", std::forward< Args>(args)...);
|
vlog(" ", std::forward< Args>(args)...);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<WorksToString T, Logable... Args>
|
/// Log anything where to_string(const T&) -> Stringy
|
||||||
|
template<ExistsToString T, Logable... Args>
|
||||||
void vlog(const char* appendChars, T&& t, Args&&... args) {
|
void vlog(const char* appendChars, T&& t, Args&&... args) {
|
||||||
logArray[iter] += std::to_string(t);
|
logLines[iter] += to_string(t);
|
||||||
logArray[iter] += appendChars;
|
logLines[iter] += appendChars;
|
||||||
vlog(" ", std::forward< Args>(args)...);
|
vlog(" ", std::forward< Args>(args)...);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Log anything that works with std::to_string()
|
||||||
|
template<WorksWithStdToString T, Logable... Args>
|
||||||
|
void vlog(const char* appendChars, T&& t, Args&&... args) {
|
||||||
|
logLines[iter] += std::to_string(t);
|
||||||
|
logLines[iter] += appendChars;
|
||||||
|
vlog(" ", std::forward< Args>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Log bool
|
||||||
template<typename T, Logable... Args>
|
template<typename T, Logable... Args>
|
||||||
requires(std::same_as<T, bool>)
|
requires(std::same_as<T, bool>)
|
||||||
void vlog(const char* appendChars, T&& b, Args&&... args) {
|
void vlog(const char* appendChars, T&& b, Args&&... args) {
|
||||||
logArray[iter] += boolToString(b);
|
logLines[iter] += boolToString(b);
|
||||||
logArray[iter] += appendChars;
|
logLines[iter] += appendChars;
|
||||||
vlog(" ", std::forward< Args>(args)...);
|
vlog(" ", std::forward< Args>(args)...);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Log vec2
|
||||||
template<Vector2Printable V, Logable... Args>
|
template<Vector2Printable V, Logable... Args>
|
||||||
void vlog(const char* appendChars, V&& v, Args&&... args) {
|
void vlog(const char* appendChars, V&& v, Args&&... args) {
|
||||||
logArray[iter] += "(";
|
logLines[iter] += "(";
|
||||||
vlog("", v.x);
|
vlog("", v.x);
|
||||||
logArray[iter] += ", ";
|
logLines[iter] += ", ";
|
||||||
vlog("", v.y);
|
vlog("", v.y);
|
||||||
logArray[iter] += ")";
|
logLines[iter] += ")";
|
||||||
logArray[iter] += appendChars;
|
logLines[iter] += appendChars;
|
||||||
vlog(" ", std::forward< Args>(args)...);
|
vlog(" ", std::forward< Args>(args)...);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Log a pair
|
||||||
template<PairPrintable P, Logable... Args>
|
template<PairPrintable P, Logable... Args>
|
||||||
void vlog(const char* appendChars, P&& p, Args&&... args) {
|
void vlog(const char* appendChars, P&& p, Args&&... args) {
|
||||||
logArray[iter] += "(";
|
logLines[iter] += "(";
|
||||||
vlog("", p.first);
|
vlog("", p.first);
|
||||||
logArray[iter] += ", ";
|
logLines[iter] += ", ";
|
||||||
vlog("" ,p.second);
|
vlog("" ,p.second);
|
||||||
logArray[iter] += ")";
|
logLines[iter] += ")";
|
||||||
logArray[iter] += appendChars;
|
logLines[iter] += appendChars;
|
||||||
vlog(" ", std::forward< Args>(args)...);
|
vlog(" ", std::forward< Args>(args)...);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Log a container using iterators
|
||||||
template<ContainerPrintable T, Logable... Args>
|
template<ContainerPrintable T, Logable... Args>
|
||||||
void vlog(const char* appendChars, T&& t, Args&&... args) {;
|
void vlog(const char* appendChars, T&& t, Args&&... args) {;
|
||||||
logArray[iter] += "[";
|
logLines[iter] += "[";
|
||||||
for (auto it = t.begin(); it != t.end(); it++) {
|
for (auto it = t.begin(); it != t.end(); it++) {
|
||||||
vlog(", ", *it);
|
vlog(", ", *it);
|
||||||
}
|
}
|
||||||
logArray[iter] += "]";
|
logLines[iter] += "]";
|
||||||
logArray[iter] += appendChars;
|
logLines[iter] += appendChars;
|
||||||
vlog(" ", std::forward< Args>(args)...);
|
vlog(" ", std::forward< Args>(args)...);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Log a container containing a pair
|
||||||
template<MapPrintable T, Logable... Args>
|
template<MapPrintable T, Logable... Args>
|
||||||
void vlog(const char* appendChars, T&& t, Args&&... args) {
|
void vlog(const char* appendChars, T&& t, Args&&... args) {
|
||||||
logArray[iter] += "{";
|
logLines[iter] += "{";
|
||||||
for (const auto& [k, v] : t) {
|
for (const auto& [k, v] : t) {
|
||||||
vlog(": ", k);
|
vlog(": ", k);
|
||||||
vlog(", ", v);
|
vlog(", ", v);
|
||||||
}
|
}
|
||||||
logArray[iter] += "}";
|
logLines[iter] += "}";
|
||||||
logArray[iter] += appendChars;
|
logLines[iter] += appendChars;
|
||||||
vlog(" ", std::forward<Args>(args)...);
|
vlog(" ", std::forward<Args>(args)...);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Log any logable element that is stored in a pointer
|
/// Log any logable element that is stored in a pointer
|
||||||
template<LogableSmartPointer T, Logable... Args>
|
template<LogableSmartPointer T, Logable... Args>
|
||||||
void vlog(const char* appendChars, T&& t, Args&&... args) {
|
void vlog(const char* appendChars, T&& t, Args&&... args) {
|
||||||
@ -316,8 +364,13 @@ class Log {
|
|||||||
void vlog(const char* appendChars) {};
|
void vlog(const char* appendChars) {};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::array<std::string, logLength> logArray;
|
/// Where the lines are stored
|
||||||
|
std::vector<std::string> logLines;
|
||||||
|
/// The current position in logLines
|
||||||
size_t iter;
|
size_t iter;
|
||||||
|
/// When iter reaches writeToFileAfterLines, write log to file
|
||||||
|
unsigned int writeToFileAfterLines;
|
||||||
|
/// Absolute path to the logfile
|
||||||
std::string logFile;
|
std::string logFile;
|
||||||
bool showLog;
|
bool showLog;
|
||||||
bool storeLog;
|
bool storeLog;
|
||||||
@ -327,17 +380,16 @@ class Log {
|
|||||||
std::string prefix;
|
std::string prefix;
|
||||||
std::string::size_type prefixLength;
|
std::string::size_type prefixLength;
|
||||||
|
|
||||||
char time[TIMESTAMP_CHAR_COUNT];
|
/// Stores the current time in yyyy-mm-dd hh:mm:ss format
|
||||||
char* getTime();
|
char time[LOG_TIMESTAMP_CHAR_COUNT];
|
||||||
|
/// Store the current time in yyyy-mm-dd hh:mm:ss format in time member
|
||||||
|
void getTime();
|
||||||
#ifdef LOG_MULTITHREAD
|
#ifdef LOG_MULTITHREAD
|
||||||
|
/// Lock for std::cout
|
||||||
static std::mutex mtx;
|
static std::mutex mtx;
|
||||||
#endif
|
#endif
|
||||||
};
|
}; // class Log
|
||||||
|
} // namespace gz
|
||||||
extern Log genLog;
|
|
||||||
extern Log gameLog;
|
|
||||||
extern Log engLog;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @file
|
* @file
|
||||||
|
Loading…
Reference in New Issue
Block a user