375 lines
No EOL
14 KiB
C++
375 lines
No EOL
14 KiB
C++
//+------------------------------------------------------------------+
|
|
//| SimpleLogger.hpp |
|
|
//| Copyright 2026, Niquel Mendoza. |
|
|
//| https://www.mql5.com/es/users/nique_372 |
|
|
//+------------------------------------------------------------------+
|
|
|
|
#pragma once
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Includes |
|
|
//+------------------------------------------------------------------+
|
|
#include <string>
|
|
#include <iostream>
|
|
#include <string_view>
|
|
#include <vector>
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Defines |
|
|
//+------------------------------------------------------------------+
|
|
namespace TSN
|
|
{
|
|
#ifdef _MSC_VER
|
|
#define FUNC_NAME __FUNCTION__
|
|
#define FORCE_INLINE __forceinline
|
|
#else
|
|
#define FUNC_NAME __func__
|
|
#define FORCE_INLINE inline __attribute__((always_inline))
|
|
#endif
|
|
|
|
//--- Log Flags
|
|
const constexpr unsigned char LOG_LEVEL_ERROR = 1; // 0001 - Critical errors
|
|
const constexpr unsigned char LOG_LEVEL_WARNING = 2; // 0010 - Warnings
|
|
const constexpr unsigned char LOG_LEVEL_INFO = 4; // 0100 - General information
|
|
const constexpr unsigned char LOG_LEVEL_CAUTION = 8; // 1000 - Cautions
|
|
const constexpr unsigned char LOG_ALL = LOG_LEVEL_CAUTION | LOG_LEVEL_INFO | LOG_LEVEL_WARNING;
|
|
|
|
//---
|
|
enum class ENUM_VERBOSE_LOG_LEVEL
|
|
{
|
|
VERBOSE_LOG_LEVEL_ERROR_ONLY = LOG_LEVEL_ERROR, // Only Errors
|
|
VERBOSE_LOG_LEVEL_WARNINGS = LOG_LEVEL_WARNING, // Warnings + Errors
|
|
VERBOSE_LOG_LEVEL_INFO = LOG_LEVEL_INFO, // Info + Errors
|
|
VERBOSE_LOG_LEVEL_CAUTION = LOG_LEVEL_CAUTION, // Caution + Errors
|
|
VERBOSE_LOG_LEVEL_WARNINGS_INFO = LOG_LEVEL_WARNING | LOG_LEVEL_INFO, // Warnings + Info + Errors
|
|
VERBOSE_LOG_LEVEL_WARNINGS_CAUTION = LOG_LEVEL_WARNING | LOG_LEVEL_CAUTION, // Warnings + Caution + Errors
|
|
VERBOSE_LOG_LEVEL_INFO_CAUTION = LOG_LEVEL_INFO | LOG_LEVEL_CAUTION, // Info + Caution + Errors
|
|
VERBOSE_LOG_LEVEL_ALL = (LOG_LEVEL_WARNING | LOG_LEVEL_INFO | LOG_LEVEL_CAUTION) // All: Warnings + Info + Caution + Errors
|
|
};
|
|
|
|
constexpr std::string_view WARNING_TEXT = "WARNING";
|
|
constexpr std::string_view CAUTION_TEXT = "CAUTION";
|
|
constexpr std::string_view INFO_TEXT = "INFO";
|
|
constexpr std::string_view ERROR_TEXT = "ERROR";
|
|
constexpr std::string_view CRITICAL_ERROR_TEXT = "CRITICAL ERROR";
|
|
constexpr std::string_view FATAL_ERROR_TEXT = "FATAL ERROR";
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Base Logging Class with Flag System |
|
|
//+------------------------------------------------------------------+
|
|
class CLoggerBase
|
|
{
|
|
private:
|
|
unsigned char m_log_flags; // Active logging flags
|
|
unsigned char m_last_flags; // Last active logging flags
|
|
|
|
|
|
//--- Main logging method with flags
|
|
FORCE_INLINE void RemoveFlag(unsigned char flags) noexcept { m_log_flags &= ~flags; }
|
|
|
|
protected:
|
|
//--- Flag-specific methods
|
|
FORCE_INLINE void LogWarning(const std::string& message, const std::string& function) const noexcept;
|
|
FORCE_INLINE void LogInfo(const std::string& message, const std::string& function) const noexcept;
|
|
FORCE_INLINE void LogCaution(const std::string& message, const std::string& function) const noexcept;
|
|
|
|
public:
|
|
CLoggerBase() noexcept;
|
|
virtual ~CLoggerBase() noexcept {}
|
|
|
|
//---
|
|
void ForceRemoveLogErrors() noexcept;
|
|
static FORCE_INLINE void LogError(const std::string& message, const std::string& function) noexcept;
|
|
static FORCE_INLINE void LogFatalError(const std::string& message, const std::string& function) noexcept;
|
|
static FORCE_INLINE void LogCriticalError(const std::string& message, const std::string& function) noexcept;
|
|
|
|
|
|
//--- Methods to check if a flag is active
|
|
FORCE_INLINE bool IsWarningLogEnabled() const noexcept { return (m_log_flags & LOG_LEVEL_WARNING) != 0; }
|
|
FORCE_INLINE bool IsInfoLogEnabled() const noexcept { return (m_log_flags & LOG_LEVEL_INFO) != 0; }
|
|
FORCE_INLINE bool IsCautionLogEnabled() const noexcept { return (m_log_flags & LOG_LEVEL_CAUTION) != 0; }
|
|
|
|
//--- Getters
|
|
FORCE_INLINE unsigned char LogFlags() const noexcept { return m_log_flags; }
|
|
inline bool IsLogEnabled(unsigned char flag) const noexcept { return (m_log_flags & flag) != 0; }
|
|
|
|
//--- Main configuration using flags
|
|
virtual inline void AddLogFlags(const unsigned char flags) noexcept;
|
|
virtual void RemoveLogFlags(const unsigned char flags) noexcept;
|
|
inline void ResetLastStateFlags() noexcept { m_log_flags = m_last_flags; }
|
|
|
|
//--- Disbale and Enable all logs
|
|
virtual void EnableAllLogs() noexcept;
|
|
virtual void DisableAllLogs() noexcept;
|
|
};
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Constructor |
|
|
//+------------------------------------------------------------------+
|
|
CLoggerBase::CLoggerBase(void) noexcept
|
|
{
|
|
m_log_flags = LOG_LEVEL_ERROR;
|
|
m_last_flags = LOG_LEVEL_ERROR;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
void CLoggerBase::ForceRemoveLogErrors(void) noexcept
|
|
{
|
|
m_last_flags = m_log_flags;
|
|
RemoveFlag(LOG_LEVEL_ERROR);
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
void CLoggerBase::DisableAllLogs() noexcept
|
|
{
|
|
m_log_flags = LOG_LEVEL_ERROR;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
void CLoggerBase::EnableAllLogs(void) noexcept
|
|
{
|
|
m_log_flags |= LOG_ALL;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
inline void CLoggerBase::AddLogFlags(const unsigned char flags) noexcept
|
|
{
|
|
m_last_flags = m_log_flags;
|
|
m_log_flags |= flags;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
void CLoggerBase::RemoveLogFlags(const unsigned char flags) noexcept
|
|
{
|
|
m_last_flags = m_log_flags;
|
|
unsigned char safe_flags = flags & ~LOG_LEVEL_ERROR;
|
|
RemoveFlag(safe_flags);
|
|
m_log_flags |= LOG_LEVEL_ERROR;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Método principal de logging |
|
|
//+------------------------------------------------------------------+
|
|
#define FastLog(function, class_info, message) std::cerr << "[" << class_info << "] " << function << " | " << message << std::endl
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Métodos específicos por flag |
|
|
//+------------------------------------------------------------------+
|
|
FORCE_INLINE void CLoggerBase::LogError(const std::string& message, const std::string& function) noexcept
|
|
{
|
|
FastLog(function, ERROR_TEXT, message);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
FORCE_INLINE void CLoggerBase::LogCriticalError(const std::string& message, const std::string& function) noexcept
|
|
{
|
|
FastLog(function, CRITICAL_ERROR_TEXT, message);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
FORCE_INLINE void CLoggerBase::LogFatalError(const std::string& message, const std::string& function) noexcept
|
|
{
|
|
FastLog(function, FATAL_ERROR_TEXT, message);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
FORCE_INLINE void CLoggerBase::LogWarning(const std::string& message, const std::string& function) const noexcept
|
|
{
|
|
if((m_log_flags & LOG_LEVEL_WARNING) != 0)
|
|
FastLog(function, WARNING_TEXT, message);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
FORCE_INLINE void CLoggerBase::LogInfo(const std::string& message, const std::string& function) const noexcept
|
|
{
|
|
if((m_log_flags & LOG_LEVEL_INFO) != 0)
|
|
FastLog(function, INFO_TEXT, message);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
FORCE_INLINE void CLoggerBase::LogCaution(const std::string& message, const std::string& function) const noexcept
|
|
{
|
|
if((m_log_flags & LOG_LEVEL_CAUTION) != 0)
|
|
FastLog(function, CAUTION_TEXT, message);
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Specialized Logger Manager Class port of MQL5 |
|
|
//+------------------------------------------------------------------+
|
|
//| Manages multiple loggers and propagates flags to all of them. |
|
|
//| This is like an evolution of CLoggerBase that can manage |
|
|
//| multiple child loggers and synchronize their logging levels. |
|
|
//+------------------------------------------------------------------+
|
|
class CSpecializedManager : public CLoggerBase
|
|
{
|
|
protected:
|
|
std::vector<CLoggerBase*> m_loggers; // Vector of logger pointers
|
|
|
|
//--- Propagate flags to all loggers
|
|
void PropagateFlags(const unsigned char flags, bool enable) noexcept;
|
|
|
|
//--- Remove logger by pointer
|
|
bool RemoveLogger(CLoggerBase* logger) noexcept;
|
|
|
|
//--- Delete logger if already exists
|
|
void DeleteLoggerAlreadyExist(CLoggerBase* logger) noexcept;
|
|
|
|
//--- Add logger (pointer version)
|
|
void AddLogger(CLoggerBase* logger) noexcept;
|
|
|
|
//--- Add logger (reference version)
|
|
FORCE_INLINE void AddLogger(CLoggerBase& logger) noexcept { AddLogger(&logger); }
|
|
|
|
//--- Clean loggers (with or without deletion)
|
|
virtual void CleanLoggers(bool delete_ptrs = true) noexcept;
|
|
|
|
public:
|
|
CSpecializedManager() noexcept;
|
|
virtual ~CSpecializedManager() noexcept {}
|
|
|
|
|
|
//--- Override flag methods to propagate
|
|
void AddLogFlags(const unsigned char flags) noexcept override;
|
|
void RemoveLogFlags(const unsigned char flags) noexcept override;
|
|
void EnableAllLogs() noexcept override;
|
|
void DisableAllLogs() noexcept override;
|
|
};
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Constructor |
|
|
//+------------------------------------------------------------------+
|
|
CSpecializedManager::CSpecializedManager() noexcept
|
|
: CLoggerBase()
|
|
{
|
|
m_loggers.clear();
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
void CSpecializedManager::AddLogger(CLoggerBase* logger) noexcept
|
|
{
|
|
if (!logger)
|
|
{
|
|
LogFatalError("Logger pointer is invalid", FUNC_NAME);
|
|
return;
|
|
}
|
|
|
|
m_loggers.push_back(logger);
|
|
logger->AddLogFlags(LogFlags());
|
|
|
|
LogInfo("Logger added. Total: " + std::to_string(m_loggers.size()), FUNC_NAME);
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
bool CSpecializedManager::RemoveLogger(CLoggerBase* logger) noexcept
|
|
{
|
|
if (!logger)
|
|
{
|
|
LogWarning("Removing a nullptr logger", FUNC_NAME);
|
|
return false;
|
|
}
|
|
|
|
for (size_t i = 0; i < m_loggers.size(); i++)
|
|
{
|
|
if (m_loggers[i] == logger)
|
|
{
|
|
m_loggers.erase(m_loggers.begin() + i);
|
|
LogInfo("Logger removed. Total: " + std::to_string(m_loggers.size()), FUNC_NAME);
|
|
return true;
|
|
}
|
|
}
|
|
|
|
LogWarning("Logger not found for removal", FUNC_NAME);
|
|
return false;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
void CSpecializedManager::DeleteLoggerAlreadyExist(CLoggerBase* logger) noexcept
|
|
{
|
|
if (!logger)
|
|
return;
|
|
|
|
for (size_t i = 0; i < m_loggers.size(); i++)
|
|
{
|
|
if (m_loggers[i] == logger)
|
|
{
|
|
delete m_loggers[i];
|
|
m_loggers.erase(m_loggers.begin() + i);
|
|
LogInfo("Logger deleted. Total: " + std::to_string(m_loggers.size()), FUNC_NAME);
|
|
return;
|
|
}
|
|
}
|
|
|
|
LogWarning("Logger not found for deletion", FUNC_NAME);
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
void CSpecializedManager::PropagateFlags(const unsigned char flags, bool enable) noexcept
|
|
{
|
|
for (auto logger : m_loggers)
|
|
{
|
|
if (logger)
|
|
{
|
|
if (enable)
|
|
logger->AddLogFlags(flags);
|
|
else
|
|
logger->RemoveLogFlags(flags);
|
|
}
|
|
}
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
void CSpecializedManager::AddLogFlags(const unsigned char flags) noexcept
|
|
{
|
|
CLoggerBase::AddLogFlags(flags);
|
|
PropagateFlags(flags, true);
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
void CSpecializedManager::RemoveLogFlags(const unsigned char flags) noexcept
|
|
{
|
|
CLoggerBase::RemoveLogFlags(flags);
|
|
PropagateFlags(flags, false);
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
void CSpecializedManager::EnableAllLogs() noexcept
|
|
{
|
|
CLoggerBase::EnableAllLogs();
|
|
for (auto logger : m_loggers)
|
|
{
|
|
if (logger)
|
|
logger->EnableAllLogs();
|
|
}
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
void CSpecializedManager::DisableAllLogs() noexcept
|
|
{
|
|
CLoggerBase::DisableAllLogs();
|
|
for (auto logger : m_loggers)
|
|
{
|
|
if (logger)
|
|
logger->DisableAllLogs();
|
|
}
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
void CSpecializedManager::CleanLoggers(bool delete_ptrs) noexcept
|
|
{
|
|
if (delete_ptrs)
|
|
{
|
|
for (auto logger : m_loggers)
|
|
{
|
|
if (logger) {
|
|
delete logger;
|
|
logger = nullptr;
|
|
}
|
|
}
|
|
}
|
|
m_loggers.clear();
|
|
LogInfo("All loggers cleaned", FUNC_NAME);
|
|
}
|
|
|
|
}
|
|
|