299 lines
26 KiB
Plaintext
299 lines
26 KiB
Plaintext
//+------------------------------------------------------------------+
|
|
//| Logs.mqh |
|
|
//| Copyright 2016, Vasiliy Sokolov, St-Petersburg, Russia |
|
|
//| https://www.mql5.com/en/users/c-4 |
|
|
//+------------------------------------------------------------------+
|
|
#property copyright "Copyright 2016, Vasiliy Sokolov."
|
|
#property link "https://www.mql5.com/en/users/c-4"
|
|
#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();
|
|
}
|
|
CLog::~CLog(void)
|
|
{
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| 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);
|
|
}
|
|
//+------------------------------------------------------------------+
|