English Русский 中文 Español Deutsch 日本語
preview
A Arte de Registrar Logs (Parte 3): Explorando os handlers para armazenamento de logs

A Arte de Registrar Logs (Parte 3): Explorando os handlers para armazenamento de logs

MetaTrader 5Exemplos |
52 0
joaopedrodev
joaopedrodev

Introdução

No primeiro artigo deste ciclo, Dominando registros de log (parte 1): Conceitos fundamentais e primeiros passos em MQL5, começamos com a criação de uma biblioteca de logs própria para o desenvolvimento de um EA. Nele, definimos os principais motivos para criar uma ferramenta tão essencial: superar as limitações dos logs nativos do MetaTrader 5 e introduzir uma solução confiável, personalizável e de alto desempenho no universo MQL5.

Relembremos os pontos principais abordados: estabelecemos a base para nossa biblioteca, fixando os seguintes requisitos fundamentais:

  1. Estrutura robusta utilizando o padrão Singleton, garantindo consistência entre os fragmentos de código.
  2. Modo de armazenamento avançado para salvar logs em bancos de dados, proporcionando histórico rastreável para análises aprofundadas e auditorias.
  3. Flexibilidade de saída, permitindo salvar ou exibir logs com praticidade, seja no console, em arquivos, no terminal ou em banco de dados.
  4. Classificação por níveis de log, diferenciando mensagens informativas de alertas críticos e erros.
  5. Customização do formato de saída para atender às necessidades únicas de cada desenvolvedor ou projeto.

Com esse alicerce sólido, ficou claro que o sistema de registro de eventos que estamos desenvolvendo representa muito mais do que um logger simples: ele será um instrumento estratégico para compreender, monitorar e otimizar o comportamento dos EAs em tempo real.

Agora, neste terceiro artigo, daremos um passo importante: entenderemos o conceito de handlers. Enquanto os formatters estruturam os dados, os handlers decidem para onde os logs serão enviados. Eles agem como despachantes de mensagens, direcionando-as aos destinos apropriados, como arquivos, consoles, bancos de dados e sistemas de notificação. Nesta postagem, compreenderemos a lógica por trás dos handlers, criaremos exemplos práticos de uso em diversos cenários e estudaremos sua integração com os formatters. Ao final, você terá todas as ferramentas necessárias para criar fluxos de log altamente personalizáveis e eficientes. Vamos começar?


O que são handlers?

Handlers são componentes-chave que determinam para onde os logs são direcionados. Eles podem ser imaginados como despachantes de mensagens que recebem informação do logger e a encaminham ao destino adequado, seja o console, um arquivo, e-mail ou até um servidor remoto.

Imagine que você administra uma fábrica. Os produtos (logs) precisam ser transportados para diferentes destinos: alguns vão para o estoque, outros para o setor de expedição e outros ficam guardados como registros históricos. O despachante define a rota de cada mensagem, e é essa a função dos handlers.

Cada handler pode ter configurações individuais, como níveis de severidade (por exemplo, enviar apenas mensagens de erro), formatos de saída (por exemplo, incluir ou não carimbos de data e hora) e destinos.

Esses componentes garantem a segregação e roteamento inteligente dos logs, algo especialmente importante para aplicações de médio e grande porte. Os handlers permitem desde ajudar desenvolvedores a depurar erros em tempo real no console, guardar logs detalhados para análise futura, enviar notificações críticas por e-mail quando algo urgente acontece ou encaminhar informações de monitoramento a um servidor central. Tudo isso pode ser feito simultaneamente, sem necessidade de configurações complexas.


Como os handlers funcionam

Para entender como os handlers atuam na prática, vejamos um exemplo da biblioteca. O diagrama abaixo mostra o processo básico de registro de mensagens:

Atualmente, a principal função da classe CLogify é o método Append, responsável por receber os dados do log, incluindo severidade, mensagem, origem e horário do registro. Com essas informações, o método Append cria uma variável do tipo MqlLogifyModel, que é enviada ao console do terminal pela função nativa Print.

Esse processo funciona, mas apresenta limitações: todos os logs só podem ser exibidos no console e não há flexibilidade para processar ou armazenar essas mensagens em outro lugar.

Com a adição dos handlers, o fluxo melhorou significativamente. Observe o novo diagrama:

No novo fluxo:

  1. O método Append continua recebendo a informação do log (severidade, mensagem, origem, horário etc.).
  2. Ele cria a mesma variável MqlLogifyModel para guardar os dados.
  3. Em vez de enviar diretamente ao console, o log agora é passado para uma lista de handlers, representada pelo array Handlers.

Cada handler pode processar os dados de forma independente, permitindo encaminhar mensagens para vários destinos.

Aqui estão três exemplos principais de handlers que podem ser usados nesse sistema:

  • HandlerTerminal exibe os logs diretamente no terminal MetaTrader 5, o que é útil para diagnóstico e depuração em tempo real.
  • HandlerFile grava os logs em arquivos com extensão .txt ou .log, sendo ideal para armazenar o histórico de execuções ou criar relatórios detalhados para análise futura.
  • HandlerDatabase salva os logs em um banco de dados, como o SQLite, permitindo executar consultas avançadas sobre os dados, incluindo análise de tendências ou auditorias mais complexas.

Vou dar um exemplo prático da utilidade dos handlers. Imagine que você desenvolveu um robô de negociação que precisa de um sistema de logs eficiente para monitorar sua operação. Você pode configurar os handlers da seguinte forma:

  • Salvar em arquivo apenas as mensagens DEBUG e INFO, para registrar todas as operações executadas, incluindo entradas e saídas do mercado.
  • Exibir no terminal apenas mensagens WARN e ERROR, o que permitirá acompanhar problemas em tempo real.
  • Registrar erros críticos no banco de dados, para que engenheiros ou analistas possam posteriormente acessar e analisar as informações correspondentes.

Essa estrutura proporciona um sistema de logging mais confiável, organizado e eficiente. Com os handlers, você tem controle total sobre como e onde os logs são processados e armazenados.


Implementação da classe base de handlers

Vamos implementar a classe base CLogifyHandler, que servirá como fundação (classe pai) para todos os handlers que criaremos mais adiante. Começamos criando a pasta Handlers no diretório raiz da biblioteca. Dentro dessa nova pasta, crie o arquivo LogifyHandler. Nesse arquivo, será definido o código da classe CLogifyHandler, que inicialmente conterá apenas um construtor e um destrutor básicos. O código-fonte ficará assim:

//+------------------------------------------------------------------+
//|                                                LogifyHandler.mqh |
//|                                                     joaopedrodev |
//|                       https://www.mql5.com/en/users/joaopedrodev |
//+------------------------------------------------------------------+
#property copyright "joaopedrodev"
#property link      "https://www.mql5.com/en/users/joaopedrodev"
//+------------------------------------------------------------------+
//| class : CLogifyHandler                                           |
//|                                                                  |
//| [PROPERTY]                                                       |
//| Name        : CLogifyHandler                                     |
//| Heritage    : No heritage                                        |
//| Description : Base class for all log handlers.                   |
//|                                                                  |
//+------------------------------------------------------------------+
class CLogifyHandler
  {
public:
                     CLogifyHandler(void);
                    ~CLogifyHandler(void);
  };
//+------------------------------------------------------------------+
//| Constructor                                                      |
//+------------------------------------------------------------------+
CLogifyHandler::CLogifyHandler(void)
  {
  }
//+------------------------------------------------------------------+
//| Destructor                                                       |
//+------------------------------------------------------------------+
CLogifyHandler::~CLogifyHandler(void)
  {
  }
//+------------------------------------------------------------------+

Neste estágio, a classe CLogifyHandler funciona como um modelo, que será expandido posteriormente para incluir funcionalidades adicionais.

Agora adicionamos os imports necessários, começando pelo arquivo LogifyModel.mqh, que define o modelo de logging usado pelos handlers.

//+------------------------------------------------------------------+
//| Include files                                                    |
//+------------------------------------------------------------------+
#include "../LogifyModel.mqh"

Esse arquivo contém a definição da classe ou estrutura MqlLogifyModel, utilizada para encapsular os dados de cada mensagem, como nível de severidade, texto e origem.

O próximo passo é adicionar dois atributos protegidos à classe:

  • m_name armazena o nome do handler, o que pode ser útil para identificação durante a depuração ou geração de relatórios;
  • m_level define o nível de severidade que o handler irá processar (por exemplo, DEBUG, INFO, ERROR).

Além disso, criaremos métodos públicos para definir e obter esses valores.

