English Русский 中文 Español Deutsch 日本語 Português 한국어 Italiano Türkçe
Recherche d'erreurs et journalisation

Recherche d'erreurs et journalisation

MetaTrader 5Exemples | 17 novembre 2021, 16:04
164 0
Дмитрий Александрович
Дмитрий Александрович

Introduction

Bonjour chers lecteurs !

Dans cet article, nous examinerons plusieurs façons de trouver des erreurs dans les Expert Advisors/Scripts/Indicators et les méthodes de connexion Je vais également vous proposer un petit programme pour afficher les fichiers journaux - LogMon.

La recherche d'erreurs fait partie intégrante de la programmation. Lorsque vous écrivez un nouveau bloc de code, il est nécessaire de vérifier s'il fonctionne correctement et ne comporte pas d'erreurs logiques. Vous pouvez trouver une erreur dans votre programme de trois manières différentes :

  1. Évaluation du résultat final  
  2. Débogage pas à pas  
  3. Écriture des étapes logiques dans le fichier journal

Examinez chaque façon.

1. Évaluation du résultat final

Avec cette méthode, nous analysons le résultat du travail du programme ou une partie de son code. Par exemple, prenons un code simple, qui contient une erreur évidente faite uniquement par souci de clarté :

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

  }

Compilez et exécutez, et l'écran affichera "0". En analysant les résultats, nous attendons le nombre "9", nous concluons donc que notre programme ne fonctionne pas comme il le devrait. Cette méthode de recherche d'erreurs est courante et ne permet pas de trouver l'emplacement de l'erreur. Examinons la deuxième façon de trouver des erreurs, nous utiliserons le débogage.  

2. Débogage étape par étape

Cette méthode vous permet de trouver exactement l'endroit où la logique du programme a été enfreinte. Dans MetaEditor, placez un point d'arrêt dans la boucle 'for', commencez le débogage et ajoutez veille pour la variable i :

Débogage

Cliquez ensuite sur "Reprendre le débogage" tant que nous considérons l'ensemble du processus de travail du programme. Nous constatons que comme la variable "i" a la valeur "8", nous quittons la boucle, nous concluons donc que l'erreur est dans la ligne :

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

Autrement dit, lorsque la valeur de i et le nombre 9 sont comparés. Fixez la ligne "i<9" " à "i<10" ou à "i<=9", vérifiez les résultats. Nous obtenons le numéro 9 - exactement ce à quoi nous nous attendions. En utilisant le débogage, nous avons appris comment le programme agit lors de son exécution et avons pu résoudre le problème. Les inconvénients de cette méthode :

  1. On ne sait pas où l'erreur s'est produite, par intuition.
  2. Vous devez ajouter des variables à la liste de surveillance et les afficher après chaque étape.
  3. Cette méthode ne peut pas détecter les erreurs lors de l'exécution du programme terminé, telles que le trading EA sur un compte réel ou démo.

Enfin, examinons la troisième façon de trouver des erreurs.

3. Écriture d'étapes logiques dans le journal

En utilisant cette méthode, nous enregistrons les étapes importantes de notre programme. Par exemple : initialisation, conclusion d’un deal, calcul d'indicateur, etc. Mettez à niveau notre script avec une ligne de code. Autrement dit , nous imprimerons la valeur de la variable i à chaque itération :

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

  }

Exécutez et constatez la sortie du journal - nombres "0 1 2 3 4 5 6 7 8 0". Concluez pourquoi il peut en être ainsi et corrigez le script, comme la dernière fois.

Avantages et inconvénients de cette méthode de recherche d'erreurs :

  1. + Pas besoin d'exécuter le programme étape par étape, ce qui permet de gagner beaucoup de temps.
  2. + Souvent, il est évident, où se trouve l'erreur.
  3. + Vous pouvez continuer à vous connecter pendant l'exécution du programme.
  4. +Vous pouvez enregistrer le journal pour une analyse et une comparaison ultérieures (par exemple, lors de l'écriture dans un fichier. Voir ci-dessous.).
  5. -- Le code source augmente en taille en raison des opérateurs ajoutés, qui écrivent des données dans le journal.
  6. -- Augmentation du temps d'exécution du programme (fondamentalement important pour l'optimisation).

