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
|