class CLogifyHandler
  {
protected:
   string            m_name;
   ENUM_LOG_LEVEL    m_level;
   
public:
   //--- Set/Get
   void              SetLevel(ENUM_LOG_LEVEL level);
   string            GetName(void);
   ENUM_LOG_LEVEL    GetLevel(void);
  };
//+------------------------------------------------------------------+
//| Set level                                                        |
//+------------------------------------------------------------------+
void CLogifyHandler::SetLevel(ENUM_LOG_LEVEL level)
  {
   m_level = level;
  }
//+------------------------------------------------------------------+
//| Get name                                                         |
//+------------------------------------------------------------------+
string CLogifyHandler::GetName(void)
  {
   return(m_name);
  }
//+------------------------------------------------------------------+
//| Get level                                                        |
//+------------------------------------------------------------------+
ENUM_LOG_LEVEL CLogifyHandler::GetLevel(void)
  {
   return(m_level);
  }
//+------------------------------------------------------------------+

O atributo m_name pode ser definido apenas nas classes derivadas, por meio de seus construtores, o que garante segurança e encapsulamento. Por esse motivo, não há um método SetName.

Existem três métodos principais que todos os handlers devem implementar:

  1. Emit(MqlLogifyModel &data) processa o log e o envia para o destino especificado (arquivo, console, banco de dados etc.).
  2. O método Flush() finaliza ou limpa todas as operações pendentes.
  3. O método Close() encerra o handler e libera os recursos associados a ele.

Neste momento, essas funções são definidas como virtuais, com uma implementação padrão vazia. Isso permite que cada classe filha personalize o comportamento conforme necessário.

class CLogifyHandler
  {
public:
   //--- Handler methods
   virtual void      Emit(MqlLogifyModel &data);         // Processes a log message and sends it to the specified destination
   virtual void      Flush(void);                        // Clears or completes any pending operations
   virtual void      Close(void);                        // Closes the handler and releases any resources
  };
//+------------------------------------------------------------------+
//| Processes a log message and sends it to the specified destination|
//+------------------------------------------------------------------+
void CLogifyHandler::Emit(MqlLogifyModel &data)
  {
  }
//+------------------------------------------------------------------+
//| Clears or completes any pending operations                       |
//+------------------------------------------------------------------+
void CLogifyHandler::Flush(void)
  {
  }
//+------------------------------------------------------------------+
//| Closes the handler and releases any resources                    |
//+------------------------------------------------------------------+
void CLogifyHandler::Close(void)
  {
  }
//+------------------------------------------------------------------+

Nesta etapa, os métodos ainda não executam nenhuma ação, pois a implementação específica de cada handler depende das classes derivadas (como HandlerFile, HandlerDatabase etc.).


Implementação dos handlers

Após a implementação da classe base CLogifyHandler, podemos começar a criar handlers especializados, herdados dela. Essa abordagem segue os princípios fundamentais da programação orientada a objetos, como herança e polimorfismo, garantindo modularidade e flexibilidade ao código. Cada handler especializado será responsável por processar logs de uma forma específica, utilizando a estrutura comum da classe base, mas implementando sua própria lógica para os métodos Emit, Flush e Close.

Antes de implementar os handlers, vamos estruturar melhor o projeto. Crie três novos arquivos dentro da pasta Handlers: LogifyHandlerConsole.mqh, LogifyHandlerDatabase.mqh e LogifyHandlerFile.mqh. A estrutura final ficará assim:

No arquivo LogifyHandlerConsole.mqh, criaremos a classe CLogifyHandlerConsole, que herda os atributos e métodos da classe base CLogifyHandler. Uma das primeiras modificações será o valor da variável m_name, definida como "console" no construtor da classe. Isso ajudará a identificar claramente o handler durante a execução. Eis a definição inicial da classe:

//+------------------------------------------------------------------+
//| Include files                                                    |
//+------------------------------------------------------------------+
#include "LogifyHandler.mqh"
//+------------------------------------------------------------------+
//| class : CLogifyHandlerConsole                                    |
//|                                                                  |
//| [PROPERTY]                                                       |
//| Name        : CLogifyHandlerConsole                              |
//| Heritage    : CLogifyHandler                                     |
//| Description : Log handler, inserts data into terminal window.    |
//|                                                                  |
//+------------------------------------------------------------------+
class CLogifyHandlerConsole : public CLogifyHandler
  {
public:
                     CLogifyHandlerConsole(void);
                    ~CLogifyHandlerConsole(void);
   
   virtual void      Emit(MqlLogifyModel &data);         // Processes a log message and sends it to the specified destination
   virtual void      Flush(void);                        // Clears or completes any pending operations
   virtual void      Close(void);                        // Closes the handler and releases any resources
  };