Résumé:

La première façon de trouver des erreurs ne permet pas de localiser l'emplacement réel de l'erreur. Nous l'utilisons principalement pour sa rapidité. La deuxième façon - le débogage étape par étape vous permet de trouver l'emplacement exact de l'erreur, mais cela prend beaucoup de temps. Et si vous dépassez le bloc de code souhaité, vous devez tout recommencer.

Enfin, la troisième façon - l'enregistrement des étapes logiques dans le journal vous permet d'analyser rapidement le travail du programme et de sauvegarder le résultat. Lors de l'écriture des événements de vos Expert Advisors/Indicateurs/Scripts dans le journal, vous pouvez facilement trouver une erreur et vous ne devez pas à rechercher des conditions favorables dans lesquelles une erreur se produit, et vous n'avez pas à déboguer votre programme pendant des heures et des heures. Ensuite, nous examinerons les détails de méthodes de connexion et les comparerons. Je vous proposerai également le moyen le plus pratique et le plus rapide.

Quand devez-vous vous connecter ?

Voici quelques motifs de connexion :
  1. Comportement erroné du programme.
  2. Durée d'exécution du programme trop longue (optimisation).
  3. Suivi de l'exécution (impression des notifications de positions d'ouverture/clôture, actions exécutées, etc.).  
  4. Apprendre MQL5, par exemple - imprimer des tableaux.  
  5. Vérification des Expert Advisors avant le championnat, etc.

Méthodes de journalisation

Il existe de nombreuses façons d'écrire des messages dans le journal, mais certaines sont utilisées partout, tandis que d'autres sont nécessaires dans des cas particuliers. Par exemple, l'envoi d’un journal par email ou via ICQ n'est pas toujours nécessaire.  

Voici la liste des méthodes les plus couramment utilisées dans la programmation MQL5 :

  1. Utilisation de la fonction Commenter()
  2. Utilisation de la fonction Alerte()
  3. Utilisation de la fonction Imprimer()
  4. Écrire le journal dans le fichier à l'aide de la fonction FileWrite()

Ensuite, je donnerai des exemples de chaque méthode avec des codes sources et décrirai les caractéristiques de chaque méthode. Ces codes sources sont plutôt abstraits, nous n'irons donc pas loin de l'essence.

Utilisation de la fonction Commenter()

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

Ainsi, dans le coin supérieur gauche, nous voyons la valeur actuelle de la variable "i":

Commenter()

Ainsi, nous pouvons surveiller l'état actuel du programme en cours d'exécution. Maintenant les avantages et les inconvénients :

  1. + Vous pouvez voir la valeur immédiatement.
  2. - Restriction de sortie.
  3. - Vous ne pouvez pas sélectionner un message en particulier.
  4. - Vous ne voyez pas son travail tout au long de l'exécution, seulement l'état actuel.
  5. - Méthode relativement lente.
  6. - Inadaptée à la surveillance continue du travail, car vous devez toujours surveiller la lecture.

La fonction Commenter() est utile pour afficher l'état actuel d'Expert Advisor. Par exemple, « Ouvrir 2 deal » ou « acheter un lot GBRUSD : 0.7".  

Utilisation de la fonction Alerte()

Cette fonction affiche les messages dans une fenêtre séparée avec notification sonore. L'exemple de code :

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");
  }
Le résultat de l'exécution du code :  

Alerte()

Et maintenant, nous sommes au septième ciel, tout est immédiatement évident même avec le son. Mais maintenant les avantages et inconvénients :

  1. + Tous les messages sont enregistrés de manière cohérente.
  2. +Notification sonore.
  3. +Tout est écrit dans le fichier "Terminal_dir\MQL5\Logs\data.txt".
  4. -Tous les messages de tous les scripts/conseillers experts/indicateurs sont écrits dans un seul journal.
  5. -Ne fonctionne pas dans le Testeur de Stratégie
  6. -- Lorsqu'il est appelé fréquemment, il peut geler le terminal pendant une longue période (par exemple, lors de l'appel à chaque tick ou lors de l'impression d'un tableau en boucle).
  7. -Impossible de grouper les messages.
  8. -Affichage peu pratique du fichier journal.
  9. -Impossible d'enregistrer les messages dans un dossier différent du dossier de données standard.

