English Русский 中文 Español Deutsch 日本語 Português 한국어 Français Türkçe
Ricerca di Errori e Registrazione

Ricerca di Errori e Registrazione

MetaTrader 5Esempi | 16 dicembre 2021, 11:02
159 0
Дмитрий Александрович
Дмитрий Александрович

Introduzione

Ciao, cari lettori!

In questo articolo considereremo diversi modi per trovare errori in Expert Advisor / Script / Indicatori e metodi di logging. Inoltre ti offrirò un piccolo programma per visualizzare i log - LogMon.

Trovare errori è parte integrante della programmazione. Mentre scrivi un nuovo blocco di codice, è necessario verificare se funziona correttamente e non presenta errori logici. È possibile trovare un errore nel programma in tre modi diversi:

  1. Valutazione del risultato finale  
  2. Debug passo dopo passo  
  3. Scrittura di passaggi logici nel log

Considera ogni modo.

1. Valutazione del Risultato Finale

Con questo metodo, analizziamo il risultato del lavoro del programma o parte del suo codice. Ad esempio, prendi un codice semplice, che contiene un errore evidente fatto solo per chiarezza:

void OnStart()
  {
//---
   int intArray[10];
   for(int i=0;i<9;i++)
     {
      intArray[i]=i;
     }
   Alert(intArray[9]);

  }

Compila ed esegui e sullo schermo verrà visualizzato "0". Analizzando i risultati ci aspettiamo il numero "9", quindi concludiamo che il nostro programma non funziona come dovrebbe. Questo metodo di ricerca degli errori è comune e non riesce a trovare la posizione dell'errore. Considerando il secondo modo di trovare gli errori, useremo il debug.  

2. Debug Passo per Passo

Questo metodo consente di trovare esattamente il luogo in cui la logica del programma è stata violata. In MetaEditor inserisci un punto di interruzione all'interno del ciclo 'for', inizia il debug e aggiungi watch per la variabile i:

Debug

Quindi fare clic su "Riprendi il debug" per tutto il tempo in cui consideriamo l'intero processo di lavoro del programma. Vediamo che poiché la variabile "i" ha il valore di "8", usciamo dal ciclo, quindi concludiamo che l'errore è nella riga:

for(int i=0;i<9;i++)

Vale a dire, quando vengono confrontati il valore di i e il numero 9. Correggi la riga "i<9" " a "i<10" o a "i< = 9", controlla i risultati. Otteniamo il numero 9 - esattamente quello che ci aspettavamo. Utilizzando il debug, abbiamo imparato come agisce il programma in fase di esecuzione e siamo stati in grado di risolvere il problema. I contro di questo metodo:

  1. Non è chiaro dove si sia verificato l'errore, per intuizione.
  2. È necessario aggiungere variabili all'elenco di controllo e visualizzarle dopo ogni passaggio.
  3. Questo metodo non è in grado di rilevare errori durante l'esecuzione del programma finito, come il trading EA su account reale o demo.

Infine, considera il terzo modo di trovare gli errori.

3. Scrittura di Passaggi Logici nel Log

Utilizzando questo metodo, registriamo i passaggi significativi del nostro programma. Ad esempio: inizializzazione, calcolo dell'indicatore, ecc. Aggiorna il nostro script con una riga di codice. Vale a dire, stamperemo il valore della variabile i su ogni iterazione:

void OnStart()
  {
//---
   int intArray[10];
   for(int i=0;i<9;i++)
     {
      intArray[i]=i;
      Alert(i);
     }
   Alert(intArray[9]);

  }

Esegui e vedi l'output del registro - numeri "0 1 2 3 4 5 6 7 8 0". Concludi perché può essere così e correggi lo script, proprio come l'ultima volta.

