Files
All-MQL5-code/Include/Strategy/Logs.mqh
T
Pierre8rTeam d2a192666b Commit
2018-06-23 11:25:42 +02:00

296 lines
26 KiB
Plaintext

//+------------------------------------------------------------------+
//| Logs.mqh |
//| Copyright 2015, Vasiliy Sokolov. |
//| http://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2015, Vasiliy Sokolov."
#property link "http://www.mql5.com"
#include <Object.mqh>
#include <Arrays\ArrayObj.mqh>
#include "Message.mqh"
//+------------------------------------------------------------------+
//| The class implements logging of messages as Singleton |
//+------------------------------------------------------------------+
class CLog
{
private:
static CLog* m_log; // A pointer to the global static sample
CArrayObj m_messages; // The list of saved messages
bool m_terminal_enable; // True if you need to print the received message to the trading terminal
bool m_push_enable; // True if a Push notification is sent
ENUM_MESSAGE_TYPE m_push_priority; // Contains the specified priority of message display in the terminal window.
ENUM_MESSAGE_TYPE m_terminal_priority; // Contains the specified priority of sending pushes to mobile devices.
bool m_recursive; // A flag indicating the recursive call of the destructor.
bool SendPush(CMessage *msg);
void CheckMessage(CMessage *msg);
CLog(void); // Private constructor
string GetName(void);
void DeleteOldLogs(int day_history=30);
void DeleteOldLog(string file_name,int day_history);
~CLog(void){;}
public:
static CLog *GetLog(void); // The method to receive a static object
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);
};
CLog *CLog::m_log;
//+------------------------------------------------------------------+
//| Constructor of the global object |
//+------------------------------------------------------------------+
CLog::CLog(void) : m_terminal_enable(true),
m_push_enable(false),
m_recursive(false)
{
DeleteOldLogs();
}
//+------------------------------------------------------------------+
//| Returns the logger object |
//+------------------------------------------------------------------+
static CLog *CLog::GetLog()
{
if(CheckPointer(m_log)==POINTER_INVALID)
m_log=new CLog();
return m_log;
}
//+------------------------------------------------------------------+
//| Deletes the logger object |
//+------------------------------------------------------------------+
bool CLog::DeleteLog(void)
{
bool res=CheckPointer(m_log)!=POINTER_INVALID;
if(res)
delete m_log;
return res;
}
//+------------------------------------------------------------------+
//| Returns a message with the specified index 'index' |
//+------------------------------------------------------------------+
CMessage *CLog::MessageAt(int index)const
{
CMessage *msg=m_messages.At(index);
return msg;
}
//+------------------------------------------------------------------+
//| Returns the total number of logs. |
//+------------------------------------------------------------------+
int CLog::Total(void)
{
return m_messages.Total();
}
//+------------------------------------------------------------------+
//| Saves a message to a CSV file. |
//+------------------------------------------------------------------+
bool CLog::Save(string path)
{
return false;
}
//+------------------------------------------------------------------+
//| Cleans the logger. |
//+------------------------------------------------------------------+
void CLog::Clear(void)
{
m_messages.Clear();
}
//+------------------------------------------------------------------+
//| Adds a new message to the list. |
//+------------------------------------------------------------------+
bool CLog::AddMessage(CMessage *msg)
{
CheckMessage(msg);
if(m_terminal_enable)
printf(msg.ToConsoleType());
if(m_push_enable)
SendPush(msg);
return m_messages.Add(msg);
}
//+------------------------------------------------------------------+
//| Sets a flag indicating whether it's necessary to display |
//| the passed message to platform window. |
//+------------------------------------------------------------------+
void CLog::TerminalEnable(bool enable)
{
m_terminal_enable=enable;
}
//+------------------------------------------------------------------+
//| Returns the flag indicating whether the received message is |
//| displayed in the trading platform window (Experts tab) |
//+------------------------------------------------------------------+
bool CLog::TerminalEnable(void)
{
return m_terminal_enable;
}
//+------------------------------------------------------------------+
//| Sets a flag indicating whether it's necessary to send |
//| the passed message to receivers' mobile devices. |
//+------------------------------------------------------------------+
void CLog::PushEnable(bool enable)
{
m_push_enable=enable;
}
//+------------------------------------------------------------------+
//| Returns the flag indicating whether the received message is |
//| sent as pushes to mobile devices. |
//+------------------------------------------------------------------+
bool CLog::PushEnable(void)
{
return m_push_enable;
}
//+------------------------------------------------------------------+
//| Sends a passed message as a pushe to mobile devices to specified |
//| recipients. Details: |
//| https://www.mql5.com/en/docs/common/sendnotification |
//| RETURN: |
//| True if successfully sent, false if otherwise |
//| |
//+------------------------------------------------------------------+
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;
}
//+------------------------------------------------------------------+
//| Sets the priority of sending push notifications to mobiles of |
//| recipients For example, if priority = MESSAGE_ERROR, all messages|
//| of type MESSAGE_INFO и MESSAGE_WARNING will not be sent. If |
//| priority = MESSAGE_WARNING, it will send messages of types |
//| MESSAGE_WARNING and MESSAGE_ERROR. |
//+------------------------------------------------------------------+
void CLog::PushPriority(ENUM_MESSAGE_TYPE priority)
{
m_push_priority=priority;
}
//+------------------------------------------------------------------+
//| Returns priority of push-notification sending |
//+------------------------------------------------------------------+
ENUM_MESSAGE_TYPE CLog::PushPriority(void)
{
return m_push_priority;
}
//+------------------------------------------------------------------+
//| Sets the priority of sending messages to the terminal |
//| For example, if priority = MESSAGE_ERROR, all messages of type |
//| MESSAGE_INFO and MESSAGE_WARNING aren't sent to terminal. If |
//| priority = MESSAGE_WARNING, it will send messages |
//| MESSAGE_WARNING and MESSAGE_ERROR. |
//+------------------------------------------------------------------+
void CLog::TerminalPriority(ENUM_MESSAGE_TYPE priority)
{
m_terminal_priority=priority;
}
//+------------------------------------------------------------------+
//| Returns the priority of terminal message sending. |
//+------------------------------------------------------------------+
ENUM_MESSAGE_TYPE CLog::TerminalPriority(void)
{
return m_terminal_priority;
}
//+------------------------------------------------------------------+
//| Checks if the sent message contains source and the text of the |
//| message. If it doesn't, creates a new warning |
//| message. |
//+------------------------------------------------------------------+
void CLog::CheckMessage(CMessage *msg)
{
if(msg.Source()==UNKNOW_SOURCE || msg.Source()==NULL || msg.Source()=="")
{
string text="The passed message does not contain its source of origin.";
CMessage *msg_info=new CMessage(MESSAGE_INFO,"CLog::AddMessage",text);
AddMessage(msg_info);
}
if(msg.Text()==NULL || msg.Text()=="")
{
string text="The passed message does not contain message text.";
CMessage *msg_info=new CMessage(MESSAGE_INFO,"CLog::AddMessage",text);
AddMessage(msg_info);
}
}
//+------------------------------------------------------------------+
//| Saves messages to a file, writing them to the end. |
//+------------------------------------------------------------------+
bool CLog::SaveToFile(void)
{
int h=INVALID_HANDLE;
// Make 3 attempts to open the file with a delay of 200 ms.
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;
}
//+------------------------------------------------------------------+
//| Generates a log name to record based on the current date. |
//+------------------------------------------------------------------+
string CLog::GetName(void)
{
string date=TimeToString(TimeCurrent(),TIME_DATE);
return "Logs\\log_"+date+".txt";
}
//+------------------------------------------------------------------+
//| Removes logs with the creation date older than day_history |
//| days (default 30 days). |
//+------------------------------------------------------------------+
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;
}
//+------------------------------------------------------------------+
//| Deletes a passed file if it is date is older than |
//| day_history days. |
//+------------------------------------------------------------------+
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);
}
//+------------------------------------------------------------------+