Le sixième point est capital dans le trading réel, notamment lors du scalpage ou de la modification d’Arrêt de Perte. Il y a pas mal d'inconvénients et vous pouvez en trouver d'autres, mais je pense que cela suffit.  

Utilisation de la fonction Imprimer()

Cette fonction écrit les messages de journal dans une fenêtre spéciale appelée "Experts". Voici le code :

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");
  }

Imprimer()

Comme vous pouvez le constater, cette fonction est appelée comme la fonction Alerte(), mais maintenant tous les messages sont écrits sans notifications dans l'onglet "Experts" et dans le fichier "Terminal_dir\MQL5\Logs\data.txt". Tenez compte des avantages et des inconvénients de cette méthode :  

  1. +Tous les messages sont enregistrés de manière cohérente.
  2. +Tout est écrit dans le fichier "Terminal_dir\MQL5\Logs\data.txt".
  3. + Convient pour la journalisation continue du travail du programme.
  4. -Tous les messages de tous les scripts/conseillers experts/indicateurs sont écrits dans un seul journal.
  5. -Impossible de grouper les messages.
  6. -Affichage peu pratique du fichier journal.
  7. -Impossible d'enregistrer les messages dans un dossier différent du dossier de données standard.

Cette méthode est probablement utilisée par la plupart des programmeurs MQL5, elle est assez rapide et bien adaptée pour un grand nombre d'enregistrements de journaux.

Écriture du journal dans un fichier

Tenez compte de la dernière façon de se connecter - écrire des messages dans des fichiers. Cette méthode est beaucoup plus compliquée que toutes les précédentes, mais avec une bonne préparation assure une bonne vitesse d'écriture et une visualisation confortable du journal, ainsi que des notifications. Voici le code le plus simple pour écrire un journal dans un fichier :

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
  }

Exécutez et parcourez jusqu’au dossier "Terminal_dir\MQL5\Files" et ouvrez le fichier "log.txt" dans l'éditeur de texte. Voici le sommaire :

Enregistrer dans un fichier

Comme vous pouvez le constater r, la sortie est conséquente, pas de messages supplémentaires, juste ce que nous avons écrit dans le fichier. Tenez compte des avantages et les inconvénients :

  1. + Rapide.
  2. +N'écrit que ce que nous souhaitons.
  3. +Vous pouvez écrire des messages de différents programmes dans différents fichiers, de sorte que cela écarte l'intersection des journaux.
  4. - Aucune notification de nouveaux messages dans le journal.
  5. -Impossible de distinguer un message particulier ou une catégorie de message.
  6. - L'ouverture du journal prend beaucoup de temps, vous devez parcourir jusqu'au dossier et ouvrir le fichier.

Résumé:

Toutes les méthodes mentionnées ci-dessus ont leurs inconvénients, mais vous pouvez en modifier certaines. Les trois premières méthodes de journalisation ne sont pas flexibles, nous ne pouvons presque pas affecter leur comportement. Mais cette dernière méthode, Writing Log into File, est la plus flexible, nous pouvons décider comment et quand les messages sont enregistrés. Si vous souhaitez afficher un seul numéro, il est bien entendu plus simple d'utiliser les trois premières méthodes. Mais si vous avez un programme compliqué avec plusieurs codes, il sera difficile de l'utiliser sans vous connecter.


Nouvelle approche de journalisation


Maintenant, je vais vous dire et vous montrer comment vous pouvez améliorer la connexion à un fichier et vous donner l'outil pratique pour afficher les journaux. C'est l'application pour Windows, que j'ai écrite en C++ et que j'ai baptisée LogMon.

Commençons par écrire la classe, qui assurera toute la journalisation, notamment :

  1. Conservez l'emplacement du fichier dans lequel le journal et les autres paramètres du journal seront écrits.
  2. Créez des fichiers journaux en fonction du nom donné et de la date/heure.
  3. Convertissez les paramètres passés en ligne de log.
  4. Ajoutez du temps au message de journal.
  5. Ajouter la couleur du message.
  6. Ajouter une catégorie de message.
  7. Mettez les messages en cache et écrivez-les une fois toutes les n secondes ou tous les n messages.

