logging 2.0 is almost at first working build

v1
Brett 2023-07-21 03:32:42 -04:00
parent 58ba957b1d
commit 889f24d402
15 changed files with 285 additions and 433 deletions

View File

@ -9,7 +9,7 @@
#include <blt/math/vectors.h>
#include <blt/math/matrix.h>
#include <blt/std/logging_old.h>
#include <blt/std/logging.h>
namespace blt {

View File

@ -11,7 +11,7 @@
#include <blt/std/queue.h>
#include <vector>
#include <unordered_map>
#include <blt/std/logging_old.h>
#include <blt/std/logging.h>
#include <fstream>
#include <cstdint>

View File

@ -13,7 +13,7 @@
#include <unordered_map>
#include <string>
#include <blt/std/string.h>
#include <blt/std/logging_old.h>
#include <blt/std/logging.h>
namespace blt::fs {
std::vector<std::string> getLinesFromFile(const std::string& path);

View File

@ -11,25 +11,34 @@
#include <type_traits>
#include <functional>
#include <blt/config.h>
#include <iostream>
namespace blt::logging {
template<typename K, typename V>
using hashmap = std::unordered_map<K, V>;
enum class log_level {
// default
NONE,
// low level
TRACE0, TRACE1, TRACE2, TRACE3,
// normal
TRACE, DEBUG, INFO,
// errors
WARN, ERROR, FATAL,
// default
NONE
};
struct log_tag {
struct tag_func_param {
blt::logging::log_level level;
const std::string& file, line, raw_string, formatted_string;
};
struct tag {
// tag without the ${{ or }}
std::string tag;
// function to run, log level and raw user input string are provided
std::function<std::string(blt::logging::log_level, std::string)> func;
// function to run: log level, file, line, and raw user input string are provided
std::function<std::string(const tag_func_param&)> func;
};
struct log_format {
@ -43,9 +52,15 @@ namespace blt::logging {
* - ${{HOUR}} // current hour
* - ${{MINUTE}} // current minute
* - ${{SECOND}} // current second
* - ${{MS}} // current millisecond
* - ${{LF}} // log level color (ASCII color code)
* - ${{R}} // ASCII color reset
* - ${{MS}} // current unix time
* - ${{NS}} // current ns from the high resolution system timer
* - ${{ISO_YEAR}} // ISO formatted 'year-month-day' in a single variable
* - ${{TIME}} // 'hour:minute:second' formatted string in a single variable
* - ${{FULL_TIME}} // 'year-month-day hour:minute:second' in a single variable
* - ${{LF}} // log level color (ANSI color code)
* - ${{ER}} // Error red
* - ${{CNR}} // conditional error red (only outputs if log level is an error!)
* - ${{RC}} // ANSI color reset
* - ${{LOG_LEVEL}} // current log level
* - ${{THREAD_NAME}} // current thread name, NOTE: thread names must be set by calling "setThreadName()" from the thread in question!
* - ${{FILE}} // file from which the macro is invoked
@ -53,34 +68,247 @@ namespace blt::logging {
* - ${{RAW_STR}} // raw user string without formatting applied (NOTE: format args are not provided!)
* - ${{STR}} // the user supplied string (format applied!)
*/
std::string logOutputFormat = "[${{HOUR}}:${{MINUTE}}:${{SECOND}] ${{LF}}[${{LOG_LEVEL}}]${{R}} ${{STR}}";
std::string logOutputFormat = "[${{HOUR}}:${{MINUTE}}:${{SECOND}] ${{LF}}[${{LOG_LEVEL}}]${{R}} ${{CNR}}${{STR}}";
std::string levelNames[10] = {"STDOUT", "TRACE0, TRACE1, TRACE2", "TRACE3", "TRACE", "DEBUG", "INFO", "WARN", "ERROR", "FATAL"};
std::string levelColors[10] = {"\033[0m", "\033[22;97m", "\033[97m", "\033[97m", "\033[97m", "\033[36m", "\033[92m", "\033[93m", "\033[91m", "\033[97;41m"};
};
void log(log_level level, const std::string& format, const char* file, int line, ...);
struct logger {
log_level level;
std::string file;
std::string line;
};
struct empty_logger {
};
void log(const std::string& format, log_level level, const char* file, int line, ...);
void log_stream(const std::string& str, const logger& logger);
template<typename T, typename std::enable_if<std::is_arithmetic<T>::value>::type* = nullptr>
inline void log(T t, log_level level, const char* file, int line) {
log(std::to_string(t), level, file, line);
}
template<typename T, typename std::enable_if<std::is_arithmetic<T>::value>::type* = nullptr>
inline void log_stream(T t, const logger& logger) {
log_stream(std::to_string(t), logger);
}
static inline const blt::logging::logger& operator<<(const blt::logging::logger& out, const std::string& str) {
log_stream(str, out);
return out;
}
template<typename T, typename std::enable_if<std::is_arithmetic<T>::value>::type* = nullptr>
static inline const blt::logging::logger& operator<<(const blt::logging::logger& out, T t) {
log_stream(std::to_string(t), out);
return out;
}
static inline const blt::logging::empty_logger& operator<<(const blt::logging::empty_logger& out, const std::string&) {
return out;
}
template<typename T, typename std::enable_if<std::is_arithmetic<T>::value>::type* = nullptr>
static inline const blt::logging::empty_logger& operator<<(const blt::logging::empty_logger& out, T) {
return out;
}
void flush();
void setThreadName(const std::string& name);
}
#define BLT_LOGGING_IMPLEMENTATION
#ifdef BLT_LOGGING_IMPLEMENTATION
#include <iostream>
#include <chrono>
#include <ctime>
#include <unordered_map>
#include <thread>
namespace blt::logging {
/**
* Used to store fast associations between built in tags and their respective values
*/
class tag_map {
private:
tag* tags;
size_t size;
[[nodiscard]] inline size_t hash(const tag& t) const {
size_t h = t.tag[0]+ t.tag[1] * 3;
return h;
}
inline void expand(){
auto newSize = size * 2;
tag* newTags = new tag[newSize];
for (size_t i = 0; i < size; i++)
newTags[i] = tags[i];
delete[] tags;
tags = newTags;
size = newSize;
}
public:
tag_map(std::initializer_list<tag> initial_tags){
tags = new tag[(size = 16)];
for (auto& t : initial_tags)
insert(t);
}
tag_map& insert(const tag& t){
auto h = hash(t);
if (h > size)
expand();
if (!tags[h].tag.empty())
std::cerr << "Tag not empty! " << tags[h].tag << "!!!\n";
tags[h] = t;
return *this;
}
tag& operator[](const std::string& name){
auto h = hash(tag{name, nullptr});
if (h > size)
std::cerr << "Tag out of bounds";
return tags[h];
}
~tag_map(){
delete[] tags;
}
};
#define BLT_NOW() auto t = std::time(nullptr); auto now = std::localtime(&t)
#define BLT_ISO_YEAR(S) auto S = std::to_string(now->tm_year); \
S += '-'; \
S += std::to_string(now->tm_mon); \
S += '-'; \
S += std::to_string(now->tm_mday);
#define BLT_CUR_TIME(S) auto S = std::to_string(now->tm_hour); \
S += '-'; \
S += std::to_string(now->tm_min); \
S += '-'; \
S += std::to_string(now->tm_sec);
static inline std::string ensureHasDigits(int current, int digits) {
std::string asString = std::to_string(current);
auto length = digits - asString.length();
if (length <= 0)
return asString;
std::string zeros;
zeros.reserve(length);
for (unsigned int i = 0; i < length; i++){
zeros += '0';
}
return zeros + asString;
}
log_format loggingFormat {};
hashmap<std::thread::id, std::string> loggingThreadNames;
hashmap<std::thread::id, hashmap<blt::logging::log_level, std::string>> loggingStreamLines;
const tag_map tagMap = {
{"YEAR", [](const tag_func_param&) -> std::string {
BLT_NOW();
return std::to_string(now->tm_year);
}},
{"MONTH", [](const tag_func_param&) -> std::string {
BLT_NOW();
return ensureHasDigits(now->tm_mon, 2);
}},
{"DAY", [](const tag_func_param&) -> std::string {
BLT_NOW();
return ensureHasDigits(now->tm_mday, 2);
}},
{"HOUR", [](const tag_func_param&) -> std::string {
BLT_NOW();
return ensureHasDigits(now->tm_hour, 2);
}},
{"MINUTE", [](const tag_func_param&) -> std::string {
BLT_NOW();
return ensureHasDigits(now->tm_min, 2);
}},
{"SECOND", [](const tag_func_param&) -> std::string {
BLT_NOW();
return ensureHasDigits(now->tm_sec, 2);
}},
{"MS", [](const tag_func_param&) -> std::string {
return std::to_string(std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::high_resolution_clock::now().time_since_epoch()).count()
);
}},
{"NS", [](const tag_func_param&) -> std::string {
return std::to_string(std::chrono::duration_cast<std::chrono::nanoseconds>(
std::chrono::high_resolution_clock::now().time_since_epoch()).count()
);
}},
{"ISO_YEAR", [](const tag_func_param&) -> std::string {
BLT_NOW();
BLT_ISO_YEAR(returnStr);
return returnStr;
}},
{"TIME", [](const tag_func_param&) -> std::string {
BLT_NOW();
BLT_CUR_TIME(returnStr);
return returnStr;
}},
{"FULL_TIME", [](const tag_func_param&) -> std::string {
BLT_NOW();
BLT_ISO_YEAR(ISO);
BLT_CUR_TIME(TIME);
ISO += ' ';
ISO += TIME;
return ISO;
}},
{"LF", [](const tag_func_param& f) -> std::string {
return loggingFormat.levelColors[(int)f.level];
}},
{"ER", [](const tag_func_param&) -> std::string {
return loggingFormat.levelColors[(int)log_level::ERROR];
}},
{"CNR", [](const tag_func_param& f) -> std::string {
return f.level >= log_level::ERROR ? loggingFormat.levelColors[(int)log_level::ERROR] : "";
}},
{"RC", [](const tag_func_param&) -> std::string {
return "\033[0m";
}},
{"LOG_LEVEL", [](const tag_func_param& f) -> std::string {
return loggingFormat.levelNames[(int)f.level];
}},
{"THREAD_NAME", [](const tag_func_param&) -> std::string {
if (loggingThreadNames.find(std::this_thread::get_id()) == loggingThreadNames.end())
return "UNKNOWN";
return loggingThreadNames[std::this_thread::get_id()];
}},
{"FILE", [](const tag_func_param& f) -> std::string {
return f.file;
}},
{"LINE", [](const tag_func_param& f) -> std::string {
return f.line;
}},
{"RAW_STR", [](const tag_func_param& f) -> std::string {
return f.raw_string;
}},
{"STR", [](const tag_func_param& f) -> std::string {
return f.formatted_string;
}},
};
void log(const std::string& format, log_level level, const char* file, int line, ...) {
}
void log_stream(const std::string& str, const logger& logger) {
loggingStreamLines[]
}
void setThreadName(const std::string& name) {
loggingThreadNames[std::this_thread::get_id()] = name;
}
void flush() {
@ -104,38 +332,58 @@ namespace blt::logging {
#define BLT_LOG(format, level, ...) log(format, level, __FILE__, __LINE__, ##__VA_ARGS__)
#ifndef BLT_ENABLE_TRACE
#define BLT_TRACE(format, ...)
#define BLT_TRACE0_STREAM blt::logging::empty_logger{}
#define BLT_TRACE1_STREAM blt::logging::empty_logger{}
#define BLT_TRACE2_STREAM blt::logging::empty_logger{}
#define BLT_TRACE3_STREAM blt::logging::empty_logger{}
#define BLT_TRACE_STREAM blt::logging::empty_logger{}
#else
#define BLT_TRACE(format, ...) BLT_LOG(format, blt::logging::log_level::TRACE, ##__VA_ARGS__)
#define BLT_TRACE0_STREAM blt::logging::logger{blt::logging::log_level::TRACE0, std::string(__FILE__), std::to_string(__LINE__)}
#define BLT_TRACE1_STREAM blt::logging::logger{blt::logging::log_level::TRACE1, std::string(__FILE__), std::to_string(__LINE__)}
#define BLT_TRACE2_STREAM blt::logging::logger{blt::logging::log_level::TRACE2, std::string(__FILE__), std::to_string(__LINE__)}
#define BLT_TRACE3_STREAM blt::logging::logger{blt::logging::log_level::TRACE3, std::string(__FILE__), std::to_string(__LINE__)}
#define BLT_TRACE_STREAM blt::logging::logger{blt::logging::log_level::TRACE, std::string(__FILE__), std::to_string(__LINE__)}
#endif
#ifndef BLT_ENABLE_DEBUG
#define BLT_DEBUG(format, ...)
#define BLT_DEBUG_STREAM blt::logging::empty_logger{}
#else
#define BLT_DEBUG(format, ...) BLT_LOG(format, blt::logging::log_level::DEBUG, ##__VA_ARGS__)
#define BLT_DEBUG_STREAM blt::logging::logger{blt::logging::log_level::DEBUG, std::string(__FILE__), std::to_string(__LINE__)}
#endif
#ifndef BLT_ENABLE_INFO
#define BLT_INFO(format, ...)
#define BLT_INFO_STREAM blt::logging::empty_logger{}
#else
#define BLT_INFO(format, ...) BLT_LOG(format, blt::logging::log_level::INFO, ##__VA_ARGS__)
#define BLT_INFO_STREAM blt::logging::logger{blt::logging::log_level::INFO, std::string(__FILE__), std::to_string(__LINE__)}
#endif
#ifndef BLT_ENABLE_WARN
#define BLT_WARN(format, ...)
#define BLT_WARN_STREAM blt::logging::empty_logger{}
#else
#define BLT_WARN(format, ...) BLT_LOG(format, blt::logging::log_level::WARN, ##__VA_ARGS__)
#define BLT_WARN_STREAM blt::logging::logger{blt::logging::log_level::WARN, std::string(__FILE__), std::to_string(__LINE__)}
#endif
#ifndef BLT_ENABLE_ERROR
#define BLT_ERROR(format, ...)
#define BLT_ERROR_STREAM blt::logging::empty_logger{}
#else
#define BLT_ERROR(format, ...) BLT_LOG(format, blt::logging::log_level::ERROR, ##__VA_ARGS__)
#define BLT_ERROR_STREAM blt::logging::logger{blt::logging::log_level::ERROR, std::string(__FILE__), std::to_string(__LINE__)}
#endif
#ifndef BLT_ENABLE_FATAL
#define BLT_FATAL(format, ...)
#define BLT_FATAL_STREAM blt::logging::empty_logger{}
#else
#define BLT_FATAL(format, ...) BLT_LOG(format, blt::logging::log_level::FATAL, ##__VA_ARGS__)
#define BLT_FATAL_STREAM blt::logging::logger{blt::logging::log_level::FATAL, std::string(__FILE__), std::to_string(__LINE__)}
#endif
#endif

View File

@ -1,153 +0,0 @@
/*
* Created by Brett on 23/01/23.
* Licensed under GNU General Public License V3.0
* See LICENSE file for license detail
*/
#ifndef BLT_LOGGING_H
#define BLT_LOGGING_H
#include <string>
#include <type_traits>
#include <blt/config.h>
namespace blt::logging {
enum class log_level {
// low level
TRACE0, TRACE1, TRACE2, TRACE3,
// normal
TRACE, DEBUG, INFO,
WARN,
// errors
ERROR, FATAL,
// default
NONE
};
class ILogHandler {
public:
virtual void log(std::string message, log_level level) = 0;
};
struct LOG_PROPERTIES {
bool m_useColor = true;
bool m_logToConsole = true;
bool m_logToFile = true;
// include file + line data?
bool m_logWithData = true;
// print the whole path or just the file name?
bool m_logFullPath = false;
const char* m_directory = "./";
log_level minLevel = log_level::TRACE;
explicit constexpr LOG_PROPERTIES(
bool useColor, bool logToConsole, bool logToFile, const char* directory
):
m_useColor(useColor), m_logToConsole(logToConsole), m_logToFile(logToFile),
m_directory(directory) {}
explicit constexpr LOG_PROPERTIES() = default;
};
struct logger {
log_level level;
void log_internal(const std::string& str) const;
// evil hack, todo: better way
#ifdef BLT_DISABLE_LOGGING
void log(const std::string& str) const {
}
#else
void log(const std::string& str) const {
log_internal(str);
}
#endif
void flush() const;
static void flush_all();
};
static logger std_out{log_level::NONE};
static logger trace{log_level::TRACE};
static logger debug{log_level::DEBUG};
static logger info{log_level::INFO};
static logger warn{log_level::WARN};
static logger error{log_level::ERROR};
static logger fatal{log_level::FATAL};
static inline logger& getLoggerFromLevel(log_level level) {
static logger loggerLevelDecode[11]{trace, trace, trace, trace, trace, debug, info, warn, error, fatal, std_out};
return loggerLevelDecode[(int)level];
}
static inline logger& operator<<(logger& out, const std::string& str) {
out.log(str);
return out;
}
template<typename T, typename std::enable_if<std::is_arithmetic<T>::value>::type* = nullptr>
static inline logger& operator<<(logger& out, T t) {
out.log(std::to_string(t));
return out;
}
void init(LOG_PROPERTIES properties);
void log_internal(
const std::string& format, log_level level, const char* file, int currentLine,
int auto_line, ...
);
// template voodoo magic (SFINAE, "Substitution Failure Is Not An Error")
// https://stackoverflow.com/questions/44848011/c-limit-template-type-to-numbers
// std::enable_if has a member called type if the condition is true.
// What I am doing is saying that if the condition is true then the template has a non type
// template parameter of type type* (which is void* since the default type for enable_if is void) and it's value is nullptr.
// if the condition is false, the substitution fails, and the entire template is silently (no compiler error) discarded from the overload set.
/**
* Logs an is_arithmetic type to the console.
* @tparam T type to log
* @param t the value to log
* @param level logger level to log at
* @param auto_line put a new line at the end if none exists if true
*/
template<typename T, typename std::enable_if<std::is_arithmetic<T>::value>::type* = nullptr>
inline void log_internal(
T t, log_level level, const char* file, int currentLine, int auto_line
) {
log_internal(std::to_string(t), level, file, currentLine, auto_line);
}
/**
* Will flush all buffers! This might cause issues with threads!
*/
void flush();
void testLogging();
}
#ifndef BLT_ENABLE_LOGGING
#define BLT_TRACE(format, ...)
#define BLT_DEBUG(format, ...)
#define BLT_INFO(format, ...)
#define BLT_WARN(format, ...)
#define BLT_ERROR(format, ...)
#define BLT_FATAL(format, ...)
#else
#ifndef BLT_DISABLE_LOGGING
#define BLT_TRACE(format, ...) log_internal(format, blt::logging::log_level::TRACE, __FILE__, __LINE__, true, ##__VA_ARGS__)
#define BLT_DEBUG(format, ...) log_internal(format, blt::logging::log_level::DEBUG, __FILE__, __LINE__, true, ##__VA_ARGS__)
#define BLT_INFO(format, ...) log_internal(format, blt::logging::log_level::INFO, __FILE__, __LINE__, true, ##__VA_ARGS__)
#define BLT_WARN(format, ...) log_internal(format, blt::logging::log_level::WARN, __FILE__, __LINE__, true, ##__VA_ARGS__)
#define BLT_ERROR(format, ...) log_internal(format, blt::logging::log_level::ERROR, __FILE__, __LINE__, true, ##__VA_ARGS__)
#define BLT_FATAL(format, ...) log_internal(format, blt::logging::log_level::FATAL, __FILE__, __LINE__, true, ##__VA_ARGS__)
#endif
#endif
#endif //BLT_LOGGING_H

View File

@ -136,12 +136,12 @@ namespace blt {
V* _values;
size_t _size = 0;
public:
enum_storage(std::initializer_list<std::pair<K, V>> init){
for (auto& i : init)
_size = std::max((size_t)i, _size);
_size = std::max((size_t)i.first, _size);
_values = new V[_size];
for (auto& v : init)
_values[(size_t)v.first] = v.second;
}
inline V& operator[](size_t index){

View File

@ -12,7 +12,7 @@
#include <sstream>
#include <algorithm>
#include <vector>
#include <blt/std/logging_old.h>
#include <blt/std/logging.h>
namespace blt::string {

View File

@ -7,7 +7,7 @@
#include <mutex>
#include <vector>
#include <blt/std/time.h>
#include <blt/std/logging_old.h>
#include <blt/std/logging.h>
#include <iostream>
#include <algorithm>
#include <blt/std/format.h>
@ -31,9 +31,11 @@ namespace blt::profiling {
};
inline void println(const std::vector<std::string>&& lines, logging::log_level level) {
auto& logger = logging::getLoggerFromLevel(level);
for (const auto& line : lines)
logger << line << "\n";
BLT_INFO_STREAM << line << "\n";
// auto& logger = logging::getLoggerFromLevel(level);
// for (const auto& line : lines)
// logger << line << "\n";
}
/**

View File

@ -5,7 +5,7 @@
*/
#include <blt/std/format.h>
#include <cmath>
#include "blt/std/logging_old.h"
#include "blt/std/logging.h"
std::string createPadding(int padAmount) {
std::string padStr;

View File

@ -1,245 +0,0 @@
/*
* Created by Brett on 23/01/23.
* Licensed under GNU General Public License V3.0
* See LICENSE file for license detail
*/
#include <blt/std/logging_old.h>
#include <blt/std/time.h>
#include <cstdarg>
#include <string>
#include <iostream>
#include "blt/std/string.h"
#include "blt/std/format.h"
#include <fstream>
#include <unordered_map>
#include <ios>
#include <thread>
#include <filesystem>
#include <blt/std/memory.h>
// https://en.cppreference.com/w/cpp/utility/variadic
// https://medium.com/swlh/variadic-functions-3419c287a0d2
// https://publications.gbdirect.co.uk//c_book/chapter9/stdarg.html
// https://cplusplus.com/reference/cstdio/printf/
#include <blt/std/memory.h>
namespace blt::logging {
class LogFileWriter {
private:
std::string m_path;
std::fstream* output;
int currentLines = 0;
static constexpr int MAX_LINES = 100000;
public:
explicit LogFileWriter(const std::string& path): m_path(path){
auto currentTime = system::getTimeStringFS();
output = new std::fstream(path + currentTime + ".log", std::ios::out | std::ios::app);
if (!output->good()){
throw std::runtime_error("Unable to open console filestream!\n");
}
}
void writeLine(const std::string& line){
if (!output->good()){
std::cerr << "There has been an error in the logging file stream!\n";
output->clear();
}
*output << line;
currentLines++;
if (currentLines > MAX_LINES){
output->flush();
output->close();
currentLines = 0;
auto currentTime = system::getTimeStringFS();
delete(output);
output = new std::fstream(m_path + currentTime + ".log");
}
}
~LogFileWriter() {
delete(output);
}
};
void applyFormatting(const std::string& format, std::string& output, va_list& args){
// args must be copied because they will be consumed by the first vsnprintf
va_list args_copy;
va_copy(args_copy, args);
auto buffer_size = std::vsnprintf(nullptr, 0, format.c_str(), args_copy) + 1;
// some compilers don't even allow you to do stack dynamic arrays. So always allocate on the heap.
// originally if the buffer was small enough the buffer was allocated on the stack because it made no sense to make a heap object
// that will be deleted a couple lines later.
scoped_buffer<char> buffer{static_cast<unsigned long>(buffer_size)};
vsnprintf(*buffer, buffer_size, format.c_str(), args);
output = std::string(*buffer);
va_end(args_copy);
}
const char* levelColors[6] = {
"\033[97m",
"\033[36m",
"\033[92m",
"\033[93m",
"\033[91m",
"\033[97;41m"
};
const char* levelNames[6] = {
"[BLT_TRACE]: ",
"[BLT_DEBUG]: ",
"[BLT_INFO]: ",
"[BLT_WARN]: ",
"[BLT_ERROR]: ",
"[BLT_FATAL]: ",
};
// by default everything is enabled
LOG_PROPERTIES BLT_LOGGING_PROPERTIES {};
LogFileWriter* writer = new LogFileWriter{"./"};
void init(LOG_PROPERTIES properties) {
if (properties.m_logToFile && BLT_LOGGING_PROPERTIES.m_directory != properties.m_directory) {
delete(writer);
writer = new LogFileWriter{properties.m_directory};
}
if (properties.m_logToFile)
std::filesystem::create_directory(properties.m_directory);
BLT_LOGGING_PROPERTIES = properties;
}
inline std::string filename(const std::string& path){
if (BLT_LOGGING_PROPERTIES.m_logFullPath)
return path;
auto paths = blt::string::split(path, "/");
auto final = paths[paths.size()-1];
if (final == "/")
return paths[paths.size()-2];
return final;
}
inline void log(const std::string& str, bool hasEndingLinefeed, log_level level, const char* file, int currentLine, int auto_line){
if (level < BLT_LOGGING_PROPERTIES.minLevel)
return;
std::string outputString = system::getTimeStringLog();
if (BLT_LOGGING_PROPERTIES.m_logWithData && currentLine >= 0) {
outputString += '[';
outputString += filename(file);
outputString += ':';
outputString += std::to_string(currentLine);
outputString += "] ";
}
outputString += levelNames[(int)level];
outputString += str;
std::string fileString = outputString;
if (BLT_LOGGING_PROPERTIES.m_useColor) {
outputString = levelColors[(int)level] + outputString;
outputString += "\033[0m";
}
if (hasEndingLinefeed || auto_line) {
outputString += "\n";
fileString += "\n";
}
if (BLT_LOGGING_PROPERTIES.m_logToConsole) {
if (level > log_level::WARN)
std::cerr << outputString;
else
std::cout << outputString;
}
if (BLT_LOGGING_PROPERTIES.m_logToFile) {
writer->writeLine(fileString);
}
}
void log_internal(const std::string& format, log_level level, const char* file, int currentLine, int auto_line, ...) {
va_list args;
va_start(args, auto_line);
std::string formattedString;
applyFormatting(format, formattedString, args);
bool hasEndingLinefeed = false;
if (formattedString.length() > 0)
hasEndingLinefeed = formattedString[formattedString.length() - 1] == '\n';
if (hasEndingLinefeed)
formattedString = formattedString.substr(0, formattedString.length()-1);
log(formattedString, hasEndingLinefeed, level, file, currentLine, auto_line);
va_end(args);
}
// stores an association between thread -> log level -> current line buffer
std::unordered_map<std::thread::id, std::unordered_map<log_level, std::string>> thread_local_strings;
void logger::log_internal(const std::string& str) const {
auto id = std::this_thread::get_id();
auto th_str = thread_local_strings[id][level];
th_str += str;
if (blt::string::contains(str, "\n")){
// make sure new lines are properly formatted to prevent danging lines. Ie "[trace]: .... [debug]: ...."
bool hasEndingLinefeed = str[str.length()-1] == '\n';
if (level == log_level::NONE) {
std::cout << th_str;
} else
logging::log(th_str, false, level, "", -1, !hasEndingLinefeed);
thread_local_strings[id][level] = "";
} else {
thread_local_strings[id][level] = th_str;
}
}
void flushLogger_internal(std::thread::id id, log_level level){
auto th_str = thread_local_strings[id][level];
if (th_str.empty())
return;
bool hasEndingLinefeed = th_str[th_str.length() - 1] == '\n';
logging::log(th_str, false, level, "", -1, !hasEndingLinefeed);
thread_local_strings[id][level] = "";
}
void logger::flush() const {
for (const auto& id : thread_local_strings) {
flushLogger_internal(id.first, level);
}
}
void logger::flush_all() {
for (const auto& id : thread_local_strings) {
for (const auto& level : thread_local_strings[id.first]){
flushLogger_internal(id.first, level.first);
}
}
}
void flush() {
logger::flush_all();
std::cerr.flush();
std::cout.flush();
}
void testLogging() {
trace << "Trace Test!\n";
debug << "Debug Test!\n";
info << "Info Test!\n";
warn << "Warn Test!\n";
error << "Error Test!\n";
fatal << "Fatal Test!\n";
}
}

View File

@ -18,10 +18,10 @@ void run_logging() {
BLT_ERROR("Hello World!\n");
BLT_FATAL("Hello World!\n");
blt::logging::trace << "Hello! " << "Double stream insertion! " << 51 << 65 << " ";
blt::logging::trace << "Same Line! ";
blt::logging::trace << "Write the end!\n";
blt::logging::trace << "Seeee\n Super\n";
// blt::logging::trace << "Hello! " << "Double stream insertion! " << 51 << 65 << " ";
// blt::logging::trace << "Same Line! ";
// blt::logging::trace << "Write the end!\n";
// blt::logging::trace << "Seeee\n Super\n";
std::string hello = "superSexyMax";
std::cout << "String starts with: " << blt::string::contains(hello, "superSexyMaxE") << "\n";

View File

@ -19,10 +19,10 @@ int main() {
nbt_tests();
blt::logging::trace << "Test Output!\n";
blt::logging::trace << 5;
blt::logging::trace << 5;
blt::logging::trace << 5;
// blt::logging::trace << "Test Output!\n";
// blt::logging::trace << 5;
// blt::logging::trace << 5;
// blt::logging::trace << 5;
blt::logging::flush();

View File

@ -9,7 +9,7 @@
#include <blt/nbt/nbt.h>
#include <blt/profiling/profiler.h>
#include <blt/std/logging_old.h>
#include <blt/std/logging.h>
#include <blt/std/format.h>
#include <blt/std/filesystem.h>

View File

@ -8,7 +8,7 @@
#define BLT_TESTS_PROFILING_TESTS_H
#include "blt/profiling/profiler.h"
#include "blt/std/logging_old.h"
#include "blt/std/logging.h"
#include "blt/std/time.h"
#include "blt/std/format.h"

View File

@ -9,7 +9,7 @@
#include <queue>
#include <blt/std/queue.h>
#include <blt/std/logging_old.h>
#include <blt/std/logging.h>
#include <blt/profiling/profiler.h>
#include <array>
#include <blt/std/random.h>