//+------------------------------------------------------------------+ //| LoggingManager.mqh | //| Universal Buffer Reader EA v2.0 | //+------------------------------------------------------------------+ #property copyright "Copyright 2025" #property link "" #property version "1.00" #property strict //+------------------------------------------------------------------+ //| CLoggingManager - Smart logging with error deduplication | //+------------------------------------------------------------------+ class CLoggingManager { private: bool m_enable_debug; string m_session_id; // Error tracking for deduplication struct ErrorRecord { int error_code; string error_message; int count; datetime first_seen; datetime last_seen; }; ErrorRecord m_error_records[]; int m_max_error_records; public: //+------------------------------------------------------------------+ //| Constructor | //+------------------------------------------------------------------+ CLoggingManager() { m_enable_debug = false; m_session_id = ""; m_max_error_records = 50; ArrayResize(m_error_records, 0); } //+------------------------------------------------------------------+ //| Destructor | //+------------------------------------------------------------------+ ~CLoggingManager() { ArrayResize(m_error_records, 0); } //+------------------------------------------------------------------+ //| Set parameters | //+------------------------------------------------------------------+ void SetParameters(bool enable_debug) { m_enable_debug = enable_debug; m_session_id = GenerateSessionID(); ClearErrorRecords(); } //+------------------------------------------------------------------+ //| Log info message | //+------------------------------------------------------------------+ void LogInfo(string message) { Print("[INFO] ", message); } //+------------------------------------------------------------------+ //| Log warning message | //+------------------------------------------------------------------+ void LogWarning(string message) { Print("[WARNING] ", message); } //+------------------------------------------------------------------+ //| Get error description | //+------------------------------------------------------------------+ string ErrorDescription(int error_code) { switch(error_code) { case 0: return "No error"; case 1: return "No error, but result is unknown"; case 2: return "Common error"; case 3: return "Invalid parameters"; case 4: return "Trade server is busy"; case 5: return "Old version of the client terminal"; case 6: return "No connection with trade server"; case 7: return "Not enough rights"; case 8: return "Too frequent requests"; case 9: return "Malfunctional trade operation"; case 64: return "Account disabled"; case 65: return "Invalid account"; case 128: return "Trade timeout"; case 129: return "Invalid price"; case 130: return "Invalid stops"; case 131: return "Invalid volume"; case 132: return "Market is closed"; case 133: return "Trade is disabled"; case 134: return "Not enough money"; case 135: return "Price changed"; case 136: return "No prices"; case 137: return "Broker is busy"; case 138: return "New prices (requote)"; case 139: return "Order locked"; case 140: return "Long positions only allowed"; case 141: return "Too many requests"; case 145: return "Modification denied because order is too close to market"; case 146: return "Trade context is busy"; case 147: return "Expirations are denied by broker"; case 148: return "Too many orders"; case 149: return "Hedge is prohibited"; case 150: return "Prohibited by FIFO rules"; case 4000: return "No error"; case 4001: return "Wrong function pointer"; case 4002: return "Array index is out of range"; case 4003: return "No memory for function call stack"; case 4004: return "Recursive stack overflow"; case 4005: return "Not enough stack for parameter"; case 4006: return "No memory for parameter string"; case 4007: return "No memory for temp string"; case 4008: return "Not initialized string"; case 4009: return "Not initialized arraystring"; case 4010: return "No memory for arraystring"; case 4011: return "Too long string"; case 4012: return "Remainder from zero divide"; case 4013: return "Zero divide"; case 4014: return "Unknown command"; case 4015: return "Wrong jump (never generated error)"; case 4016: return "Not initialized array"; case 4017: return "DLL calls are not allowed"; case 4018: return "Cannot load library"; case 4019: return "Cannot call function"; case 4020: return "External function calls are not allowed"; case 4021: return "Not enough memory for temp string"; case 4022: return "System is busy (never generated error)"; case 4023: return "Internal error"; case 4024: return "Out of memory"; case 4025: return "Invalid pointer"; case 4026: return "Too long string (up to 256 characters)"; case 4027: return "Structures or classes containing objects are not allowed"; case 4028: return "Not enough memory for string"; case 4029: return "Not enough memory for arraystring"; case 4030: return "Not enough memory for array"; case 4031: return "Unknown object type"; case 4032: return "Invalid object type"; case 4033: return "Object is not initialized"; case 4034: return "Cannot apply delete operation"; case 4035: return "Too many objects"; case 4036: return "Cannot create object"; case 4037: return "Invalid object pointer"; case 4038: return "Too many array dimensions"; case 4039: return "Access to arrayindex is out of range"; case 4040: return "Custom indicator error"; case 4041: return "Incorrect series array using"; case 4042: return "Custom indicator error"; case 4043: return "Arrays are incompatible"; case 4044: return "Series array cannot be used as timeseries"; case 4045: return "Custom indicator error"; case 4046: return "Internal error"; case 4047: return "Custom indicator error"; case 4048: return "Internal error"; case 4049: return "String error"; case 4050: return "String error"; case 4051: return "String error"; case 4052: return "String error"; case 4053: return "String error"; case 4054: return "Too long string"; case 4055: return "String error"; case 4056: return "String error"; case 4057: return "String error"; case 4058: return "String error"; case 4059: return "String error"; case 4060: return "String error"; case 4061: return "Array error"; case 4062: return "Array error"; case 4063: return "Array error"; case 4064: return "Array error"; case 4065: return "Array error"; case 4066: return "Array error"; case 4067: return "Array error"; case 4068: return "Array error"; case 4069: return "String error"; case 4070: return "String error"; case 4071: return "String error"; case 4072: return "String error"; case 4073: return "String error"; case 4074: return "String error"; case 4075: return "String error"; case 4076: return "String error"; case 4077: return "String error"; case 4078: return "String error"; case 4079: return "String error"; case 4080: return "String error"; case 4081: return "Too many array dimensions"; case 4082: return "Too many array dimensions"; case 4083: return "Too many array dimensions"; case 4084: return "Too many array dimensions"; case 4085: return "Array error"; case 4086: return "Array error"; case 4087: return "Array error"; case 4088: return "Array error"; case 4089: return "Array error"; case 4090: return "Array error"; case 4091: return "Array error"; case 4092: return "Array error"; case 4093: return "Array error"; case 4094: return "Array error"; case 4095: return "Array error"; case 4096: return "Array error"; case 4097: return "Array error"; case 4098: return "Array error"; case 4099: return "Array error"; case 4100: return "Array error"; case 4101: return "Array error"; case 4102: return "Array error"; case 4103: return "Array error"; case 4104: return "Array error"; case 4105: return "Array error"; case 4106: return "Array error"; case 4107: return "Array error"; case 4108: return "Array error"; case 4109: return "Array error"; case 4110: return "Array error"; case 4111: return "Array error"; case 4112: return "Array error"; case 4113: return "Array error"; case 4114: return "Array error"; case 4115: return "Array error"; case 4116: return "Array error"; case 4117: return "Array error"; case 4118: return "Array error"; case 4119: return "Array error"; case 4200: return "Object is not exist"; case 4201: return "Unknown object property"; case 4202: return "Object is not exist"; case 4203: return "Unknown object type"; case 4204: return "No object name"; case 4205: return "Object coordinates error"; case 4206: return "No specified subwindow"; case 4207: return "Some object error"; default: return "Unknown error code: " + IntegerToString(error_code); } } //+------------------------------------------------------------------+ //| Log error with deduplication | //+------------------------------------------------------------------+ void LogError(int error_code, string context) { string error_message = ErrorDescription(error_code); // Check if this error has been logged before if(IsErrorDuplicate(error_code, error_message)) { // Update existing record for(int i = 0; i < ArraySize(m_error_records); i++) { if(m_error_records[i].error_code == error_code && m_error_records[i].error_message == error_message) { m_error_records[i].count++; m_error_records[i].last_seen = TimeCurrent(); // Log with repetition count Print("[ERROR] ", FormatErrorMessage(error_code, context, m_error_records[i].count)); return; } } } else { // New error - add to tracking AddErrorRecord(error_code, error_message); Print("[ERROR] ", FormatErrorMessage(error_code, context, 1)); } } //+------------------------------------------------------------------+ //| Log debug message (only if enabled) | //+------------------------------------------------------------------+ void LogDebug(string message) { if(m_enable_debug) { Print("[DEBUG] ", message); } } //+------------------------------------------------------------------+ //| Clear error records | //+------------------------------------------------------------------+ void ClearErrorRecords() { ArrayResize(m_error_records, 0); } private: //+------------------------------------------------------------------+ //| Check if error has been logged before | //+------------------------------------------------------------------+ bool IsErrorDuplicate(int error_code, string error_message) { for(int i = 0; i < ArraySize(m_error_records); i++) { if(m_error_records[i].error_code == error_code && m_error_records[i].error_message == error_message) { return true; } } return false; } //+------------------------------------------------------------------+ //| Add error to tracking | //+------------------------------------------------------------------+ void AddErrorRecord(int error_code, string error_message) { int size = ArraySize(m_error_records); // Limit number of tracked errors if(size >= m_max_error_records) { // Remove oldest error by shifting elements for(int i = 0; i < size - 1; i++) { m_error_records[i] = m_error_records[i + 1]; } size = m_max_error_records - 1; } ArrayResize(m_error_records, size + 1); m_error_records[size].error_code = error_code; m_error_records[size].error_message = error_message; m_error_records[size].count = 1; m_error_records[size].first_seen = TimeCurrent(); m_error_records[size].last_seen = TimeCurrent(); } //+------------------------------------------------------------------+ //| Format error message for display | //+------------------------------------------------------------------+ string FormatErrorMessage(int error_code, string context, int count) { string error_msg = ErrorDescription(error_code); string result = error_msg + " (Code: " + IntegerToString(error_code) + ")"; if(count > 1) { result += " [REPEATED " + IntegerToString(count) + "x]"; } result += "\nContext: " + context; return result; } //+------------------------------------------------------------------+ //| Generate session ID | //+------------------------------------------------------------------+ string GenerateSessionID() { datetime now = TimeCurrent(); return TimeToString(now, TIME_DATE|TIME_MINUTES|TIME_SECONDS); } }; //+------------------------------------------------------------------+