Puisque MQL5 est un langage orienté-objet et ne diffère considérablement pas du C++ par sa vitesse, nous écrirons une classe spécifiquement pour MQL5. Commençons.


Implémentation de la classe d'écriture du journal dans le fichier

Nous mettrons notre classe dans un fichier d'inclusion séparé avec l'extension mqh. Voici la structure générale de la classe.

CLogger

Maintenant le code source de la classe avec des commentaires détaillés :

//+------------------------------------------------------------------+
//|                                                      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
  }
//+------------------------------------------------------------------+

Dans MetaEditor, créez le fichier d'inclusion (.mqh), copiez le code source de la classe et sauvegardez-le sous le nom "CLogger.mqh". Évoquons maintenant chaque méthode et de la façon d'appliquer la classe.

Utilisation de la classe CLogger

Pour commencer l’enregistrement des messages dans le journal à l'aide de cette classe, nous devons inclure le fichier de classe dans Expert Advisor/Indicator/Script :

#include <CLogger.mqh>

Ensuite, vous devez créer un objet de cette classe :

CLogger logger;

Nous mènerons toutes les actions avec l'objet "logger". Nous devons maintenant régler les paramètres en appelant la méthode "SetSetting()". Dans cette méthode, nous devons passer le nom du projet et le nom du fichier. Il existe également deux paramètres facultatifs : le nom de la catégorie par défaut et la durée de vie du cache (en secondes) pendant laquelle le cache est stocké avant d'être écrit dans le fichier. Si vous indiquez zéro, tous les messages seront écrits une fois.

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
           );

Exemple d'appel :

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

En conséquence, les messages seront écrits dans le fichier "Client_Terminal_dir\MQL5\Files\log\log_MyProject\log_myLog_date.txt", la catégorie par défaut est "Comment" et la durée de vie du cache est de 60 secondes. Ensuite, vous devez appeler la méthode init() pour ouvrir/créer un fichier journal. L'exemple d'appel est simple, car vous n'avez pas besoin de passer de paramètres :  

logger.init();

Cette méthode génère le chemin et le nom du fichier journal, l'ouvre et vérifie s'il ne dépasse pas la taille maximale. Si la taille dépasse la valeur constante précédemment définie, un autre fichier est ouvert et 1 est enchaîné à son nom. Ensuite encore, la taille est vérifiée jusqu'à ce que le fichier avec la taille correcte soit ouvert.

Ensuite, le pointeur est déplacé pour se positionner à la fin du fichier. L'objet est maintenant prêt à écrire le journal. Nous avons remplacé la méthode d'écriture. Grâce à cela, nous pouvons définir différentes structures de messages, exemple d'appel de la méthode d'écriture et le résultat dans le fichier :

// 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__);

Le fichier journal contiendra les lignes suivantes :

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

Comme vous pouvez le voir, tout est très simple. Appelez la méthode write() avec les paramètres requis n'importe où et le message sera écrit dans le fichier. A la fin de votre programme, vous devez insérer l'appel de deux méthodes - flush() et deinit().

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

Voici un exemple simple de script qui écrit des nombres en boucle dans le journal :

//+------------------------------------------------------------------+
//|                                                   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 exécuté en trois secondes et créé 2 fichiers :

Fichiers journaux

Contenu du fichier :

sommaire du fichier journal

Et donc tous les 100000 messages. Comme vous pouvez le constater, tout fonctionne assez rapidement. Vous pouvez modifier cette classe, ajouter de nouvelles fonctionnalités ou l'optimiser.

Niveau de sortie des messages


Au fur et à mesure que vous écrivez un programme, vous devez afficher plusieurs types de messages :

  1. Erreurs critiques (le programme ne se comporte pas correctement)
  2. Notifications d'erreurs non critiques, d'opérations de trading, etc. (le programme connaît des erreurs temporaires ou le programme a effectué une action importante, dont l'utilisateur doit être informé)
  3. Informations de débogage (contenu des tableaux et des variables, et autres informations qui ne sont pas nécessaires dans le travail réel).

Il est également souhaitable de pouvoir ajuster les messages que vous souhaitez imprimer sans changer le code source. Nous implémenterons cet objectif en tant que fonction simple et n'utiliserons pas de classes et méthodes.

Déclarez le paramètre variable qui stockera le niveau de sortie des messages. Plus le nombre de variable est grand, plus de catégories de messages seront affichées. Si vous souhaitez désactiver complètement la sortie des messages, attribuez-lui la valeur "-1".

input int dLvl=2;

Ci-dessous se trouve le code source de la fonction, qui doit être déclaré après la création de l'objet de la 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
   }
}

