A Arte de Registrar Logs (Parte 3): Explorando os handlers para armazenamento de logs
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:
- Estrutura robusta utilizando o padrão Singleton, garantindo consistência entre os fragmentos de código.
- Modo de armazenamento avançado para salvar logs em bancos de dados, proporcionando histórico rastreável para análises aprofundadas e auditorias.
- Flexibilidade de saída, permitindo salvar ou exibir logs com praticidade, seja no console, em arquivos, no terminal ou em banco de dados.
- Classificação por níveis de log, diferenciando mensagens informativas de alertas críticos e erros.
- 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:
- O método Append continua recebendo a informação do log (severidade, mensagem, origem, horário etc.).
- Ele cria a mesma variável MqlLogifyModel para guardar os dados.
- 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:
- Emit(MqlLogifyModel &data) processa o log e o envia para o destino especificado (arquivo, console, banco de dados etc.).
- O método Flush() finaliza ou limpa todas as operações pendentes.
- 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. |
Traduzido do Inglês pela MetaQuotes Ltd.
Artigo original: https://www.mql5.com/en/articles/16866
Aviso: Todos os direitos sobre esses materiais pertencem à MetaQuotes Ltd. É proibida a reimpressão total ou parcial.
Esse artigo foi escrito por um usuário do site e reflete seu ponto de vista pessoal. A MetaQuotes Ltd. não se responsabiliza pela precisão das informações apresentadas nem pelas possíveis consequências decorrentes do uso das soluções, estratégias ou recomendações descritas.
Implementação do algoritmo criptográfico SHA-256 do zero em MQL5
Integrando MQL5 com pacotes de processamento de dados (Parte 4): Manipulação de Big Data
Estratégia de trading "Captura de Liquidez" (Liquidity Grab)
Modelos ocultos de Markov para previsão de volatilidade com consideração de tendência
- Aplicativos de negociação gratuitos
- 8 000+ sinais para cópia
- Notícias econômicas para análise dos mercados financeiros
Você concorda com a política do site e com os termos de uso