CppBases/Utils/SimpleLogger.hpp

375 lines
14 KiB
C++
Raw Permalink Normal View History

2026-05-07 16:43:13 -05:00
//+------------------------------------------------------------------+
//| 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);
}
}