Maintenant un exemple : Indiquez le niveau "0" aux messages les plus importants, et n'importe quel nombre (par ordre croissant de zéro) aux plus inutiles :

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

Affichage facile des journaux à l'aide de LogMon

OK, maintenant nous avons des fichiers journaux contenant des milliers de lignes. Mais il est assez difficile d'y trouver des informations. Ils ne sont pas divisés en catégories et ne diffèrent pas les uns des autres. J'ai essayé de résoudre ce problème, autrement dit, j'ai écrit un programme pour afficher les journaux générés par la classe CLogger. Maintenant, je vais vous présenter brièvement le programme LogMon, qui est écrit en C++ à l'aide de WinAPI. Pour cette raison, il est rapide et de petite taille. Le programme est totalement gratuit.

Pour travailler avec le programme, vous devez :

  1. Copiez-le dans le dossier "Client_Terminal_dir\MQL5\Files\" et exécutez-le - en cas de mode normal.
  2. Copiez-le dans le dossier "Agents_dir\Agent\MQL5\Files\" et exécutez-le - en cas de test ou d'optimisation.

La fenêtre principale du programme ressemble à ceci :

LogMon Fenêtre principale de LogMon

La fenêtre principale contient la barre d'outils et la fenêtre avec vue arborescente. Pour étendre un élément, double-cliquez dessus avec le bouton gauche de la souris. Dossier dans la liste - sont les projets, situés dans le dossier "Client_Terminal_dir\MQL\Files\log\". Vous définissez le nom du projet dans la classe CLogger à l'aide de la méthode SetSetting(). Les fichiers dans la liste des dossiers - sont en fait les fichiers journaux. Les messages dans les fichiers journaux sont divisés en catégories que vous avez indiquées dans la méthode write(). Les nombres entre parenthèses - sont les nombres de messages dans cette catégorie.

Examinons ,à présent, les boutons de la barre d'outils de gauche à droite.

Bouton pour supprimer le projet ou le fichier journal, ainsi que pour réinitialiser la vue arborescente

Lorsque vous appuyez sur ce bouton, la fenêtre suivante apparaît :

supprimer, vider

Si vous appuyez sur le bouton "Supprimer et vider", tous les threads d'analyse des fichiers/dossiers seront interrompus, la vue arborescente sera réinitialisée et vous serez appelé à supprimer le fichier ou le projet sélectionné (cliquez simplement sur un élément pour le sélectionner - vous n’avez pas besoin de cocher la case !). Le bouton "Réinitialiser" arrêtera tous les threads d'analyse des fichiers/dossiers et effacera la vue arborescente.

Bouton pour afficher la boîte de dialogue "À propos"

Affiche de brèves informations sur le programme et son auteur.

Bouton pour afficher la fenêtre du programme toujours en haut

Place la fenêtre du programme au-dessus de toutes les autres fenêtres.

Bouton pour activer la surveillance des nouveaux messages dans les fichiers journaux

Ce bouton masque la fenêtre du programme dans la système Barred'état système et active la surveillance des nouveaux messages dans les fichiers journaux. Pour sélectionner le projet/fichier/catégorie qui sera analysé, cochez les cases prés des éléments nécessaires.

Si vous cochez la case prés de la catégorie de messages, la notification se déclenchera sur un nouveau message dans ce projet/fichier/catégorie. Si vous cochez la case près du fichier, la notification se déclenchera sur un nouveau message dans ce fichier pour n'importe quelle catégorie. Enfin, si vous cochez la case prés du projet, la notification se déclenchera sur un nouveau fichier journal et les messages qu'il contient.

Surveillance