Pro e contro di questo metodo di ricerca degli errori:

  1. + Non è necessario eseguire il programma passo dopo passo, in modo da risparmiare molto tempo.
  2. + Spesso è evidente dove si trova l'errore.
  3. + Puoi continuare a registrare mentre il programma viene eseguito.
  4. + È possibile salvare il registro per un'analisi e un confronto successivi (ad esempio, quando si scrive in un file. Vedi sotto.).
  5. - Il codice sorgente cresce di dimensioni grazie all'aggiunta di operatori che scrivono i dati nel log.
  6. - Aumento del runtime del programma (principalmente importante per l'ottimizzazione).

Sommario:

Il primo modo per trovare gli errori non può tenere traccia di dove si trova effettivamente l'errore. Lo usiamo principalmente per la sua velocità. Il secondo modo: il debug passo-passo consente di trovare la posizione esatta dell'errore, ma richiede molto tempo. E se scivolerai oltre il blocco di codice desiderato, devi ricominciare tutto da capo.

Infine, il terzo modo: la registrazione dei passaggi logici nel log consente di analizzare rapidamente il lavoro del programma e salvare il risultato. Durante la scrittura degli eventi dei tuoi Expert Advisor / Indicatori / Script nel log, puoi facilmente trovare un errore e non devi cercare le giuste condizioni in cui si verifica un errore e non devi eseguire il debug del tuo programma per ore e ore. Successivamente, considereremo i modi di accedere ai dettagli e confrontarli. Inoltre ti offrirò il modo più conveniente e veloce.

Quando è necessario effettuare il log?

Ecco alcuni motivi per il logging:
  1. Comportamento errato del programma.
  2. Runtime del programma troppo lungo (ottimizzazione).
  3. Monitoraggio del runtime (notifiche di stampa delle posizioni di apertura/chiusura, azioni eseguite, ecc.).  
  4. Apprendimento di MQL5, ad esempio - stampa di matrici.  
  5. Controllare gli Expert Advisor prima del campionato, ecc.

Metodi di Logging

Esistono molti modi per scrivere messaggi nel log, ma alcuni sono utilizzati in tutto, mentre altri sono necessari in casi speciali. Ad esempio, l'invio del log via e-mail o tramite ICQ non è sempre necessario.  

Ecco l'elenco dei metodi più comuni utilizzati nella programmazione MQL5:

  1. Utilizzo della funzione Comment()
  2. Utilizzo della funzione Alert()
  3. Utilizzo della funzione Print()
  4. Scrivere il log nel file utilizzando la funzione FileWrite()

Successivamente fornirò esempi di ciascun metodo con codici sorgente e descriverò le caratteristiche di ciascun metodo. Questi codici sorgente sono piuttosto astratti, quindi non andremo lontano dall'essenza.

Utilizzo della Funzione Comment()

void OnStart()
  {
//---
   int intArray[10];
   for(int i=0;i<10;i++)
     {
      intArray[i]=i;
      Comment("Variable i: ",i);
      Sleep(5000);
     }
   Alert(intArray[9]);
  }

Quindi, nell'angolo in alto a sinistra vediamo il valore corrente della variabile "i":

Comment()

In questo modo possiamo monitorare lo stato corrente del programma in esecuzione. Ora i pro ei contro:

  1. + Puoi vedere immediatamente il valore.
  2. - Limitazione dell'output.
  3. - Non è possibile selezionare alcun messaggio particolare.
  4. - Non vedi il suo lavoro in tutto il runtime, solo lo stato corrente.
  5. - Metodo relativamente lento.
  6. - Inadatto per il monitoraggio continuo del lavoro, in quanto è sempre necessario guardare la lettura.

La funzione Comment() è utile per visualizzare lo stato corrente di un Expert Advisor. Ad esempio, "Apri 2 deal" o "acquista lotto GBRUSD: 0,7".  

Utilizzo della Funzione Alert()

Questa funzione visualizza i messaggi in una finestra separata con notifica sonora. L'esempio di codice:

void OnStart()
  {
//---
   Alert("Start script");
   int intArray[10];
   for(int i=0;i<10;i++)
     {
      intArray[i]=i;
      Alert("Variable i:", I);
      Sleep(1000);
     }
   Alert(intArray[9]);
   Alert("Stop script");
  }
Il risultato dell'esecuzione del codice:  

Alert()

E ora siamo al settimo cielo, tutto è immediatamente evidente anche con il suono. Ma ora i pro e i contro:

  1. + Tutti i messaggi vengono registrati in modo coerente.
  2. + Notifica sonora.
  3. + Tutto è scritto nel file "Terminal_dir\MQL5\Logs\data.txt".
  4. - Tutti i messaggi provenienti da tutti gli script / Expert Advisor / Indicatori sono scritti in un unico log.
  5. - Non funziona in Strategy Tester.
  6. - Quando viene chiamato frequentemente, può bloccare il terminale per un lungo periodo (ad esempio, quando si chiama ogni segno di spunta o quando si stampa l'array in loop).
  7. - Impossibile raggruppare i messaggi.
  8. - Visualizzazione scomoda del file di log.
  9. - Impossibile salvare i messaggi in una cartella diversa dalla cartella dati standard.

Il sesto punto è molto critico nel trading reale, specialmente quando si esegue lo scalping o si modifica lo Stop Loss. Ci sono tanti contro e puoi trovarne altri, ma penso che sia abbastanza.  

Utilizzo della Funzione Print()

Questa funzione scrive i messaggi di log in una finestra speciale chiamata "Experts". Ecco il codice:

void OnStart()
  {
//---
   Print("Старт скрипта");
   int intArray[10];
   for(int i=0;i<10;i++)
     {
      intArray[i]=i;
      Print("Variable i: ",i);
     }
   Print(intArray[9]);
   Print("Stop script");
  }

Print()

Come puoi vedere, questa funzione è chiamata proprio come la funzione Alert(), ma ora tutti i messaggi vengono scritti senza notifiche nella scheda "Experts" e nel file "Terminal_dir\MQL5\Logs\data.txt". Considera i pro e i contro di questo metodo:  

  1. + Tutti i messaggi vengono registrati in modo coerente.
  2. + Tutto è scritto nel file "Terminal_dir\MQL5\Logs\data.txt".
  3. + Adatto per la registrazione continua del lavoro del programma.
  4. - Tutti i messaggi provenienti da tutti gli script / Expert Advisor / Indicatori sono scritti in un unico log.
  5. - Impossibile raggruppare i messaggi.
  6. - Visualizzazione scomoda del file di log.
  7. - Impossibile salvare i messaggi in una cartella diversa dalla cartella dati standard.

Questo metodo è probabilmente utilizzato dalla maggior parte dei programmatori MQL5, è abbastanza veloce e adatto per un gran numero di record di log.

Scrittura del Log nel File

Considera l'ultimo modo di logging: scrivere messaggi nei file. Questo metodo è molto più complicato di tutti i precedenti, ma con una preparazione adeguata garantisce una buona velocità di scrittura e una comoda visualizzazione del log, nonché delle notifiche. Ecco il codice più semplice per scrivere il log in un file:

void OnStart()
  {
//--- Open log file
   int fileHandle=FileOpen("log.txt",FILE_WRITE|FILE_TXT|FILE_SHARE_READ|FILE_UNICODE); 
   FileWrite(fileHandle,"Start script");
   int intArray[10];
   for(int i=0;i<10;i++)
     {
      intArray[i]=i;
      FileWrite(fileHandle,"Variable i: ",i);
      // Sleep(1000);
     }
   FileWrite(fileHandle,intArray[9]);
   FileWrite(FileHandle,"Stop script");
   FileClose(fileHandle); // close log file
  }

Eseguire e passare alla cartella "Terminal_dir\MQL5\Files" e aprire il file "log.txt" nell'editor di testo. Ecco i contenuti:

Log to File

Come puoi vedere, l'output è conseguente, nessun messaggio extra, solo quello che abbiamo scritto sul file. Considera i pro e i contro:

  1. + Veloce.
  2. + Scrive solo quello che vogliamo.
  3. + È possibile scrivere messaggi da diversi programmi in file diversi, in modo che ciò escluda l'intersezione dei log.
  4. - Nessuna notifica di nuovi messaggi nel log.
  5. - Impossibile distinguere un particolare messaggio o categoria di messaggio.
  6. - Ci vuole molto tempo per aprire il log, è necessario passare alla cartella e aprire il file.

Sommario:

Tutti i metodi sopra menzionati hanno i loro svantaggi, ma è possibile modificarne alcuni. I primi tre metodi di logging non sono flessibili, quasi da non poter influenzare il loro comportamento. Ma quest'ultimo metodo, Writing Log into File è il più flessibile, possiamo decidere come e quando vengono registrati i messaggi. Se si desidera visualizzare un singolo numero, ovviamente è più facile utilizzare i primi tre metodi. Ma se hai un programma complicato con molti codici, sarà difficile usarlo senza fare il logging.


Nuovo Approccio al Logging


Ora ti dirò e ti mostrerò come puoi migliorare l'accesso a un file e darti il pratico strumento per visualizzare i log. Questa è l'applicazione per Windows, che ho scritto in C ++ e l'ho chiamata LogMon.

Iniziamo con la scrittura della classe, che farà tutta il logging, vale a dire:

  1. Mantenere la posizione del file, in cui verranno scritte le impostazioni del log e di altre impostazioni del log.
  2. Creare file di log in base al nome e alla data/ora.
  3. Convertire i parametri passati in una riga di log.
  4. Aggiungere tempo al messaggio di log.
  5. Aggiungi il colore del messaggio.
  6. Aggiungi categoria di messaggi.
  7. Memorizza i messaggi nella cache e scrivili una volta per n-secondi o ogni n-messaggi.

Poiché MQL5 è un linguaggio orientato agli oggetti e non differisce significativamente da C ++ nella sua velocità, scriveremo una classe specifica per MQL5. Cominciamo.


Implementazione della Classe di Scrittura del Log nel File

Metteremo la nostra classe in un file di include separato con l'estensione mqh. Ecco la struttura generale della classe.

CLogger

Ora il codice sorgente della classe con commenti dettagliati:

//+------------------------------------------------------------------+
//|                                                      Clogger.mqh |
//|                                                             ProF |
//|                                                          http:// |
//+------------------------------------------------------------------+
#property copyright "ProF"
#property link      "http://"

// Max size of cache (quantity)
#define MAX_CACHE_SIZE   10000
// Max file size in megabytes
#define MAX_FILE_SIZEMB 10
//+------------------------------------------------------------------+
//|   Logger                                                         |
//+------------------------------------------------------------------+
class CLogger
  {
private:
   string            project,file;             // Name of project and log file
   string            logCache[MAX_CACHE_SIZE]; // Cache max size
   int               sizeCache;                // Cache counter
   int               cacheTimeLimit;           // Caching time
   datetime          cacheTime;                // Time of cache last flush into file
   int               handleFile;               // Handle of log file
   string            defCategory;              // Default category
   void              writeLog(string log_msg); // Writing message into log or file, and flushing cache
public:
   void              CLogger(void){cacheTimeLimit=0; cacheTime=0; sizeCache=0;};    // Constructor
   void             ~CLogger(void){};                                               // Destructor
   void              SetSetting(string project,string file_name,
                                string default_category="",int cache_time_limit=0); // Settings
   void              init();                   // Initialization, open file for writing
   void              deinit();                 // Deinitialization, closing file
   void              write(string msg,string category="");                                         // Generating message
   void              write(string msg,string category,color colorOfMsg,string file="",int line=0); // Generating message
   void              write(string msg,string category,uchar red,uchar green,uchar blue,
                           string file="",int line=0);                                             // Generating message
   void              flush(void);              // Flushing cache into file

  };
//+------------------------------------------------------------------+
//|  Settings                                                        |
//+------------------------------------------------------------------+
void CLogger::SetSetting(string project_name,string file_name,
                        string default_category="",int cache_time_limit=0)
  {
   project=project_name;             // Project name
   file=file_name;                   // File name
   cacheTimeLimit=cache_time_limit;  // Caching time
   if(default_category=="")          // Setting default category
     {  defCategory="Comment";   }
     else
     {defCategory = default_category;}
  }
//+------------------------------------------------------------------+
//|  Initialization                                                  |
//+------------------------------------------------------------------+
void CLogger::init(void)
  {
   string path;
   MqlDateTime date;
   int i=0;
   TimeToStruct(TimeCurrent(),date);                            // Get current time
   StringConcatenate(path,"log\\log_",project,"\\log_",file,"_",
                     date.year,date.mon,date.day);              // Generate path and file name
   handleFile=FileOpen(path+".txt",FILE_WRITE|FILE_READ|
                       FILE_UNICODE|FILE_TXT|FILE_SHARE_READ);  // Open or create new file
   while(FileSize(handleFile)>(MAX_FILE_SIZEMB*1000000))        // Check file size
     {
      // Open or create new log file
      i++;
      FileClose(handleFile);
      handleFile=FileOpen(path+"_"+(string)i+".txt",
                          FILE_WRITE|FILE_READ|FILE_UNICODE|FILE_TXT|FILE_SHARE_READ);
     }
   FileSeek(handleFile,0,SEEK_END);                             // Set pointer to the end of file
  }
//+------------------------------------------------------------------+
//|   Deinitialization                                               |
//+------------------------------------------------------------------+
void CLogger::deinit(void)
  {
   FileClose(handleFile); // Close file
  }
//+------------------------------------------------------------------+
//|   Write message into file or cache                               |
//+------------------------------------------------------------------+
void CLogger::writeLog(string log_msg)
  {
   if(cacheTimeLimit!=0)  // Check if cache is enabled
     {
      if((sizeCache<MAX_CACHE_SIZE-1 && TimeCurrent()-cacheTime<cacheTimeLimit)
         || sizeCache==0) // Check if cache time is out or if cache limit is reached
        {
         // Write message into cache
         logCache[sizeCache++]=log_msg;
        }
      else
        {
         // Write message into cache and flush cache into file
         logCache[sizeCache++]=log_msg;
         flush();
        }

     }
   else
     {
      // Cache is disabled, immediately write into file
      FileWrite(handleFile,log_msg);
     }
   if(FileTell(handleFile)>(MAX_FILE_SIZEMB*1000000)) // Check current file size
     {
      // File size exceeds allowed limit, close current file and open new
      deinit();
      init();
     }
  }
//+------------------------------------------------------------------+
//|   Generate message and write into log                            |
//+------------------------------------------------------------------+
void CLogger::write(string msg,string category="")
  {
   string msg_log;
   if(category=="")                // Check if passed category exists
     {   category=defCategory;   } // Set default category

// Generate line and call method of writing message
   StringConcatenate(msg_log,category,":|:",TimeToString(TimeCurrent(),TIME_SECONDS),"    ",msg);
   writeLog(msg_log);
  }
//+------------------------------------------------------------------+
//|    Generate message and write into log                           |
//+------------------------------------------------------------------+
void CLogger::write(string msg,string category,color colorOfMsg,string file="",int line=0)
  {
   string msg_log;
   int red,green,blue;
   red=(colorOfMsg  &Red);           // Select red color from constant
   green=(colorOfMsg  &0x00FF00)>>8; // Select green color from constant
   blue=(colorOfMsg  &Blue)>>16;     // Select blue color from constant
                                     // Check if file or line are passed, generate line and call method of writing message
   if(file!="" && line!=0)
     {
      StringConcatenate(msg_log,category,":|:",red,",",green,",",blue,
                        ":|:",TimeToString(TimeCurrent(),TIME_SECONDS),"    ",
                        "file: ",file,"   line: ",line,"   ",msg);
     }
   else
     {
      StringConcatenate(msg_log,category,":|:",red,",",green,",",blue,
                        ":|:",TimeToString(TimeCurrent(),TIME_SECONDS),"    ",msg);
     }
   writeLog(msg_log);
  }
//+------------------------------------------------------------------+
//|    Generate message and write into log                           |
//+------------------------------------------------------------------+
void CLogger::write(string msg,string category,uchar red,uchar green,uchar blue,string file="",int line=0)
  {
   string msg_log;

// Check if file or line are passed, generate line and call method of writing message
   if(file!="" && line!=0)
     {
      StringConcatenate(msg_log,category,":|:",red,",",green,",",blue,
                        ":|:",TimeToString(TimeCurrent(),TIME_SECONDS),"    ",
                        "file: ",file,"   line: ",line,"   ",msg);
     }
   else
     {
      StringConcatenate(msg_log,category,":|:",red,",",green,",",blue,
                        ":|:",TimeToString(TimeCurrent(),TIME_SECONDS),"    ",msg);
     }
   writeLog(msg_log);
  }
//+------------------------------------------------------------------+
//|    Flush cache into file                                         |
//+------------------------------------------------------------------+
void CLogger::flush(void)
  {
   for(int i=0;i<sizeCache;i++) // In loop write all messages into file
     {
      FileWrite(handleFile,logCache[i]);
     }
   sizeCache=0; // Reset cache counter
   cacheTime=TimeCurrent(); // Set time of reseting cache
  }
//+------------------------------------------------------------------+

In MetaEditor creare il file di include (.mqh) e copiare il codice sorgente della classe e salvare con il nome "CLogger.mqh". Ora parliamo di più su ciascun metodo e su come applicare la classe.

Utilizzo della classe CLogger

Per iniziare a registrare i messaggi nel log utilizzando questa classe, dobbiamo includere il file di classe negli Expert Advisor/ Indicatori/Script:

#include <CLogger.mqh>

Successivamente, è necessario creare un oggetto di questa classe:

CLogger logger;

Eseguiremo tutte le azioni con l'oggetto "logger". Ora dobbiamo regolare le impostazioni chiamando il metodo "SetSetting()". In questo metodo dobbiamo passare il nome del progetto e il nome del file. Ci sono anche due parametri facoltativi: il nome della categoria predefinita e la durata della cache (in secondi) durante la quale la cache viene memorizzata prima di essere scritta nel file. Se si specifica zero, tutti i messaggi verranno scritti una sola volta.

SetSetting(string project,             // Project name
           string file_name,           // Log file name
           string default_category="", // Default category
           int cache_time_limit=0      // Cache lifetime in seconds
           );

Esempio di chiamata:

logger.SetSetting("MyProject","myLog","Comment",60);

Di conseguenza, i messaggi verranno scritti nel file "Client_Terminal_dir\MQL5\Files\log\log_MyProject\log_myLog_date.txt", la categoria predefinita è "Commento" e la durata della cache è di 60 secondi. Quindi è necessario chiamare il metodo init() per aprire / creare il file di log. L'esempio di chiamata è semplice, in quanto non è necessario passare i parametri:  

logger.init();

Questo metodo genera il percorso e il nome del file di log, lo apre e controlla se non supera la dimensione massima. Se la dimensione supera il valore costante impostato in precedenza, viene aperto un altro file e 1 viene concatenato al suo nome. Quindi di nuovo, la dimensione viene controllata fino a quando non viene aperto il file con la dimensione corretta.

Quindi il puntatore viene spostato in posizione alla fine del file. Ora l'oggetto è pronto per scrivere il log. Abbiamo sovrascritto il metodo di scrittura. Grazie a questo possiamo impostare diverse strutture di messaggi, esempio di chiamare il metodo di scrittura e il risultato nel file:

// Write message with default caegory
logger.write("Test message");
// Write message with "Errors" category
logger.write("Test message", "Errors");
// Write message with "Errors" category, that will be highlighted with red color in LogMon
logger.write("Test message", "Errors",Red);
// Write message with "Errors" category, that will be highlighted with red color in LogMon
// Also message will contain current file name and current line
logger.write("Test message", "Errors",Red,__FILE__,__LINE__);
// Write message with "Errors" category, that will be highlighted with GreenYellow color in LogMon
// But now we specify each color independently as: red, green, blue. 0-black, 255 - white
logger.write("Test message", "Errors",173,255,47);
// Write message with "Errors" category, that will be highlighted with GreenYellow color in LogMon
// But now we specify each color independently as: red, green, blue. 0-black, 255 - white
// Also message will contain current file name and current line
logger.write("Test message", "Errors",173,255,47,__FILE__,__LINE__);

Il file di log conterrà le seguenti righe:

Comment:|:23:13:12    Test message
Errors:|:23:13:12    Test message
Errors:|:255,0,0:|:23:13:12    Test message
Errors:|:255,0,0:|:23:13:12    file: testLogger.mq5   line: 27   Test message
Errors:|:173,255,47:|:23:13:12    Test message
Errors:|:173,255,47:|:23:13:12    file: testLogger.mq5   line: 29   Test message

Come puoi vedere, tutto è molto semplice. Chiamare il metodo write() con i parametri richiesti ovunque e il messaggio verrà scritto nel file. Alla fine del programma è necessario inserire la chiamata di due metodi: flush() e deinit().

logger.flush();  // Forcibly flush cache to hard disk
logger.deinit(); // Close the log file

Ecco un semplice esempio di script che scrive numeri in un ciclo nel log:

//+------------------------------------------------------------------+
//|                                                   testLogger.mq5 |
//|                                                             ProF |
//|                                                          http:// |
//+------------------------------------------------------------------+
#property copyright "ProF"
#property link      "http://"
#property version   "1.00"
#include <Сlogger.mqh>
CLogger logger;
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+

void OnStart()
  {
//---
   logger.SetSetting("proj","lfile");      // Settings
   logger.init();                          // Initialization
   logger.write("Start script","system");  
   for(int i=0;i<100000;i++)               // Write 100000 messages to the log
     {
      logger.write("log: "+(string)i,"Comment",100,222,100,__FILE__,__LINE__);
     }
   logger.write("Stop script","system"); 
   logger.flush();                         // Flush buffer
   logger.deinit();                        // Deinitialization
  }
//+------------------------------------------------------------------+

Script eseguito in tre secondi e creato 2 file:

File di registro

Contenuto del file:

Contenuto del file di log

E così tutti i 100000 messaggi. Come puoi vedere, tutto funziona abbastanza rapidamente. È possibile modificare questa classe, aggiungere nuove funzionalità o ottimizzarla.

Livello di Output dei Messaggi


Mentre scrivi un programma, devi visualizzare diversi tipi di messaggi:

  1. Errori critici (il programma non si comporta correttamente)
  2. Notifiche di errori non critici, operazioni di trading, ecc. (il programma sta riscontrando errori temporanei, o il programma ha effettuato un'azione importante, di cui l'utente deve essere informato)
  3. Informazioni di debug (contenuto di matrici e variabili e altre informazioni che non sono necessarie nel lavoro reale).

Inoltre è consigliabile essere in grado di regolare quali messaggi si desidera stampare senza modificare il codice sorgente. Implementeremo questo obiettivo come una semplice funzione e non useremo classi e metodi.

Dichiarare il parametro variabile che memorizzerà il livello di output dei messaggi. Maggiore è il numero in variabile, più categorie di messaggi verranno visualizzate. Se si desidera disabilitare completamente l'output dei messaggi, assegnarlo con il valore "-1".

input int dLvl=2;

Di seguito è riportato il codice sorgente della funzione, che deve essere dichiarato dopo aver creato l'oggetto della classe CLogger.

void debug(string debugMsg,             // Message text
          int lvl        )              // Message level
{
   if (lvl<=dLvl)                       // Compare message level with level of messages output
   {
       if (lvl==0)                      // If message is critical (level = 0)
       {logger.write(debugMsg,"",Red);} // mark it with red color
       else
       {logger.write(debugMsg);}        // Else print it with default color
   }
}

Ora un esempio: specificare il livello "0" ai messaggi più importanti e qualsiasi numero (in ordine crescente da zero) a quelli più inutili:

debug("Error in Expert Advisor!",0);      // Critical error
debug("Stop-Loss execution",1);      // Notification
int i = 99;
debug("Variable i:"+(string)i,2); // Debugging information, variable contents

Facile Visualizzazione dei Log con LogMon

OK, ora abbiamo file di log contenenti migliaia di righe. Ma è piuttosto difficile trovare informazioni in loro. Non sono divisi in categorie e non differiscono l'uno dall'altro. Ho cercato di risolvere questo problema, vale a dire, ho scritto un programma per visualizzare i log generati dalla classe CLogger. Ora ti presenterò brevemente il programma LogMon, che è scritto in C ++ usando WinAPI. A causa di ciò è veloce e di piccole dimensioni. Il programma è assolutamente gratuito.

Per lavorare con il programma è necessario:

  1. Copialo nella cartella "Client_Terminal_dir\MQL5\Files\" ed eseguilo - in caso di modalità normale.
  2. Copialo nella cartella "Agents_dir\Agent\MQL5\Files\" ed eseguilo - in caso di test o ottimizzazione.

La finestra principale del programma si presenta così:

Finestra principale di LogMon

La finestra principale contiene la barra degli strumenti e la finestra con la vista ad albero. Per espandere un elemento, fare doppio clic su di esso con il pulsante sinistro del mouse. Cartella nell'elenco - sono i progetti, che si trovano nella cartella "Client_Terminal_dir\MQL\Files\log\". È possibile impostare il nome del progetto nella classe CLogger utilizzando il metodo SetSetting(). I file nell'elenco delle cartelle - sono in realtà i file di log. I messaggi nei file di log sono suddivisi in categorie specificate nel metodo write(). Numeri tra parentesi - sono i numeri di messaggi in quella categoria.

Ora consideriamo i pulsanti sulla barra degli strumenti da sinistra a destra.

Pulsante per eliminare il progetto o il file di log, nonché per reimpostare la visualizzazione ad albero

Quando si preme questo pulsante, viene visualizzata la seguente finestra:

Delete, Flush

Se si preme il pulsante "Delete and Flush", tutti i thread di scansione di file/cartelle verranno interrotti, la visualizzazione ad albero verrà ripristinata e verrà richiesto di eliminare il file o il progetto selezionato (è sufficiente fare click su un elemento per selezionarlo - non è necessario selezionare la casella di controllo!). Il pulsante "Ripristina" interromperà tutti i thread di scansione di file / cartelle e cancellerà la vista ad albero.

Pulsante per visualizzare la finestra di dialogo "Informazioni"

Mostra brevi informazioni sul programma e sul suo autore.

Pulsante per visualizzare la finestra del programma sempre in alto

Posiziona la finestra del programma sopra tutte le altre finestre.

Pulsante per attivare il monitoraggio dei nuovi messaggi nei file di log

Questo pulsante nasconde la finestra del programma per vassoio System Tray  e attiva il monitoraggio dei nuovi messaggi nei file di registro. Per selezionare il progetto/file/la categoria che verrà analizzato, selezionare le caselle di controllo accanto agli elementi necessari.

Se si seleziona la casella di controllo accanto alla categoria di messaggi, la notifica verrà attivata su un nuovo messaggio in questo progetto/file/categoria. Se si seleziona la casella di controllo accanto al file, la notifica verrà attivata su un nuovo messaggio in questo file per qualsiasi categoria. Infine, se si seleziona la casella di controllo accanto al progetto, la notifica verrà attivata su un nuovo file di log e sui messaggi in essi.

Monitoraggio

Se è stato attivato il monitoraggio e la finestra del programma è ridotta a icona a tray, quando viene visualizzato un nuovo messaggio negli elementi selezionati, la finestra principale dell'applicazione verrà ingrandita con una notifica sonora. Per disabilitare le notifiche, fare clic in un punto qualsiasi dell'elenco con il pulsante sinistro del mouse. Per interrompere il monitoraggio, fare click sull'icona del programma nella barra delle applicazioni  icona LogMon. Per modificare il suono della notifica con il proprio, inserire .wav file con nome "alert.wav" nella stessa cartella con il file eseguibile del programma.  

Visualizza Categoria Log

Per visualizzare una categoria specifica è sufficiente fare doppio clic su di essa. Quindi vedrai la finestra di messaggio:

Ricerca LogMon

In questa finestra puoi cercare i messaggi, appuntare la finestra sempre in alto e attivare lo scorrimento automatico. Il colore di ogni messaggio viene impostato singolarmente utilizzando il metodo write() della classe CLogger. Lo sfondo del messaggio verrà evidenziato con il colore selezionato.

Quando si fa doppio clic su un messaggio, questo si aprirà in una finestra separata. Sarà utile se il messaggio è troppo lungo e non si adatta alla finestra di dialogo:  

Messaggio LogMon

Ora hai un pratico strumento per visualizzare e monitorare i file di log. Speriamo che questo programma ti aiuti, mentre sviluppi e usi i programmi MQL5.

Conclusione

La registrazione degli eventi nel tuo programma è molto utile, ti aiuta a identificare gli errori nascosti e rivelare le opportunità per migliorare il tuo programma. In questo articolo ho descritto metodi e programmi per l'accesso più semplice ai file, il monitoraggio e la visualizzazione dei log.

I vostri commenti e suggerimenti saranno apprezzati!

Tradotto dal russo da MetaQuotes Ltd.
Articolo originale: https://www.mql5.com/ru/articles/150

File allegati |
clogger.mqh (8.72 KB)
testlogger.mq5 (1.29 KB)
logmon_source_en.zip (119.02 KB)
logmonen.zip (88.78 KB)

Altri articoli di questo autore

Simulink: una Guida per gli Sviluppatori di Expert Advisor Simulink: una Guida per gli Sviluppatori di Expert Advisor
Non sono un programmatore professionista. E così, il principio di "passare dal semplice al complesso" è di primaria importanza per me quando lavoro allo sviluppo del sistema di trading. Cosa esattamente è semplice per me? Prima di tutto, è la visualizzazione del processo di creazione del sistema e la logica del suo lavoro. Inoltre, è un minimo di codice scritto a mano. In questo articolo, tenterò di creare e testare il sistema di trading basato su un pacchetto Matlab, e quindi scrivere un Expert Advisor per MetaTrader 5. I dati storici di MetaTrader 5 verranno utilizzati per il processo del test.
Come Creare Rapidamente un Expert Advisor per l’Automated Trading Championship 2010 Come Creare Rapidamente un Expert Advisor per l’Automated Trading Championship 2010
Al fine di sviluppare un expert per partecipare all'Automated Trading Championship 2010, usiamo un modello di pronto dell’expert advisor. Anche il programmatore MQL5 alle prime armi sarà in grado di questo compito, perché per le tue strategie le classi di base, le funzioni, i modelli sono già sviluppati. Basta scrivere una quantità minima di codice per implementare la tua idea di trading.
L'Handler dell'Evento "Nuova Barra" L'Handler dell'Evento "Nuova Barra"
Il linguaggio di programmazione MQL5 è in grado di risolvere i problemi a un livello completamente nuovo. Anche quei compiti, che hanno già tali soluzioni, grazie alla programmazione orientata agli oggetti possono salire ad un livello superiore. In questo articolo prendiamo un esempio particolarmente semplice di controllo della nuova barra su un grafico, che è stato trasformato in uno strumento piuttosto potente e versatile. Quale strumento? Scoprilo in questo articolo.
Controllo dello Slope della Curva di Saldo Durante il Lavoro di un Expert Advisor Controllo dello Slope della Curva di Saldo Durante il Lavoro di un Expert Advisor
Trovare regole per un sistema di trading e programmarle in un Expert Advisor è una metà del lavoro. In qualche modo, è necessario correggere il funzionamento dell'Expert Advisor in quanto accumula i risultati del trading. Questo articolo descrive uno degli approcci che consente di migliorare le prestazioni di un Expert Advisor attraverso la creazione di un feedback che misura la pendenza della curva di bilanciamento.