336 lines
25 KiB
MQL5
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;
|
|
}
|
|
//+------------------------------------------------------------------+
|