Logify/Suppression/LogifySuppression.mqh
2025-08-21 11:59:58 -03:00

336 lines
25 KiB
MQL5

//+------------------------------------------------------------------+
//| LogifySuppression.mqh |
//| Copyright 2023, MetaQuotes Ltd. |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, MetaQuotes Ltd."
#property link "https://www.mql5.com"
//+------------------------------------------------------------------+
//| Include files |
//+------------------------------------------------------------------+
#include "../LogifyModel.mqh"
//+------------------------------------------------------------------+
//| Validation constants |
//+------------------------------------------------------------------+
#define MAX_SUPPRESSION_MODE 255 // Maximum valid mode combination
#define MIN_THROTTLE_SECONDS 1 // Minimum interval between messages
#define MIN_REPEAT_COUNT 1 // Minimum number of repetitions
//+------------------------------------------------------------------+
//| ENUMS Suppression modes that can be combined using bitwise OR |
//+------------------------------------------------------------------+
enum ENUM_LOG_SUPRESSION_MODE
{
LOG_SUPRESSION_MODE_NONE = 0, // No suppression
LOG_SUPRESSION_MODE_CONSECUTIVE = 1 << 0, // Identical consecutive messages
LOG_SUPRESSION_MODE_THROTTLE_TIME = 1 << 1, // Same message within X seconds
LOG_SUPRESSION_MODE_BY_REPEAT_COUNT = 1 << 2, // After N repetitions
LOG_SUPRESSION_MODE_BY_ORIGIN = 1 << 3, // Based on message origin
LOG_SUPRESSION_MODE_BY_FILENAME = 1 << 4, // Based on source filename
};
//+------------------------------------------------------------------+
//| Struct: MqlLogifySuppressionConfig |
//+------------------------------------------------------------------+
struct MqlLogifySuppressionConfig
{
// Basic configuration
int mode; // Combination of suppression modes
int throttle_seconds; // Seconds between messages
int max_repeat_count; // Max repetitions before suppression
// Origin whitelist/blacklist
string allowed_origins[]; // If not empty, only these are allowed
string blocked_origins[]; // Always blocked
// Filename whitelist/blacklist
string allowed_filenames[]; // If not empty, only these are allowed
string blocked_filenames[]; // Always blocked
//--- Default constructor
MqlLogifySuppressionConfig(void)
{
mode = LOG_SUPRESSION_MODE_THROTTLE_TIME | LOG_SUPRESSION_MODE_CONSECUTIVE | LOG_SUPRESSION_MODE_BY_REPEAT_COUNT;
throttle_seconds = 5;
max_repeat_count = 15;
ArrayResize(allowed_origins, 0);
ArrayResize(blocked_origins, 0);
ArrayResize(allowed_filenames, 0);
ArrayResize(blocked_filenames, 0);
}
//--- Destructor
~MqlLogifySuppressionConfig(void)
{
}
//--- Helper methods for array configuration
void AddAllowedOrigin(string origin)
{
int size = ArraySize(allowed_origins);
ArrayResize(allowed_origins, size + 1);
allowed_origins[size] = origin;
}
void AddBlockedOrigin(string origin)
{
int size = ArraySize(blocked_origins);
ArrayResize(blocked_origins, size + 1);
blocked_origins[size] = origin;
}
void AddAllowedFilename(string filename)
{
int size = ArraySize(allowed_filenames);
ArrayResize(allowed_filenames, size + 1);
allowed_filenames[size] = filename;
}
void AddBlockedFilename(string filename)
{
int size = ArraySize(blocked_filenames);
ArrayResize(blocked_filenames, size + 1);
blocked_filenames[size] = filename;
}
//--- Validates configuration parameters
bool ValidateConfig(string &error_message)
{
if(throttle_seconds < MIN_THROTTLE_SECONDS)
{
error_message = "throttle_seconds must be greater than or equal to " + (string)MIN_THROTTLE_SECONDS;
return false;
}
if(max_repeat_count < MIN_REPEAT_COUNT)
{
error_message = "max_repeat_count must be greater than or equal to " + (string)MIN_REPEAT_COUNT;
return false;
}
if(mode < LOG_SUPRESSION_MODE_NONE || mode > MAX_SUPPRESSION_MODE)
{
error_message = "invalid suppression mode";
return false;
}
return true;
}
};
//+------------------------------------------------------------------+
//| class : CLogifySuppression |
//| |
//| [PROPERTY] |
//| Name : CLogifySuppression |
//| Heritage : No heritage |
//| Description : Class responsible for log message suppression, |
//| supports multiple suppression modes that can be combined: |
//| |
//| Suppression Modes |
//| - Consecutive : Blocks identical sequential messages |
//| - Throttle : Blocks messages within time window |
//| - RepeatCount : Blocks after N repetitions |
//| - Origin : Blocks based on message origin (white/blacklist)|
//| - Filename : Blocks based on source file (white/blacklist) |
//+------------------------------------------------------------------+
class CLogifySuppression
{
private:
//--- Configuration
MqlLogifySuppressionConfig m_config;
//--- State tracking
string m_last_message;
ENUM_LOG_LEVEL m_last_level;
int m_repeat_count;
datetime m_last_time;
//--- Helper methods for string comparison
bool StringContainsIgnoreCase(string text, string search_term);
public:
CLogifySuppression(void);
~CLogifySuppression(void);
//--- Configuration management
void SetConfig(MqlLogifySuppressionConfig &config);
MqlLogifySuppressionConfig GetConfig(void) const;
//--- State management
void Reset(void);
//--- Monitoring getters
int GetRepeatCount(void) const { return m_repeat_count; }
datetime GetLastMessageTime(void) const { return m_last_time; }
string GetLastMessage(void) const { return m_last_message; }
ENUM_LOG_LEVEL GetLastLevel(void) const { return m_last_level; }
//--- Main suppression logic
bool ShouldSuppress(MqlLogifyModel &data);
};
//+------------------------------------------------------------------+
//| Constructor |
//+------------------------------------------------------------------+
CLogifySuppression::CLogifySuppression(void)
{
Reset();
}
//+------------------------------------------------------------------+
//| Destructor |
//+------------------------------------------------------------------+
CLogifySuppression::~CLogifySuppression(void)
{
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CLogifySuppression::StringContainsIgnoreCase(string text, string search_term)
{
string text_lower = text;
string term_lower = search_term;
StringToLower(text_lower);
StringToLower(term_lower);
return StringFind(term_lower, text_lower) >= 0;
}
//+------------------------------------------------------------------+
//| Resets all internal state tracking |
//+------------------------------------------------------------------+
void CLogifySuppression::Reset(void)
{
m_last_message = "";
m_repeat_count = 0;
m_last_time = 0;
m_last_level = LOG_LEVEL_INFO;
}
//+------------------------------------------------------------------+
//| Updates suppression configuration |
//+------------------------------------------------------------------+
void CLogifySuppression::SetConfig(MqlLogifySuppressionConfig &config)
{
m_config = config;
string err_msg = "";
if(!m_config.ValidateConfig(err_msg))
{
Print("[ERROR] ["+TimeToString(TimeCurrent())+"] Log system error: "+err_msg);
}
}
//+------------------------------------------------------------------+
//| Returns current configuration |
//+------------------------------------------------------------------+
MqlLogifySuppressionConfig CLogifySuppression::GetConfig(void) const
{
return m_config;
}
//+------------------------------------------------------------------+
//| Checks if a message should be suppressed based on active modes |
//+------------------------------------------------------------------+
bool CLogifySuppression::ShouldSuppress(MqlLogifyModel &data)
{
datetime now = data.date_time;
//--- Check origin-based suppression
if((m_config.mode & LOG_SUPRESSION_MODE_BY_ORIGIN) == LOG_SUPRESSION_MODE_BY_ORIGIN)
{
//--- Check blacklist first
if(ArraySize(m_config.blocked_origins) > 0)
{
for(int i = 0; i < ArraySize(m_config.blocked_origins); i++)
{
if(StringContainsIgnoreCase(data.origin, m_config.blocked_origins[i]))
{
return true;
}
}
}
//--- Then check whitelist
if(ArraySize(m_config.allowed_origins) > 0)
{
bool origin_allowed = false;
for(int i = 0; i < ArraySize(m_config.allowed_origins); i++)
{
if(StringContainsIgnoreCase(data.origin, m_config.allowed_origins[i]))
{
origin_allowed = true;
break;
}
}
if(!origin_allowed)
{
return true;
}
}
}
//--- Check filename-based suppression
if((m_config.mode & LOG_SUPRESSION_MODE_BY_FILENAME) == LOG_SUPRESSION_MODE_BY_FILENAME)
{
//--- Check blacklist first
if(ArraySize(m_config.blocked_filenames) > 0)
{
for(int i = 0; i < ArraySize(m_config.blocked_filenames); i++)
{
if(StringContainsIgnoreCase(data.filename, m_config.blocked_filenames[i]))
{
return true;
}
}
}
//--- Then check whitelist
if(ArraySize(m_config.allowed_filenames) > 0)
{
bool filename_allowed = false;
for(int i = 0; i < ArraySize(m_config.allowed_filenames); i++)
{
if(StringContainsIgnoreCase(data.filename, m_config.allowed_filenames[i]))
{
filename_allowed = true;
break;
}
}
if(!filename_allowed)
{
return true;
}
}
}
//--- Reset counters if message or level changed
if(data.msg != m_last_message || data.level != m_last_level)
{
m_repeat_count = 0;
m_last_message = data.msg;
m_last_level = data.level;
m_last_time = now;
return false;
}
//--- Increment counter once per check
m_repeat_count++;
//--- Check suppression modes
if(((m_config.mode & LOG_SUPRESSION_MODE_BY_REPEAT_COUNT) == LOG_SUPRESSION_MODE_BY_REPEAT_COUNT)
&& m_repeat_count >= m_config.max_repeat_count)
{
return true;
}
if(((m_config.mode & LOG_SUPRESSION_MODE_THROTTLE_TIME) == LOG_SUPRESSION_MODE_THROTTLE_TIME)
&& (now - m_last_time) < m_config.throttle_seconds)
{
return true;
}
if((m_config.mode & LOG_SUPRESSION_MODE_CONSECUTIVE) == LOG_SUPRESSION_MODE_CONSECUTIVE)
{
return true;
}
m_last_time = now;
return false;
}
//+------------------------------------------------------------------+