348 lines
12 KiB
MQL5
348 lines
12 KiB
MQL5
//+------------------------------------------------------------------+
|
|
//| CErrorHandling.mqh - Centralized Error Management System |
|
|
//| Provides structured error handling across all subsystems |
|
|
//+------------------------------------------------------------------+
|
|
#ifndef CERROR_HANDLING_MQH
|
|
#define CERROR_HANDLING_MQH
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Error Severity Levels |
|
|
//+------------------------------------------------------------------+
|
|
enum ENUM_ERROR_SEVERITY
|
|
{
|
|
ERR_SEVERITY_INFO = 0, // Informational, no action needed
|
|
ERR_SEVERITY_WARNING = 1, // Warning, operation can continue
|
|
ERR_SEVERITY_ERROR = 2, // Error, current operation failed
|
|
ERR_SEVERITY_CRITICAL = 3, // Critical, system stability at risk
|
|
ERR_SEVERITY_FATAL = 4 // Fatal, shutdown required
|
|
};
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Error Categories |
|
|
//+------------------------------------------------------------------+
|
|
enum ENUM_ERROR_CATEGORY
|
|
{
|
|
ERR_CAT_NONE = 0,
|
|
ERR_CAT_INIT = 1, // Initialization
|
|
ERR_CAT_MEMORY = 2, // Memory/Allocation
|
|
ERR_CAT_FILE = 3, // File I/O
|
|
ERR_CAT_NETWORK = 4, // Network/HTTP
|
|
ERR_CAT_TRADE = 5, // Trade execution
|
|
ERR_CAT_GATE = 6, // Gate system
|
|
ERR_CAT_SQLITE = 7, // SQLite operations
|
|
ERR_CAT_CONFIG = 8, // Configuration
|
|
ERR_CAT_SYSTEM = 9 // General system
|
|
};
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Error Context Structure |
|
|
//+------------------------------------------------------------------+
|
|
struct SErrorContext
|
|
{
|
|
datetime timestamp;
|
|
ENUM_ERROR_SEVERITY severity;
|
|
ENUM_ERROR_CATEGORY category;
|
|
string source; // Component name
|
|
string function; // Function name
|
|
int code; // Error code
|
|
string message; // Human-readable message
|
|
string details; // Additional details
|
|
|
|
void Init(ENUM_ERROR_SEVERITY sev, ENUM_ERROR_CATEGORY cat,
|
|
const string src, const string func, int err_code,
|
|
const string msg, const string det = "")
|
|
{
|
|
timestamp = TimeCurrent();
|
|
severity = sev;
|
|
category = cat;
|
|
source = src;
|
|
function = func;
|
|
code = err_code;
|
|
message = msg;
|
|
details = det;
|
|
}
|
|
|
|
string ToString()
|
|
{
|
|
return StringFormat("[%s] %s | %s.%s | Code=%d | %s%s",
|
|
TimeToString(timestamp, TIME_DATE|TIME_SECONDS),
|
|
SeverityToString(severity),
|
|
source, function, code, message,
|
|
StringLen(details) > 0 ? " | " + details : "");
|
|
}
|
|
|
|
static string SeverityToString(ENUM_ERROR_SEVERITY sev)
|
|
{
|
|
switch(sev)
|
|
{
|
|
case ERR_SEVERITY_INFO: return "INFO";
|
|
case ERR_SEVERITY_WARNING: return "WARN";
|
|
case ERR_SEVERITY_ERROR: return "ERROR";
|
|
case ERR_SEVERITY_CRITICAL: return "CRITICAL";
|
|
case ERR_SEVERITY_FATAL: return "FATAL";
|
|
}
|
|
return "UNKNOWN";
|
|
}
|
|
};
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Error Handler Class |
|
|
//+------------------------------------------------------------------+
|
|
class CErrorHandler
|
|
{
|
|
private:
|
|
SErrorContext m_error_history[];
|
|
int m_history_size;
|
|
int m_history_index;
|
|
int m_error_counts[5]; // Per severity
|
|
int m_category_counts[10]; // Per category
|
|
|
|
// Circuit breaker for repeated errors
|
|
datetime m_last_error_time;
|
|
int m_recent_error_count;
|
|
int m_circuit_breaker_threshold;
|
|
int m_circuit_breaker_window_sec;
|
|
|
|
public:
|
|
CErrorHandler()
|
|
{
|
|
m_history_size = 100;
|
|
m_history_index = 0;
|
|
ArrayResize(m_error_history, m_history_size);
|
|
|
|
for(int i = 0; i < 5; i++) m_error_counts[i] = 0;
|
|
for(int i = 0; i < 10; i++) m_category_counts[i] = 0;
|
|
|
|
m_last_error_time = 0;
|
|
m_recent_error_count = 0;
|
|
m_circuit_breaker_threshold = 10;
|
|
m_circuit_breaker_window_sec = 60;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Log an error to history |
|
|
//+------------------------------------------------------------------+
|
|
void LogError(ENUM_ERROR_SEVERITY severity, ENUM_ERROR_CATEGORY category,
|
|
const string source, const string function, int code,
|
|
const string message, const string details = "")
|
|
{
|
|
// Create error context
|
|
SErrorContext ctx;
|
|
ctx.Init(severity, category, source, function, code, message, details);
|
|
|
|
// Add to ring buffer
|
|
m_error_history[m_history_index] = ctx;
|
|
m_history_index = (m_history_index + 1) % m_history_size;
|
|
|
|
// Update counters
|
|
m_error_counts[severity]++;
|
|
m_category_counts[category]++;
|
|
|
|
// Check circuit breaker
|
|
CheckCircuitBreaker();
|
|
|
|
// Always print critical/fatal immediately
|
|
if(severity >= ERR_SEVERITY_CRITICAL)
|
|
{
|
|
Print(ctx.ToString());
|
|
}
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Convenience methods |
|
|
//+------------------------------------------------------------------+
|
|
void Info(ENUM_ERROR_CATEGORY cat, const string src, const string func,
|
|
const string msg, const string det = "")
|
|
{
|
|
LogError(ERR_SEVERITY_INFO, cat, src, func, 0, msg, det);
|
|
}
|
|
|
|
void Warning(ENUM_ERROR_CATEGORY cat, const string src, const string func,
|
|
int code, const string msg, const string det = "")
|
|
{
|
|
LogError(ERR_SEVERITY_WARNING, cat, src, func, code, msg, det);
|
|
}
|
|
|
|
void Error(ENUM_ERROR_CATEGORY cat, const string src, const string func,
|
|
int code, const string msg, const string det = "")
|
|
{
|
|
LogError(ERR_SEVERITY_ERROR, cat, src, func, code, msg, det);
|
|
}
|
|
|
|
void Critical(ENUM_ERROR_CATEGORY cat, const string src, const string func,
|
|
int code, const string msg, const string det = "")
|
|
{
|
|
LogError(ERR_SEVERITY_CRITICAL, cat, src, func, code, msg, det);
|
|
}
|
|
|
|
void Fatal(ENUM_ERROR_CATEGORY cat, const string src, const string func,
|
|
int code, const string msg, const string det = "")
|
|
{
|
|
LogError(ERR_SEVERITY_FATAL, cat, src, func, code, msg, det);
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Get error statistics |
|
|
//+------------------------------------------------------------------+
|
|
int GetErrorCount(ENUM_ERROR_SEVERITY sev) { return m_error_counts[sev]; }
|
|
int GetCategoryCount(ENUM_ERROR_CATEGORY cat) { return m_category_counts[cat]; }
|
|
|
|
string GetErrorSummary()
|
|
{
|
|
string summary = "=== Error Summary ===\n";
|
|
summary += StringFormat("Total Errors: %d (Info:%d Warn:%d Err:%d Crit:%d Fatal:%d)\n",
|
|
GetTotalErrorCount(),
|
|
m_error_counts[ERR_SEVERITY_INFO],
|
|
m_error_counts[ERR_SEVERITY_WARNING],
|
|
m_error_counts[ERR_SEVERITY_ERROR],
|
|
m_error_counts[ERR_SEVERITY_CRITICAL],
|
|
m_error_counts[ERR_SEVERITY_FATAL]);
|
|
|
|
summary += "By Category:\n";
|
|
for(int i = 1; i < 10; i++)
|
|
{
|
|
if(m_category_counts[i] > 0)
|
|
summary += StringFormat(" %s: %d\n", CategoryToString(i), m_category_counts[i]);
|
|
}
|
|
|
|
return summary;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Get recent errors (last N) |
|
|
//+------------------------------------------------------------------+
|
|
string GetRecentErrors(int count = 10)
|
|
{
|
|
string result = "=== Recent Errors ===\n";
|
|
int start = m_history_index - MathMin(count, m_history_size);
|
|
if(start < 0) start += m_history_size;
|
|
|
|
for(int i = 0; i < MathMin(count, m_history_size); i++)
|
|
{
|
|
int idx = (start + i) % m_history_size;
|
|
if(StringLen(m_error_history[idx].message) > 0)
|
|
result += m_error_history[idx].ToString() + "\n";
|
|
}
|
|
return result;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Circuit breaker check |
|
|
//+------------------------------------------------------------------+
|
|
bool IsCircuitBreakerTripped()
|
|
{
|
|
return m_recent_error_count >= m_circuit_breaker_threshold;
|
|
}
|
|
|
|
void ResetCircuitBreaker()
|
|
{
|
|
m_recent_error_count = 0;
|
|
m_last_error_time = 0;
|
|
}
|
|
|
|
private:
|
|
int GetTotalErrorCount()
|
|
{
|
|
int total = 0;
|
|
for(int i = 0; i < 5; i++) total += m_error_counts[i];
|
|
return total;
|
|
}
|
|
|
|
void CheckCircuitBreaker()
|
|
{
|
|
datetime now = TimeCurrent();
|
|
if(now - m_last_error_time <= m_circuit_breaker_window_sec)
|
|
{
|
|
m_recent_error_count++;
|
|
}
|
|
else
|
|
{
|
|
m_recent_error_count = 1;
|
|
}
|
|
m_last_error_time = now;
|
|
|
|
if(IsCircuitBreakerTripped())
|
|
{
|
|
Print(StringFormat("[CIRCUIT BREAKER] %d errors in %d seconds - throttling error logging",
|
|
m_recent_error_count, m_circuit_breaker_window_sec));
|
|
}
|
|
}
|
|
|
|
static string CategoryToString(int cat)
|
|
{
|
|
switch(cat)
|
|
{
|
|
case ERR_CAT_INIT: return "INIT";
|
|
case ERR_CAT_MEMORY: return "MEMORY";
|
|
case ERR_CAT_FILE: return "FILE";
|
|
case ERR_CAT_NETWORK: return "NETWORK";
|
|
case ERR_CAT_TRADE: return "TRADE";
|
|
case ERR_CAT_GATE: return "GATE";
|
|
case ERR_CAT_SQLITE: return "SQLITE";
|
|
case ERR_CAT_CONFIG: return "CONFIG";
|
|
case ERR_CAT_SYSTEM: return "SYSTEM";
|
|
}
|
|
return "UNKNOWN";
|
|
}
|
|
};
|
|
|
|
// Global error handler instance
|
|
CErrorHandler* g_error_handler = NULL;
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Initialize error handling |
|
|
//+------------------------------------------------------------------+
|
|
bool InitializeErrorHandling()
|
|
{
|
|
if(g_error_handler != NULL)
|
|
delete g_error_handler;
|
|
|
|
g_error_handler = new CErrorHandler();
|
|
|
|
Print("[ErrorHandling] Initialized");
|
|
return true;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Shutdown error handling |
|
|
//+------------------------------------------------------------------+
|
|
void ShutdownErrorHandling()
|
|
{
|
|
if(g_error_handler != NULL)
|
|
{
|
|
// Avoid macro collisions on method name resolution.
|
|
// Summary can be printed by call sites that include this header.
|
|
delete g_error_handler;
|
|
g_error_handler = NULL;
|
|
}
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Convenience macros for error logging |
|
|
//+------------------------------------------------------------------+
|
|
#ifdef LOG_INFO
|
|
#undef LOG_INFO
|
|
#endif
|
|
#ifdef LOG_DEBUG
|
|
#undef LOG_DEBUG
|
|
#endif
|
|
#ifdef LOG_WARNING
|
|
#undef LOG_WARNING
|
|
#endif
|
|
#ifdef LOG_ERROR
|
|
#undef LOG_ERROR
|
|
#endif
|
|
|
|
#define LOG_INFO(cat, msg) \
|
|
do { if(g_error_handler != NULL) g_error_handler->Info(cat, __FILE__, __FUNCTION__, msg); } while(0)
|
|
|
|
#define LOG_WARN(cat, code, msg) \
|
|
do { if(g_error_handler != NULL) g_error_handler->Warning(cat, __FILE__, __FUNCTION__, code, msg); } while(0)
|
|
|
|
#define LOG_ERROR(cat, code, msg) \
|
|
do { if(g_error_handler != NULL) g_error_handler->Error(cat, __FILE__, __FUNCTION__, code, msg); } while(0)
|
|
|
|
#define LOG_CRITICAL(cat, code, msg) \
|
|
do { if(g_error_handler != NULL) g_error_handler->Critical(cat, __FILE__, __FUNCTION__, code, msg); } while(0)
|
|
|
|
#endif // CERROR_HANDLING_MQH
|