Si vous avez activé la surveillance et que la fenêtre du programme est réduite à la barre des tâches, lorsqu'un nouveau message apparaît dans les éléments sélectionnés, la fenêtre principale de l'application sera agrandie avec une notification sonore. Pour désactiver les notifications, cliquez n'importe où dans la liste avec le bouton gauche de la souris. Pour interrompre la surveillance, cliquez sur l'icône du programme dans la barre  LogMon Icône LogMon.Pour modifier le son de la notification à la vôtre, placez le fichier .wav avec le nom "alert.wav" dans le même dossier que le fichier exécutable du programme.  

Afficher la catégorie du journal

Pour afficher une catégorie spécifique, double-cliquez simplement dessus. Ensuite, vous verrez la boîte de message :

Recherche LogMon

Dans cette fenêtre, vous pouvez rechercher des messages, épingler la fenêtre toujours en haut et basculer le défilement automatique. La couleur de chaque message est définie individuellement à l'aide de la méthode write() Clogger Class. L'arrière-plan du message sera mis en évidence avec la couleur sélectionnée.

Lorsque vous double-cliquez sur un message, il s'ouvre dans une fenêtre séparée. Ce sera pratique si le message est trop long et ne rentre pas dans la boîte de dialogue :  

Message LogMon

Vous disposez maintenant d'un outil pratique pour afficher et surveiller les fichiers journaux. Espérons que ce programme vous aidera à élaborer et à utiliser des programmes MQL5.

Conclusion

La collecte de données des événements dans votre programme est très utile, elle vous aide à identifier les erreurs cachées et à révéler les opportunités d'amélioration de votre programme. Dans cet article, j'ai décrit des méthodes et des programmes pour la connexion la plus simple au fichier, la surveillance et la visualisation des journaux.

Vos commentaires et suggestions seront appréciés!

Traduit du russe par MetaQuotes Ltd.
Article original : https://www.mql5.com/ru/articles/150

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

Autres articles par cet auteur

Simulink : un guide pour les développeurs d'Expert Advisors Simulink : un guide pour les développeurs d'Expert Advisors
Je ne suis pas un programmeur professionnel. Et donc, le principe de « passer du simple au complexe » est d’une importance capitale pour moi lorsque je travaille sur l’élaboration d’un système de trading. Qu’est-ce qui est précisément simple pour moi? Tout d’abord, il s’agit de la visualisation du processus de création du système et la logique de son travail. En outre, il s’agit d’un minimum de code manuscrit. Dans cet article, je tenterai de créer et de tester le système de trading, basé sur un package Matlab, puis écrire un Expert Advisor pour MetaTrader 5. Les données historiques de MetaTrader 5 seront utilisées pour le processus de test.
Comment créer rapidement un Expert Advisor  pour le championnat de trading automatisé 2010 Comment créer rapidement un Expert Advisor pour le championnat de trading automatisé 2010
Afin d’élaborer un expert pour participer au Championnat de Trading Automatisé 2010, utilisons un modèle de conseiller expert prêt. Même le programmeur novice MQL5 sera en mesure d’assurer cette tâche, car pour vos stratégies les classes de base, les fonctions, les modèles sont déjà élaborés. Il suffit d'écrire un minimum de code pour implémenter votre idée de trading.
Le gestionnaire d'événements "New Bar" Le gestionnaire d'événements "New Bar"
Le langage de programmation MQL5 est en mesure de résoudre des problèmes à un tout nouveau niveau. Même ces tâches, qui offrent déjà de telles solutions, grâce à la programmation orientée objet peuvent atteindre un niveau supérieur. Dans cet article, nous prenons un exemple particulièrement simple de vérification d'une nouvelle barre sur un graphique, qui a été transformé en un outil plutôt puissant et polyvalent. Quel outil ? Découvrez-le dans cet article.
Contrôler  la Pente de la Courbe d' Équilibre Pendant le Travail d'un Expert Advisor Contrôler la Pente de la Courbe d' Équilibre Pendant le Travail d'un Expert Advisor
Trouver des règles pour un système de trade et les programmer dans un Expert Advisor est la moitié du travail. D'une certaine manière, vous devez corriger le fonctionnement de l'Expert Advisor au fur et à mesure qu'il accumule les résultats du trading. Cet article décrit l'une des approches qui permet d'améliorer les performances d'un Expert Advisor à travers un feedback qui mesure la pente de la courbe d'équilibre.