532 lines
22 KiB
C++
532 lines
22 KiB
C++
/*
|
|
{{copyright}}
|
|
*/
|
|
|
|
/*
|
|
{{version}}
|
|
*/
|
|
|
|
/*
|
|
{{license}}
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include "../console/ansi.h"
|
|
|
|
#ifdef _WIN32
|
|
# ifndef WIN32_LEAN_AND_MEAN
|
|
# define WIN32_LEAN_AND_MEAN // Disable windows mess
|
|
# endif
|
|
# ifndef NOMINMAX
|
|
# define NOMINMAX
|
|
# endif
|
|
# include <Windows.h>
|
|
# undef GetMessage // To avoid conflict with other libraries
|
|
#endif
|
|
|
|
#include <chrono>
|
|
#include <filesystem>
|
|
#include <fstream>
|
|
#include <iostream>
|
|
#include <map>
|
|
#include <mutex>
|
|
#include <source_location>
|
|
#include <sstream>
|
|
#include <string>
|
|
|
|
/*
|
|
* Usage :
|
|
*
|
|
* {
|
|
* int value = 42;
|
|
* std::string user = "Alice";
|
|
*
|
|
* // Usage example:
|
|
* LogMessage() << "System ready" << std::endl;
|
|
* LogDebug() << "Checking configuration file..." << std::endl;
|
|
* LogInfo() << "User " << user << " logged in. (Value: " << value << ")" << std::endl;
|
|
* LogWarning() << "Device connection lost..." << std::endl;
|
|
* LogError() << "Failed to connect to server on port " << 8080 << "!" << std::endl;
|
|
* LogComm() << "<< 0123456789" << std::endl;
|
|
* LogDev() << "<< 0123456789" << std::endl;
|
|
* }
|
|
*/
|
|
|
|
namespace sdi_toolBox::logs
|
|
{
|
|
//--------------------------------------------------------------
|
|
enum class LogLevel : uint8_t
|
|
{
|
|
None,
|
|
Dev,
|
|
Comm,
|
|
Debug,
|
|
Info,
|
|
Warning,
|
|
Error,
|
|
Message,
|
|
};
|
|
//--------------------------------------------------------------
|
|
|
|
//--------------------------------------------------------------
|
|
class ReLog
|
|
{
|
|
public:
|
|
struct Log
|
|
{
|
|
LogLevel level;
|
|
std::chrono::system_clock::time_point timestamp;
|
|
std::string message;
|
|
};
|
|
|
|
using ColorLogMap = std::map<LogLevel, std::string>;
|
|
using VisibleLogMap = std::map<LogLevel, bool>;
|
|
static VisibleLogMap getVisibleLogMap(); // Return the map of visible log messages
|
|
static void setVisibleLogMap(const VisibleLogMap &logMap); // Define the map of visible log messages
|
|
|
|
static ReLog &systemInit(const std::filesystem::path &filepath = ""); // Initialize log system
|
|
static ReLog &getInstance(); // Gets singleton instance
|
|
|
|
public:
|
|
virtual ~ReLog() = default; // Default destructor
|
|
ReLog(const ReLog &obj) = delete; // Copy constructor
|
|
ReLog(ReLog &&obj) noexcept = delete; // Move constructor
|
|
ReLog &operator=(const ReLog &obj) = delete; // Copy assignment operator
|
|
ReLog &operator=(ReLog &&obj) noexcept = delete; // Move assignment operator
|
|
|
|
void openFile(const std::filesystem::path &filepath); // Open or create log file
|
|
void closeFile(); // Close log file
|
|
|
|
void log(const Log &log); // Core log method
|
|
|
|
void printColorTest() const; // Print the different configurations and colors on the terminal
|
|
|
|
protected:
|
|
ReLog(); // Default constructor
|
|
|
|
bool m_vtModeEnabled = false;
|
|
|
|
std::mutex m_mtx;
|
|
std::ofstream m_file;
|
|
|
|
static inline ColorLogMap m_colorLogMap;
|
|
static inline VisibleLogMap m_visibleLogMap;
|
|
|
|
private:
|
|
void enableVTMode();
|
|
|
|
static void init(); // Settings initialization
|
|
|
|
static std::string createLogMessage(const Log &log, const bool isFile = false); // Print log messages
|
|
void printDate();
|
|
|
|
void saveToFile(const std::string &message); // Save log messages in file
|
|
};
|
|
//--------------------------------------------------------------
|
|
|
|
/* --- */
|
|
|
|
//--------------------------------------------------------------
|
|
/* Return the map of visible log messages */
|
|
inline ReLog::VisibleLogMap ReLog::getVisibleLogMap()
|
|
{
|
|
return m_visibleLogMap;
|
|
}
|
|
//--------------------------------------------------------------
|
|
/* Define the map of visible log messages */
|
|
inline void ReLog::setVisibleLogMap(const VisibleLogMap &logMap)
|
|
{
|
|
m_visibleLogMap = logMap;
|
|
}
|
|
//--------------------------------------------------------------
|
|
/* Initialize log system */
|
|
inline ReLog &ReLog::systemInit(const std::filesystem::path &filepath)
|
|
{
|
|
auto &logSystem = getInstance();
|
|
|
|
// Post initialization
|
|
if (!filepath.empty())
|
|
logSystem.openFile(filepath);
|
|
logSystem.printDate();
|
|
return logSystem;
|
|
}
|
|
//--------------------------------------------------------------
|
|
/* Gets singleton instance */
|
|
inline ReLog &ReLog::getInstance()
|
|
{
|
|
static ReLog instance;
|
|
return instance;
|
|
}
|
|
//--------------------------------------------------------------
|
|
/* Constructor */
|
|
inline ReLog::ReLog()
|
|
{
|
|
// Initialization
|
|
init();
|
|
enableVTMode();
|
|
|
|
// Test on debug mode
|
|
#ifdef DEBUG
|
|
// printColorTest();
|
|
#endif
|
|
}
|
|
//--------------------------------------------------------------
|
|
/* Open or create log file */
|
|
inline void ReLog::openFile(const std::filesystem::path &filepath)
|
|
{
|
|
std::lock_guard lock(m_mtx);
|
|
|
|
m_file = std::ofstream(filepath, std::ofstream::out | std::ofstream::app | std::ofstream::binary);
|
|
if (!m_file)
|
|
throw std::runtime_error("unable to open log file");
|
|
m_file << "\n-----------------------------------------------------------------" << std::endl;
|
|
}
|
|
//--------------------------------------------------------------
|
|
/* Close log file */
|
|
inline void ReLog::closeFile()
|
|
{
|
|
std::lock_guard lock(m_mtx);
|
|
|
|
if (m_file.is_open())
|
|
m_file.close();
|
|
}
|
|
//--------------------------------------------------------------
|
|
/* Core log method */
|
|
inline void ReLog::log(const Log &log)
|
|
{
|
|
std::lock_guard lock(m_mtx);
|
|
|
|
const auto termMessage = createLogMessage(log);
|
|
if (!termMessage.empty())
|
|
{
|
|
if (log.level == LogLevel::Error)
|
|
std::cerr << termMessage << std::endl;
|
|
else
|
|
std::cout << termMessage << std::endl;
|
|
}
|
|
|
|
const auto fileMessage = createLogMessage(log, true);
|
|
if (!fileMessage.empty())
|
|
saveToFile(fileMessage);
|
|
}
|
|
//--------------------------------------------------------------
|
|
/* Print the different configurations and colors on the terminal */
|
|
inline void ReLog::printColorTest() const
|
|
{
|
|
const auto coutTest = [&](const auto &color, const std::string &label)
|
|
{
|
|
std::cout << sdi_toolBox::console::ANSI::EscapeCommand::get(color) << label << sdi_toolBox::console::ANSI::EscapeCommand::clear();
|
|
std::cout << sdi_toolBox::console::ANSI::EscapeCommand::get(color, sdi_toolBox::console::ANSI::EscapeCommand::UNDERLINE) << label << sdi_toolBox::console::ANSI::EscapeCommand::clear();
|
|
std::cout << sdi_toolBox::console::ANSI::EscapeCommand::get(color, sdi_toolBox::console::ANSI::EscapeCommand::DIM | sdi_toolBox::console::ANSI::EscapeCommand::UNDERLINE) << label << sdi_toolBox::console::ANSI::EscapeCommand::clear();
|
|
std::cout << sdi_toolBox::console::ANSI::EscapeCommand::get(color, sdi_toolBox::console::ANSI::EscapeCommand::LIGHT | sdi_toolBox::console::ANSI::EscapeCommand::UNDERLINE) << label << sdi_toolBox::console::ANSI::EscapeCommand::clear();
|
|
std::cout << sdi_toolBox::console::ANSI::EscapeCommand::get(color, sdi_toolBox::console::ANSI::EscapeCommand::LIGHT) << label << sdi_toolBox::console::ANSI::EscapeCommand::clear();
|
|
std::cout << sdi_toolBox::console::ANSI::EscapeCommand::get(color, sdi_toolBox::console::ANSI::EscapeCommand::BLINK) << label << sdi_toolBox::console::ANSI::EscapeCommand::clear();
|
|
std::cout << sdi_toolBox::console::ANSI::EscapeCommand::get(color, sdi_toolBox::console::ANSI::EscapeCommand::BRIGHT) << label << sdi_toolBox::console::ANSI::EscapeCommand::clear();
|
|
std::cout << sdi_toolBox::console::ANSI::EscapeCommand::get(color, sdi_toolBox::console::ANSI::EscapeCommand::DIM) << label << sdi_toolBox::console::ANSI::EscapeCommand::clear();
|
|
std::cout << sdi_toolBox::console::ANSI::EscapeCommand::get(color, sdi_toolBox::console::ANSI::EscapeCommand::REVERSE) << label << sdi_toolBox::console::ANSI::EscapeCommand::clear();
|
|
std::cout << " | ";
|
|
std::cout << sdi_toolBox::console::ANSI::EscapeCommand::get(color, 0, sdi_toolBox::console::ANSI::EscapeCommand::Color::Black) << label << sdi_toolBox::console::ANSI::EscapeCommand::clear();
|
|
std::cout << sdi_toolBox::console::ANSI::EscapeCommand::get(color, 0, sdi_toolBox::console::ANSI::EscapeCommand::Color::Red) << label << sdi_toolBox::console::ANSI::EscapeCommand::clear();
|
|
std::cout << sdi_toolBox::console::ANSI::EscapeCommand::get(color, 0, sdi_toolBox::console::ANSI::EscapeCommand::Color::Green) << label << sdi_toolBox::console::ANSI::EscapeCommand::clear();
|
|
std::cout << sdi_toolBox::console::ANSI::EscapeCommand::get(color, 0, sdi_toolBox::console::ANSI::EscapeCommand::Color::Yellow) << label << sdi_toolBox::console::ANSI::EscapeCommand::clear();
|
|
std::cout << sdi_toolBox::console::ANSI::EscapeCommand::get(color, 0, sdi_toolBox::console::ANSI::EscapeCommand::Color::Blue) << label << sdi_toolBox::console::ANSI::EscapeCommand::clear();
|
|
std::cout << sdi_toolBox::console::ANSI::EscapeCommand::get(color, 0, sdi_toolBox::console::ANSI::EscapeCommand::Color::Magenta) << label << sdi_toolBox::console::ANSI::EscapeCommand::clear();
|
|
std::cout << sdi_toolBox::console::ANSI::EscapeCommand::get(color, 0, sdi_toolBox::console::ANSI::EscapeCommand::Color::Cyan) << label << sdi_toolBox::console::ANSI::EscapeCommand::clear();
|
|
std::cout << sdi_toolBox::console::ANSI::EscapeCommand::get(color, 0, sdi_toolBox::console::ANSI::EscapeCommand::Color::White) << label << sdi_toolBox::console::ANSI::EscapeCommand::clear();
|
|
std::cout << " | ";
|
|
std::cout << sdi_toolBox::console::ANSI::EscapeCommand::get(color, 0, sdi_toolBox::console::ANSI::EscapeCommand::Color::Black, sdi_toolBox::console::ANSI::EscapeCommand::LIGHT) << label << sdi_toolBox::console::ANSI::EscapeCommand::clear();
|
|
std::cout << sdi_toolBox::console::ANSI::EscapeCommand::get(color, 0, sdi_toolBox::console::ANSI::EscapeCommand::Color::Red, sdi_toolBox::console::ANSI::EscapeCommand::LIGHT) << label << sdi_toolBox::console::ANSI::EscapeCommand::clear();
|
|
std::cout << sdi_toolBox::console::ANSI::EscapeCommand::get(color, 0, sdi_toolBox::console::ANSI::EscapeCommand::Color::Green, sdi_toolBox::console::ANSI::EscapeCommand::LIGHT) << label << sdi_toolBox::console::ANSI::EscapeCommand::clear();
|
|
std::cout << sdi_toolBox::console::ANSI::EscapeCommand::get(color, 0, sdi_toolBox::console::ANSI::EscapeCommand::Color::Yellow, sdi_toolBox::console::ANSI::EscapeCommand::LIGHT) << label << sdi_toolBox::console::ANSI::EscapeCommand::clear();
|
|
std::cout << sdi_toolBox::console::ANSI::EscapeCommand::get(color, 0, sdi_toolBox::console::ANSI::EscapeCommand::Color::Blue, sdi_toolBox::console::ANSI::EscapeCommand::LIGHT) << label << sdi_toolBox::console::ANSI::EscapeCommand::clear();
|
|
std::cout << sdi_toolBox::console::ANSI::EscapeCommand::get(color, 0, sdi_toolBox::console::ANSI::EscapeCommand::Color::Magenta, sdi_toolBox::console::ANSI::EscapeCommand::LIGHT) << label << sdi_toolBox::console::ANSI::EscapeCommand::clear();
|
|
std::cout << sdi_toolBox::console::ANSI::EscapeCommand::get(color, 0, sdi_toolBox::console::ANSI::EscapeCommand::Color::Cyan, sdi_toolBox::console::ANSI::EscapeCommand::LIGHT) << label << sdi_toolBox::console::ANSI::EscapeCommand::clear();
|
|
std::cout << sdi_toolBox::console::ANSI::EscapeCommand::get(color, 0, sdi_toolBox::console::ANSI::EscapeCommand::Color::White, sdi_toolBox::console::ANSI::EscapeCommand::LIGHT) << label << sdi_toolBox::console::ANSI::EscapeCommand::clear();
|
|
std::cout << std::endl;
|
|
};
|
|
coutTest(sdi_toolBox::console::ANSI::EscapeCommand::Color::Black, " B ");
|
|
coutTest(sdi_toolBox::console::ANSI::EscapeCommand::Color::Red, " R ");
|
|
coutTest(sdi_toolBox::console::ANSI::EscapeCommand::Color::Green, " G ");
|
|
coutTest(sdi_toolBox::console::ANSI::EscapeCommand::Color::Yellow, " Y ");
|
|
coutTest(sdi_toolBox::console::ANSI::EscapeCommand::Color::Blue, " B ");
|
|
coutTest(sdi_toolBox::console::ANSI::EscapeCommand::Color::Magenta, " M ");
|
|
coutTest(sdi_toolBox::console::ANSI::EscapeCommand::Color::Cyan, " C ");
|
|
coutTest(sdi_toolBox::console::ANSI::EscapeCommand::Color::White, " W ");
|
|
std::cout << std::endl;
|
|
}
|
|
//--------------------------------------------------------------
|
|
inline void ReLog::enableVTMode()
|
|
{
|
|
if (m_vtModeEnabled)
|
|
return;
|
|
|
|
m_vtModeEnabled = false;
|
|
|
|
// 1. Get the handle to the standard output
|
|
const HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
|
|
if (hOut == INVALID_HANDLE_VALUE)
|
|
return;
|
|
|
|
// 2. Get the current console mode
|
|
DWORD dwMode = 0;
|
|
if (!GetConsoleMode(hOut, &dwMode))
|
|
return;
|
|
|
|
// 3. Set the ENABLE_VIRTUAL_TERMINAL_PROCESSING flag (using bitwise OR)
|
|
dwMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
|
|
|
|
// 4. Apply the new console mode
|
|
if (!SetConsoleMode(hOut, dwMode)) // This is often the point of failure on older Windows versions (pre-Win10 v1511)
|
|
return;
|
|
|
|
m_vtModeEnabled = true;
|
|
}
|
|
//--------------------------------------------------------------
|
|
/* Settings initialization */
|
|
inline void ReLog::init()
|
|
{
|
|
m_colorLogMap[LogLevel::None] = sdi_toolBox::console::ANSI::EscapeCommand::clear();
|
|
m_colorLogMap[LogLevel::Dev] = sdi_toolBox::console::ANSI::EscapeCommand::get(sdi_toolBox::console::ANSI::EscapeCommand::Color::Green, sdi_toolBox::console::ANSI::EscapeCommand::DIM);
|
|
m_colorLogMap[LogLevel::Comm] = sdi_toolBox::console::ANSI::EscapeCommand::get(sdi_toolBox::console::ANSI::EscapeCommand::Color::Magenta);
|
|
m_colorLogMap[LogLevel::Debug] = sdi_toolBox::console::ANSI::EscapeCommand::get(sdi_toolBox::console::ANSI::EscapeCommand::Color::Yellow, sdi_toolBox::console::ANSI::EscapeCommand::DIM);
|
|
m_colorLogMap[LogLevel::Info] = sdi_toolBox::console::ANSI::EscapeCommand::get(sdi_toolBox::console::ANSI::EscapeCommand::Color::White);
|
|
m_colorLogMap[LogLevel::Warning] = sdi_toolBox::console::ANSI::EscapeCommand::get(sdi_toolBox::console::ANSI::EscapeCommand::Color::Yellow);
|
|
m_colorLogMap[LogLevel::Error] = sdi_toolBox::console::ANSI::EscapeCommand::get(sdi_toolBox::console::ANSI::EscapeCommand::Color::Red, sdi_toolBox::console::ANSI::EscapeCommand::LIGHT | sdi_toolBox::console::ANSI::EscapeCommand::BRIGHT);
|
|
m_colorLogMap[LogLevel::Message] = sdi_toolBox::console::ANSI::EscapeCommand::get(sdi_toolBox::console::ANSI::EscapeCommand::Color::White, sdi_toolBox::console::ANSI::EscapeCommand::LIGHT);
|
|
|
|
m_visibleLogMap[LogLevel::Dev] = true;
|
|
m_visibleLogMap[LogLevel::Comm] = true;
|
|
m_visibleLogMap[LogLevel::Debug] = true;
|
|
m_visibleLogMap[LogLevel::Info] = true;
|
|
m_visibleLogMap[LogLevel::Warning] = true;
|
|
m_visibleLogMap[LogLevel::Error] = true;
|
|
m_visibleLogMap[LogLevel::Message] = true;
|
|
}
|
|
//--------------------------------------------------------------
|
|
/* Print log messages */
|
|
inline std::string ReLog::createLogMessage(const Log &log, const bool isFile)
|
|
{
|
|
// Check if the message should be visible or not
|
|
if (m_visibleLogMap.contains(log.level) && m_visibleLogMap[log.level] == false)
|
|
return "";
|
|
|
|
std::ostringstream stream;
|
|
|
|
// Prepare message color
|
|
const auto levelStyle = (m_colorLogMap.contains(log.level)) ? m_colorLogMap[log.level] : sdi_toolBox::console::ANSI::EscapeCommand::clear();
|
|
const auto messageStyle = (!isFile) ? levelStyle : "";
|
|
|
|
if (!log.message.empty())
|
|
{
|
|
switch (log.level)
|
|
{
|
|
case LogLevel::Error:
|
|
stream << messageStyle << "[E] ";
|
|
break;
|
|
case LogLevel::Warning:
|
|
stream << messageStyle << "[W] ";
|
|
break;
|
|
case LogLevel::Info:
|
|
stream << messageStyle << "[I] ";
|
|
break;
|
|
case LogLevel::Debug:
|
|
stream << messageStyle << "[D] ";
|
|
break;
|
|
case LogLevel::Comm:
|
|
stream << messageStyle << "[C] ";
|
|
break;
|
|
case LogLevel::Dev:
|
|
stream << messageStyle << "[-] ";
|
|
break;
|
|
case LogLevel::Message:
|
|
default:;
|
|
stream << messageStyle;
|
|
break;
|
|
}
|
|
|
|
if (log.level != LogLevel::Message)
|
|
{
|
|
const auto local_tz = std::chrono::current_zone();
|
|
const auto local_time = std::chrono::zoned_time(local_tz, log.timestamp);
|
|
stream << std::format("{0:%T} - ", local_time);
|
|
}
|
|
}
|
|
|
|
// Print message
|
|
stream << log.message;
|
|
|
|
// Reset style
|
|
if (!messageStyle.empty())
|
|
stream << sdi_toolBox::console::ANSI::EscapeCommand::clear();
|
|
|
|
return stream.str();
|
|
}
|
|
//--------------------------------------------------------------
|
|
inline void ReLog::printDate()
|
|
{
|
|
const auto now = std::chrono::system_clock::now();
|
|
const auto local_tz = std::chrono::current_zone();
|
|
const auto local_time = std::chrono::zoned_time(local_tz, now);
|
|
|
|
const Log logMessage{ .level = LogLevel::Info,
|
|
.timestamp = now,
|
|
.message = std::format("current date: {0:%F}", local_time) };
|
|
log(logMessage);
|
|
}
|
|
//--------------------------------------------------------------
|
|
/* Save log messages in file */
|
|
inline void ReLog::saveToFile(const std::string &message)
|
|
{
|
|
// Remove escape sequences
|
|
std::string messageResult;
|
|
bool in_escape_sequence = false;
|
|
|
|
constexpr char ANSI_ESCAPE_CHAR = '\x1b';
|
|
for (const char c : message)
|
|
{
|
|
if (in_escape_sequence)
|
|
{
|
|
if (c == 'm')
|
|
in_escape_sequence = false; // End of the escape sequence
|
|
}
|
|
else if (c == ANSI_ESCAPE_CHAR)
|
|
in_escape_sequence = true; // Begin of the escape sequence
|
|
else
|
|
messageResult += c;
|
|
}
|
|
|
|
if (m_file.is_open())
|
|
m_file << messageResult << "\n";
|
|
}
|
|
//--------------------------------------------------------------
|
|
|
|
/* --- */
|
|
|
|
//--------------------------------------------------------------
|
|
class ReLogStreamProxy
|
|
{
|
|
public:
|
|
ReLogStreamProxy() = delete; // Constructor
|
|
explicit ReLogStreamProxy(const LogLevel &level); // Constructor
|
|
virtual ~ReLogStreamProxy(); // Destructor
|
|
ReLogStreamProxy(ReLogStreamProxy &obj) = delete; // Copy constructor
|
|
ReLogStreamProxy(ReLogStreamProxy &&obj) = delete; // Move constructor
|
|
ReLogStreamProxy &operator=(const ReLogStreamProxy &obj) = delete; // Copy assignment operator
|
|
ReLogStreamProxy &operator=(ReLogStreamProxy &&obj) = delete; // Move assignment operator
|
|
|
|
template<typename T>
|
|
ReLogStreamProxy &operator<<(const T &data); // Overload for various data types (int, string, double, etc.)
|
|
ReLogStreamProxy &operator<<(std::ostream &(*manip)(std::ostream &)); // Overload for std::endl and other manipulators
|
|
|
|
protected:
|
|
LogLevel m_level;
|
|
std::chrono::system_clock::time_point m_timestamp;
|
|
std::stringstream m_buffer;
|
|
|
|
private:
|
|
void flush(); // Pass the buffered content to the central Logger
|
|
};
|
|
//--------------------------------------------------------------
|
|
/* Constructor */
|
|
inline ReLogStreamProxy::ReLogStreamProxy(const LogLevel &level)
|
|
{
|
|
// Initialization
|
|
m_level = level;
|
|
}
|
|
//--------------------------------------------------------------
|
|
/* Destructor */
|
|
inline ReLogStreamProxy::~ReLogStreamProxy()
|
|
{
|
|
if (!m_buffer.str().empty())
|
|
flush();
|
|
}
|
|
//--------------------------------------------------------------
|
|
/* Overload for various data types (int, string, double, etc.) */
|
|
template<typename T>
|
|
inline ReLogStreamProxy &ReLogStreamProxy::operator<<(const T &data)
|
|
{
|
|
const auto now = std::chrono::system_clock::now();
|
|
|
|
if (m_buffer.str().empty())
|
|
m_timestamp = now;
|
|
|
|
m_buffer << data;
|
|
return *this;
|
|
}
|
|
//--------------------------------------------------------------
|
|
/* Overload for std::endl and other manipulators */
|
|
inline ReLogStreamProxy &ReLogStreamProxy::operator<<(std::ostream &(*manip)(std::ostream &))
|
|
{
|
|
if (manip == static_cast<std::ostream &(*)(std::ostream &)>(std::endl))
|
|
{
|
|
flush();
|
|
}
|
|
else
|
|
{
|
|
// Handle other manipulators if necessary (e.g., std::hex)
|
|
m_buffer << manip;
|
|
}
|
|
return *this;
|
|
}
|
|
//--------------------------------------------------------------
|
|
/* Pass the buffered content to the central Logger */
|
|
inline void ReLogStreamProxy::flush()
|
|
{
|
|
// Pass the buffered content to the central Logger
|
|
ReLog::getInstance().log(ReLog::Log{ .level = m_level,
|
|
.timestamp = m_timestamp,
|
|
.message = m_buffer.str() });
|
|
|
|
// Reset stream content
|
|
m_buffer.str("");
|
|
m_buffer.clear();
|
|
}
|
|
//--------------------------------------------------------------
|
|
} // namespace sdi_toolBox::logs
|
|
|
|
//--------------------------------------------------------------
|
|
/*
|
|
* User interface
|
|
*/
|
|
inline sdi_toolBox::logs::ReLogStreamProxy LogError()
|
|
{
|
|
return sdi_toolBox::logs::ReLogStreamProxy(sdi_toolBox::logs::LogLevel::Error);
|
|
}
|
|
//--------------------------------------------------------------
|
|
inline sdi_toolBox::logs::ReLogStreamProxy LogWarning()
|
|
{
|
|
return sdi_toolBox::logs::ReLogStreamProxy(sdi_toolBox::logs::LogLevel::Warning);
|
|
}
|
|
//--------------------------------------------------------------
|
|
inline sdi_toolBox::logs::ReLogStreamProxy LogInfo()
|
|
{
|
|
return sdi_toolBox::logs::ReLogStreamProxy(sdi_toolBox::logs::LogLevel::Info);
|
|
}
|
|
//--------------------------------------------------------------
|
|
inline sdi_toolBox::logs::ReLogStreamProxy LogDebug()
|
|
{
|
|
return sdi_toolBox::logs::ReLogStreamProxy(sdi_toolBox::logs::LogLevel::Debug);
|
|
}
|
|
//--------------------------------------------------------------
|
|
inline sdi_toolBox::logs::ReLogStreamProxy LogComm()
|
|
{
|
|
return sdi_toolBox::logs::ReLogStreamProxy(sdi_toolBox::logs::LogLevel::Comm);
|
|
}
|
|
//--------------------------------------------------------------
|
|
inline sdi_toolBox::logs::ReLogStreamProxy LogMessage()
|
|
{
|
|
return sdi_toolBox::logs::ReLogStreamProxy(sdi_toolBox::logs::LogLevel::Message);
|
|
}
|
|
//--------------------------------------------------------------
|
|
inline sdi_toolBox::logs::ReLogStreamProxy LogDev()
|
|
{
|
|
return sdi_toolBox::logs::ReLogStreamProxy(sdi_toolBox::logs::LogLevel::Dev);
|
|
}
|
|
//--------------------------------------------------------------
|
|
inline void LogCode(const std::string &msg = "", const std::source_location &location = std::source_location::current())
|
|
{
|
|
LogDev() << msg << ((!msg.empty()) ? " - " : "") << "(" << location.file_name() << " l." << location.line() << ")" << std::endl;
|
|
}
|
|
//--------------------------------------------------------------
|