UTE/Strategy/Logs.mqh
super.admin bd7e405a90 convert
2025-05-30 16:34:43 +02:00

355 lines
31 KiB
MQL5

//+------------------------------------------------------------------+
//| Logs.mqh |
//| Copyright 2016, Vasiliy Sokolov, St-Petersburg, Russia |
//| https://www.mql5.com/ru/users/c-4 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2016, Vasiliy Sokolov."
#property link "https://www.mql5.com/ru/users/c-4"
#include <Object.mqh>
#include <Arrays\ArrayObj.mqh>
#include "Message.mqh"
//+------------------------------------------------------------------+
//| Класс, организующий логирование сообщений, в виде синглтона |
//+------------------------------------------------------------------+
class CLog
{
private:
static CLog* m_log; // Указатель на глобальный статический экземпляр
CArrayObj m_messages; // Список сохраненных сообщений
bool m_terminal_enable; // Истина, если требуется выводить полученое сообщение в торговый терминал
ENUM_MESSAGE_TYPE m_terminal_priority; // Содержит заданный приоритет отсылки сообщений на мобильные устройства адресатов.
bool m_push_enable; // Если истина, происходит отправка Push-уведомлений.
ENUM_MESSAGE_TYPE m_push_priority; // Содержит заданный приоритет вывода сообщений в окно терминала.
bool m_email_enable; // Если истина, происходит отправка email-уведомлений.
ENUM_MESSAGE_TYPE m_email_priority; // Содержит заданный приоритет вывода сообщений email.
//
bool m_recursive; // Флаг указывающий на рекурсивный вызов деструктора.
void CheckMessage(CMessage *msg);
CLog(void); // Приватный конструктор
~CLog(void);
string GetName(void);
void DeleteOldLogs(int day_history=30);
void DeleteOldLog(string file_name,int day_history);
// Added in v1.10
bool SendPush(CMessage *msg);
bool SendEmail(CMessage *msg);
public:
static CLog *GetLog(void); // Метод, для получения статического объекта.
bool AddMessage(CMessage *msg);
void Clear(void);
bool Save(string path);
CMessage *MessageAt(int index)const;
int Total(void);
void TerminalEnable(bool enable);
bool TerminalEnable(void);
void PushEnable(bool enable);
bool PushEnable(void);
void PushPriority(ENUM_MESSAGE_TYPE type);
ENUM_MESSAGE_TYPE PushPriority(void);
void TerminalPriority(ENUM_MESSAGE_TYPE type);
ENUM_MESSAGE_TYPE TerminalPriority(void);
bool SaveToFile(void);
static bool DeleteLog(void);
// Added in v1.10
void EmailEnable(bool enable);
bool EmailEnable(void);
void EmailPriority(ENUM_MESSAGE_TYPE type);
ENUM_MESSAGE_TYPE EmailPriority(void);
};
CLog *CLog::m_log;
//+------------------------------------------------------------------+
//| Конструктор глобального объекта |
//+------------------------------------------------------------------+
CLog::CLog(void) : m_terminal_enable(true),
m_email_enable(false),
m_push_enable(false),
m_recursive(false)
{
DeleteOldLogs();
m_terminal_priority = MESSAGE_WARNING;
m_push_priority = MESSAGE_ERROR;
m_email_priority =MESSAGE_ERROR;
}
CLog::~CLog(void)
{
}
//+------------------------------------------------------------------+
//| Возвращает объект-логировщик |
//+------------------------------------------------------------------+
static CLog *CLog::GetLog()
{
if(CheckPointer(m_log)==POINTER_INVALID)
m_log=new CLog();
return m_log;
}
//+------------------------------------------------------------------+
//| Удаляет объект-логировщик |
//+------------------------------------------------------------------+
bool CLog::DeleteLog(void)
{
bool res=CheckPointer(m_log)!=POINTER_INVALID;
if(res)
delete m_log;
return res;
}
//+------------------------------------------------------------------+
//| Возвращает сообщение, находящееся по индексу index |
//+------------------------------------------------------------------+
CMessage *CLog::MessageAt(int index)const
{
CMessage *msg=m_messages.At(index);
return msg;
}
//+------------------------------------------------------------------+
//| Возвращает общее количество сообщений. |
//+------------------------------------------------------------------+
int CLog::Total(void)
{
return m_messages.Total();
}
//+------------------------------------------------------------------+
//| Сохраняет сообщения в CSV файл. |
//+------------------------------------------------------------------+
bool CLog::Save(string path)
{
return false;
}
//+------------------------------------------------------------------+
//| Очищает логировщик. |
//+------------------------------------------------------------------+
void CLog::Clear(void)
{
m_messages.Clear();
}
//+------------------------------------------------------------------+
//| Добавляет новое сообщение в список. |
//+------------------------------------------------------------------+
bool CLog::AddMessage(CMessage *msg)
{
CheckMessage(msg);
if((m_terminal_enable) & ((int)msg.Type()>=(int)m_terminal_priority))
printf(msg.ToConsoleType());
if((m_email_enable) & ((int)msg.Type()>=(int)m_email_priority))
SendEmail(msg);
if((m_push_enable) & ((int)msg.Type()>=(int)m_push_priority))
SendPush(msg);
return m_messages.Add(msg);
}
//+------------------------------------------------------------------+
//| Устанавливает флаг, указывающий необходимо ли выводить |
//| переданное сообщение в окно платформы. |
//+------------------------------------------------------------------+
void CLog::TerminalEnable(bool enable)
{
m_terminal_enable=enable;
}
//+------------------------------------------------------------------+
//| Возвращает флаг, указывающий, происходит ли вывод принятого |
//| сообщения в окно торговой платформы (вкладка эксперты) |
//+------------------------------------------------------------------+
bool CLog::EmailEnable(void)
{
return m_email_enable;
}
//+------------------------------------------------------------------+
//| Устанавливает флаг, указывающий необходимо ли выводить |
//| переданное сообщение в окно платформы. |
//+------------------------------------------------------------------+
void CLog::EmailEnable(bool enable)
{
m_email_enable=enable;
}
//+------------------------------------------------------------------+
//| Возвращает флаг, указывающий, происходит ли вывод принятого |
//| сообщения в окно торговой платформы (вкладка эксперты) |
//+------------------------------------------------------------------+
bool CLog::TerminalEnable(void)
{
return m_terminal_enable;
}
//+------------------------------------------------------------------+
//| Устанавливает флаг, указывающий, необходимо ли отправлять |
//| переданное сообщение на мобильные телефоны адресатов. |
//+------------------------------------------------------------------+
void CLog::PushEnable(bool enable)
{
m_push_enable=enable;
}
//+------------------------------------------------------------------+
//| Возвращает флаг, указывающий, происходит ли отправка push |
//| уведомлений на мобильные телефоны адресатов. |
//+------------------------------------------------------------------+
bool CLog::PushEnable(void)
{
return m_push_enable;
}
//+------------------------------------------------------------------+
//| Отправляет переданное сообщение на мобильные устройства указаным |
//| адресатам. Более подробно: |
//| https://www.mql5.com/ru/docs/common/sendnotification |
//| RETURN: |
//| Истина, если отправка прошла успешно, ложь в противном |
//| случае. |
//+------------------------------------------------------------------+
bool CLog::SendPush(CMessage *msg)
{
string d="\t";
string stype= EnumToString(msg.Type());
string date = TimeToString(msg.TimeServer(), TIME_DATE|TIME_MINUTES|TIME_SECONDS);
string line = stype + d + date + d + msg.Source() + d + msg.Text();
if(StringLen(line)>255)
line=StringSubstr(line,0,255);
bool res=SendNotification(line);
return res;
}
//+------------------------------------------------------------------+
//| Устанавливает приоритет отправки на мобильные устройства |
//| адресатов. Например если priority = MESSAGE_ERROR, все соообщения|
//| типа MESSAGE_INFO и MESSAGE_WARNING не попадут в отправку. Если |
//| priority = MESSAGE_WARNING, в отправку будут направлены сообщения|
//| типов MESSAGE_WARNING и MESSAGE_ERROR. |
//+------------------------------------------------------------------+
void CLog::PushPriority(ENUM_MESSAGE_TYPE priority)
{
m_push_priority=priority;
}
//+------------------------------------------------------------------+
//| Возвращает приоритет отправки push-сообщений. |
//+------------------------------------------------------------------+
ENUM_MESSAGE_TYPE CLog::PushPriority(void)
{
return m_push_priority;
}
//+------------------------------------------------------------------+
bool CLog::SendEmail(CMessage *msg)
{
string d="\t";
string stype= EnumToString(msg.Type());
string date = TimeToString(msg.TimeServer(), TIME_DATE|TIME_MINUTES);
string line = stype + d + date + d + msg.Source();
bool res=SendMail(line,msg.Text());
return res;
}
//+------------------------------------------------------------------+
//| Устанавливает приоритет отправки на email |
//+------------------------------------------------------------------+
void CLog::EmailPriority(ENUM_MESSAGE_TYPE priority)
{
m_email_priority=priority;
}
//+------------------------------------------------------------------+
//| Возвращает приоритет отправки email-сообщений. |
//+------------------------------------------------------------------+
ENUM_MESSAGE_TYPE CLog::EmailPriority(void)
{
return m_email_priority;
}
//+------------------------------------------------------------------+
//| Устанавливает приоритет отправки сообщения в терминал |
//| Например если priority = MESSAGE_ERROR, все соообщения |
//| типа MESSAGE_INFO и MESSAGE_WARNING не попадут в терминал. Если |
//| priority = MESSAGE_WARNING, в терминал будут направлены сообщения|
//| типов MESSAGE_WARNING и MESSAGE_ERROR. |
//+------------------------------------------------------------------+
void CLog::TerminalPriority(ENUM_MESSAGE_TYPE priority)
{
m_terminal_priority=priority;
}
//+------------------------------------------------------------------+
//| Возвращает приоритет отправки терминальных сообщений. |
//+------------------------------------------------------------------+
ENUM_MESSAGE_TYPE CLog::TerminalPriority(void)
{
return m_terminal_priority;
}
//+------------------------------------------------------------------+
//| Проверяет заполнены ли в переданном сообщении источник, текст |
//| сообщения. Если нет, создает новое предупреждающее об этом |
//| сообщение. |
//+------------------------------------------------------------------+
void CLog::CheckMessage(CMessage *msg)
{
if(msg.Source()==UNKNOW_SOURCE || msg.Source()==NULL || msg.Source()=="")
{
string text="Переданное сообщение не содержит источника его создания.";
CMessage *msg_info=new CMessage(MESSAGE_INFO,"CLog::AddMessage",text);
AddMessage(msg_info);
}
if(msg.Text()==NULL || msg.Text()=="")
{
string text="Переданное сообщение не содержит текста сообщения.";
CMessage *msg_info=new CMessage(MESSAGE_INFO,"CLog::AddMessage",text);
AddMessage(msg_info);
}
}
//+------------------------------------------------------------------+
//| Сохраняет сообщения в файл. Дописывая их в конец. |
//+------------------------------------------------------------------+
bool CLog::SaveToFile(void)
{
int h=INVALID_HANDLE;
// Делаем три попытки на открытие файла с задержкой 200 мсек.
for(int i=0; i<3; i++)
{
h=FileOpen(GetName(),FILE_TXT|FILE_READ|FILE_WRITE|FILE_COMMON);
if(h!=INVALID_HANDLE)break;
Sleep(200);
}
if(h==INVALID_HANDLE)
{
string text="Unable to open file "+GetName()+" Reason: "+(string)GetLastError();
CMessage *msg=new CMessage(MESSAGE_ERROR,__FUNCTION__,text);
m_log.AddMessage(msg);
return false;
}
FileSeek(h,0,SEEK_END);
for(int i=0; i<m_messages.Total(); i++)
{
CMessage *msg=m_messages.At(i);
FileWriteString(h,msg.ToCSVType()+"\n");
}
FileClose(h);
return true;
}
//+------------------------------------------------------------------+
//| Генерирует имя лога для записи, опираясь на текущую дату. |
//+------------------------------------------------------------------+
string CLog::GetName(void)
{
string date=TimeToString(TimeCurrent(),TIME_DATE);
return "Logs\\log_"+date+".txt";
}
//+------------------------------------------------------------------+
//| Удаляет логи сообщений, чья дата создания старше day_history |
//| дней (по умолчанию 30 дней). |
//+------------------------------------------------------------------+
void CLog::DeleteOldLogs(int day_history=30)
{
string file_name="";
string filter="Logs\\log_*.txt";
long h=FileFindFirst(filter,file_name,FILE_COMMON);
DeleteOldLog("Logs\\"+file_name,day_history);
while(FileFindNext(h,file_name))
DeleteOldLog("Logs\\"+file_name,day_history);
int b=2;
}
//+------------------------------------------------------------------+
//| Удаляет переданный файл, если его дата создания старше |
//| day_history дней. |
//+------------------------------------------------------------------+
void CLog::DeleteOldLog(string file_name,int day_history)
{
int h= FileOpen(file_name,FILE_READ|FILE_BIN|FILE_COMMON);
if(h == INVALID_HANDLE)return;
MqlDateTime dt;
TimeToStruct((datetime)FileGetInteger(h,FILE_ACCESS_DATE),dt);
int seconds=(int)(TimeCurrent()-FileGetInteger(h,FILE_CREATE_DATE));
FileClose(h);
int days = seconds/3600/24;
if(days >= day_history)
FileDelete(file_name,FILE_COMMON);
}
//+------------------------------------------------------------------+