//+------------------------------------------------------------------+
//| Constructor                                                      |
//+------------------------------------------------------------------+
CLogifyHandlerConsole::CLogifyHandlerConsole(void)
  {
   m_name = "console";
  }
//+------------------------------------------------------------------+
//| Destructor                                                       |
//+------------------------------------------------------------------+
CLogifyHandlerConsole::~CLogifyHandlerConsole(void)
  {
  }
//+------------------------------------------------------------------+

A função Emit é responsável principalmente por processar os logs e enviá-los ao destino correspondente. No caso do console, isso significa exibir a mensagem formatada no terminal do MetaTrader. Abaixo está a implementação desse método:

//+------------------------------------------------------------------+
//| Processes a log message and sends it to the specified destination|
//+------------------------------------------------------------------+
void CLogifyHandlerConsole::Emit(MqlLogifyModel &data)
  {
   if(data.level >= this.GetLevel())
     {
      Print("Console handler: ",data.formated);
     }
  }
//+------------------------------------------------------------------+

Note que, antes de exibir a mensagem, é verificado se o nível do log (data.level) corresponde ao nível configurado no handler. Isso garante que apenas mensagens importantes ou relevantes sejam mostradas.

Seguindo o mesmo princípio do handler de console, podemos criar outros handlers especializados, por exemplo, para bancos de dados e arquivos. Para isso, é necessário modificar os arquivos LogifyHandlerDatabase.mqh e LogifyHandlerFile.mqh. Embora esses handlers possam compartilhar a mesma lógica básica, suas implementações específicas do método Emit podem variar.

Esse handler é destinado ao armazenamento de logs em um banco de dados, embora, por enquanto, exibiremos a mensagem no console apenas para fins de demonstração. O código da função Emit ficará assim:

//+------------------------------------------------------------------+
//| Processes a log message and sends it to the specified destination|
//+------------------------------------------------------------------+
void CLogifyHandlerDatabase::Emit(MqlLogifyModel &data)
  {
   if(data.level >= this.GetLevel())
     {
      Print("Database handler: ",data.formated);
     }
  }
//+------------------------------------------------------------------+

O handler LogifyHandlerFile será usado para gravar logs em um arquivo específico. Aqui está a implementação inicial do método Emit:

//+------------------------------------------------------------------+
//| Processes a log message and sends it to the specified destination|
//+------------------------------------------------------------------+
void CLogifyHandlerFile::Emit(MqlLogifyModel &data)
  {
   if(data.level >= this.GetLevel())
     {
      Print("File handler: ",data.formated);
     }
  }
//+------------------------------------------------------------------+

Embora tenhamos definido os métodos Flush e Close na classe base, nem todos os handlers precisam implementá-los imediatamente.

  • O método Flush é útil em handlers mais complexos, por exemplo, ao gravar em arquivo ou transmitir dados em tempo real.
  • O método Close é necessário para liberar recursos, como conexões com bancos de dados ou fechamento de fluxos de escrita.

Para o handler de console, esses métodos permanecem vazios, pois não há necessidade de operações adicionais. Lembre-se de que aqui estão apenas trechos de código; a versão completa será apresentada no final do artigo.


Adicionando handlers à classe CLogify

Agora que implementamos os handlers e eles funcionam isoladamente, é hora de integrá-los à classe principal da biblioteca, chamada CLogify. Para isso, começamos importando a classe base CLogifyHandler, que contém a estrutura necessária para todos os handlers:

#include "Handlers/LogifyHandler.mqh"
#include "Handlers/LogifyHandlerConsole.mqh"
#include "Handlers/LogifyHandlerDatabase.mqh"
#include "Handlers/LogifyHandlerFile.mqh"

Na implementação da classe CLogify, adicionaremos um atributo privado para armazenar os handlers que serão utilizados. Optei por um array de ponteiros do tipo CLogifyHandler, pois os handlers serão gerenciados dinamicamente.

Além disso, a classe possuirá métodos específicos para gerenciar os handlers:

  • AddHandler adiciona um novo handler ao array.
  • HasHandler verifica se um handler específico já existe na lista, usando seu nome como critério.
  • GetHandler obtém o handler pelo nome ou pelo índice no array.
  • SizeHandlers retorna o número total de handlers na lista.

Aqui está o código atualizado da classe CLogify, agora com esses métodos incluídos:

class CLogify
  {
private:
   CLogifyHandler    *m_handlers[];
   
public:
   //--- Handler
   void              AddHandler(CLogifyHandler *handler);
   bool              HasHandler(string name);
   CLogifyHandler    *GetHandler(string name);
   CLogifyHandler    *GetHandler(int index);
   int               SizeHandlers(void);
  };
//+------------------------------------------------------------------+
//| Add handler to handlers array                                    |
//+------------------------------------------------------------------+
void CLogify::AddHandler(CLogifyHandler *handler)
  {
   int size = ArraySize(m_handlers);
   ArrayResize(m_handlers,size+1);
   m_handlers[size] = GetPointer(handler);
  }
//+------------------------------------------------------------------+
//| Checks if handler is already in the array by name                |
//+------------------------------------------------------------------+
bool CLogify::HasHandler(string name)
  {
   int size = ArraySize(m_handlers);
   for(int i=0;i<size;i++)
     {
      if(m_handlers[i].GetName() == name)
        {
         return(true);
        }
     }
   return(false);
  }
//+------------------------------------------------------------------+
//| Get handler by name                                              |
//+------------------------------------------------------------------+
CLogifyHandler *CLogify::GetHandler(string name)
  {
   int size = ArraySize(m_handlers);
   for(int i=0;i<size;i++)
     {
      if(m_handlers[i].GetName() == name)
        {
         return(m_handlers[i]);
        }
     }
   return(NULL);
  }
//+------------------------------------------------------------------+
//| Get handler by index                                             |
//+------------------------------------------------------------------+
CLogifyHandler *CLogify::GetHandler(int index)
  {
   return(m_handlers[index]);
  }
//+------------------------------------------------------------------+
//| Gets the total size of the handlers array                        |
//+------------------------------------------------------------------+
int CLogify::SizeHandlers(void)
  {
   return(ArraySize(m_handlers));
  }
//+------------------------------------------------------------------+

Depois de preparar os métodos de gerenciamento dos handlers, ajustamos a função Append para que ela utilize os handlers ao processar logs.

Agora, o método Append percorrerá todos os handlers disponíveis no array e chamará o método Emit de cada um deles, fazendo com que o log seja enviado ao destino apropriado (como console, banco de dados etc.).

Aqui está o código atualizado para o método Append:

//+------------------------------------------------------------------+
//| Generic method for adding logs                                   |
//+------------------------------------------------------------------+
bool CLogify::Append(ENUM_LOG_LEVEL level,string msg, string origin = "", string args = "",string filename="",string function="",int line=0)
  {
   //--- If the formatter is not configured, the log will not be recorded.
   if(m_formatter == NULL)
     {
      return(false);
     }
   
   //--- Textual name of the log level
   string levelStr = "";
   switch(level)
     {
      case LOG_LEVEL_DEBUG: levelStr = "DEBUG"; break;
      case LOG_LEVEL_INFOR: levelStr = "INFOR"; break;
      case LOG_LEVEL_ALERT: levelStr = "ALERT"; break;
      case LOG_LEVEL_ERROR: levelStr = "ERROR"; break;
      case LOG_LEVEL_FATAL: levelStr = "FATAL"; break;
     }
   
   //--- Creating a log template with detailed information
   datetime time_current = TimeCurrent();
   MqlLogifyModel data("",levelStr,msg,args,time_current,time_current,level,origin,filename,function,line);
   data.formated = m_formatter.FormatLog(data);
   
   //--- Call handlers
   int size = this.SizeHandlers();
   for(int i=0;i<size;i++)
     {
      m_handlers[i].Emit(data);
     }
   
   return(true);
  }
//+------------------------------------------------------------------+

Algumas observações:

  • O log formatado é armazenado em data.formatted, o que garante que todas as informações completas estejam disponíveis para todos os handlers.
  • Cada handler processa o log de forma independente, chamando seu próprio método Emit.

O último ajuste que faremos será a exclusão dos ponteiros do array no destrutor da classe.

//+------------------------------------------------------------------+
//| Destructor                                                       |
//+------------------------------------------------------------------+
CLogify::~CLogify()
  {
   //--- Delete formatter
   if(m_formatter != NULL)
     {
      delete m_formatter;
     }
   
   //--- Delete handlers
   int size_handlers = ArraySize(m_handlers);
   for(int i=0;i<size_handlers;i++)
     {
      delete m_handlers[i];
     }
  }
//+------------------------------------------------------------------+


Testando os handlers

Neste exemplo, utilizaremos o arquivo de teste LogifyTest.mq5 mencionado anteriormente. Nosso objetivo é demonstrar como configurar e utilizar dois handlers de logs, cada um com um nível de logging diferente, e observar como esses logs serão registrados de acordo com os filtros definidos.

Primeiro, criaremos dois handlers, responsáveis por registrar os logs em locais e níveis diferentes:

  • Console – será uma instância de CLogifyHandlerConsole, configurada para registrar mensagens no nível DEBUG, ou seja, todas as mensagens, desde as mais detalhadas até os erros críticos.
  • Arquivo – será uma instância de CLogifyHandlerFile, configurada para capturar apenas mensagens no nível INFO, filtrando as mensagens DEBUG.

Aqui está o código para configurar esses handlers:

int OnInit()
  {
   //--- Console
   CLogifyHandler *handler_console = new CLogifyHandlerConsole();
   handler_console.SetLevel(LOG_LEVEL_DEBUG);
   
   //--- File
   CLogifyHandler *handler_file = new CLogifyHandlerFile();
   handler_file.SetLevel(LOG_LEVEL_INFOR);
   
   return(INIT_SUCCEEDED);
  }

Após configurar os handlers, o próximo passo será adicioná-los à nossa classe base CLogify, responsável por gerenciar todos os logs da aplicação.

Além disso, adicionaremos uma programa de formatação para definir como os logs serão exibidos. No exemplo, o formatter formatará os logs seguindo o padrão: "hora:minuto:segundo, [nível de log], mensagem".

Depois de configurar os handlers e o formatter, emitiremos três mensagens em níveis diferentes. Abaixo está o código completo para essa etapa:

int OnInit()
  {
   //--- Console
   CLogifyHandler *handler_console = new CLogifyHandlerConsole();
   handler_console.SetLevel(LOG_LEVEL_DEBUG);
   
   //--- File
   CLogifyHandler *handler_file = new CLogifyHandlerFile();
   handler_file.SetLevel(LOG_LEVEL_INFOR);
   
   //--- Config
   logify.SetFormatter(new CLogifyFormatter("hh:mm:ss","{date_time} [{levelname}] {msg}"));
   logify.AddHandler(handler_console);
   logify.AddHandler(handler_file);
   
   //--- Logs
   logify.Debug("Debug Message");
   logify.Infor("Information Message");
   logify.Error("Error Message");
   
   return(INIT_SUCCEEDED);
  }

Ao executar o código acima, o console exibirá o seguinte resultado:

Console handler: 03:20:05 [DEBUG] Debug Message
Console handler: 03:20:05 [INFOR] Information Message
File handler: 03:20:05 [INFOR] Information Message
Console handler: 03:20:05 [ERROR] Error Message
File handler: 03:20:05 [ERROR] Error Message

Interpretação dos resultados:

  • O handler de console (handler_console) capturou todas as mensagens, desde DEBUG até ERROR. Portanto, três registros foram exibidos no console, um para cada log emitido.
  • O handler de arquivo (handler_file) foi configurado para registrar apenas mensagens no nível INFO ou superior. Assim, ele ignorou as mensagens DEBUG e gravou apenas as mensagens INFO e ERROR, totalizando dois registros no arquivo de log.


Conclusão

Neste artigo demos um passo importante na construção da nossa biblioteca de logging em MQL5. Exploramos o conceito de handlers, compreendendo seu papel essencial como "condutores" dos logs para diferentes destinos. Vimos como eles trabalham em conjunto com os formatters, formando um sistema de logging coeso e modular.

Na prática, criamos uma estrutura básica de handlers, definindo uma classe abstrata que servirá como base para todas as futuras implementações. Também desenvolvemos três handlers iniciais: Console, Database e File, responsáveis por direcionar os logs para o console, banco de dados e arquivos, respectivamente. Embora, por enquanto, todos utilizem a função Print() para simulação, essa base sólida permite futuramente expandir e especializar cada classe para tarefas específicas.

Nos testes, verificamos a integração dos handlers com nossa biblioteca e mostramos como eles podem ser adicionados e utilizados de forma flexível. Esse processo demonstrou o potencial dos handlers como componentes modulares, capazes de se adaptar a diferentes necessidades no contexto do logging.


Todo o código utilizado neste artigo está apresentado abaixo. A seguir, uma tabela com a descrição de cada arquivo da biblioteca:

Nome do arquivo
Descrição
Experts/Logify/LogifyTest.mq5
Arquivo no qual testamos as funções da biblioteca, contendo um exemplo prático.
Include/Logify/Formatter/LogifyFormatter.mqh
Classe responsável por formatar as mensagens, substituindo os placeholders pelos valores correspondentes.
Include/Logify/Handlers/LogifyHandler.mqh
Classe base para o gerenciamento dos handlers de logs, incluindo configuração de nível e envio das mensagens.
Include/Logify/Handlers/LogifyHandlerConsole.mqh
Handler de logs que envia as mensagens formatadas diretamente para o console do terminal MetaTrader.
Include/Logify/Handlers/LogifyHandlerDatabase.mqh
Handler de logs que envia as mensagens formatadas para o banco de dados (atualmente apenas imprime, mas em breve armazenará em um banco real SQLite).
Include/Logify/Handlers/LogifyHandlerFile.mqh
Handler de logs que envia as mensagens formatadas para um arquivo (atualmente apenas imprime, mas em breve gravará em um arquivo real).
Include/Logify/Logify.mqh
Classe principal de gerenciamento de logs, integrando níveis, modelos e formatação.
Include/Logify/LogifyLevel.mqh
Arquivo que define os níveis de logging da biblioteca Logify, permitindo controle detalhado.
Include/Logify/LogifyModel.mqh
Estrutura que modela os logs, incluindo informações como nível, mensagem, carimbo de tempo e contexto.
No próximo artigo, implementaremos completamente cada handler, explorando como armazenar logs em arquivos, salvar dados em bancos de dados e configurar saídas específicas no terminal.


Traduzido do Inglês pela MetaQuotes Ltd.
Artigo original: https://www.mql5.com/en/articles/16866

Arquivos anexados |
LogifyfPart3a.zip (11.96 KB)
Implementação do algoritmo criptográfico SHA-256 do zero em MQL5 Implementação do algoritmo criptográfico SHA-256 do zero em MQL5
Criar integrações com bolsas de criptomoedas sem arquivos DLL foi, por muito tempo, uma tarefa complexa, mas esta solução fornece uma base completa para conexão direta ao mercado.
Integrando MQL5 com pacotes de processamento de dados (Parte 4): Manipulação de Big Data Integrando MQL5 com pacotes de processamento de dados (Parte 4): Manipulação de Big Data
Explorando técnicas avançadas para integrar o MQL5 com ferramentas poderosas de processamento de dados, esta parte se concentra no tratamento eficiente de big data para aprimorar a análise de negociação e a tomada de decisões.
Estratégia de trading "Captura de Liquidez" (Liquidity Grab) Estratégia de trading "Captura de Liquidez" (Liquidity Grab)
A estratégia de captura de liquidez é um componente-chave do Smart Money Concepts (SMC), que visa identificar e aproveitar as ações dos participantes institucionais no mercado. Ela envolve mirar áreas de alta liquidez, como zonas de suporte ou resistência, onde ordens de grande volume podem provocar um movimento de preço antes que o mercado retome sua tendência. Este artigo explica em detalhes o conceito de captura de liquidez e descreve o processo de desenvolvimento de um EA para a estratégia de captura de liquidez em MQL5.
Modelos ocultos de Markov para previsão de volatilidade com consideração de tendência Modelos ocultos de Markov para previsão de volatilidade com consideração de tendência
Os modelos ocultos de Markov (HMM) são uma poderosa ferramenta estatística que permite identificar estados ocultos do mercado com base na análise de movimentos observáveis dos preços. No trading, os HMM permitem melhorar a previsão da volatilidade e são aplicados no desenvolvimento de estratégias de tendência, modelando as mudanças nos regimes de mercado. Neste artigo, apresentaremos um processo passo a passo para o desenvolvimento de uma estratégia de seguimento de tendência que utiliza HMM como filtro para previsão de volatilidade.