English Deutsch
preview
ログレコードをマスターする(第3回):ログを保存するためのハンドラの調査

ログレコードをマスターする(第3回):ログを保存するためのハンドラの調査

MetaTrader 5 | 29 5月 2025, 08:16
120 0
joaopedrodev
joaopedrodev

はじめに

本連載最初の記事、「ログレコードをマスターする(第1回):MQL5の基本概念と最初のステップ」では、エキスパートアドバイザー(EA)開発に最適化したログライブラリの作成に着手しました。そこで、MetaTrader 5の標準ログの制限を克服し、MQL5の世界に堅牢でカスタマイズ可能な強力なソリューションをもたらすという、この重要なツールを作る動機を探りました。

前回の記事で取り上げた主なポイントを振り返ると、私たちは次のような基本要件をもとにライブラリの基盤を構築しました。

  1. シングルトンによる堅牢な構造で、コードコンポーネント間の一貫性を確保
  2. データベースへの永続的な保存により、詳細な監査や分析を可能にする追跡可能な履歴の実現
  3. 柔軟な出力形式に対応し、コンソール、ファイル、端末、データベースなど多様な出力先をサポート
  4. ログレベルによる分類で、情報メッセージと重大なアラート・エラーを明確に区別
  5. 出力フォーマットのカスタマイズにより、開発者やプロジェクトごとの個別ニーズに対応

このような強固な基盤を構築したことで、私たちのログフレームワークは単なるイベントログではなく、EAの動作をリアルタイムで把握・監視・最適化するための戦略的ツールとしての価値を持つことが明らかになりました。

さて、この第3回の記事では、ハンドラ概念を理解するという重要な一歩を踏み出します。フォーマッターがデータを整理する役割を担うのに対し、ハンドラはログをどこに送るかを決定します。ハンドラは「配管工」のように機能し、ファイルやコンソール、データベース、通知システムなど適切な宛先へメッセージを届けます。この記事では、ハンドラの背後にあるロジックを理解し、様々なシナリオで使える実用的な例を作成、さらにフォーマッターとの連携についても探ります。この記事を読み終える頃には、高度にカスタマイズ可能で効率的なログストリームを構築するためのすべてのツールが手に入るでしょう。では、始めましょう。


ハンドラとは何か

ハンドラは、ログメッセージを送信する先を決める基本的なコンポーネントです。ロガーから情報を受け取り、コンソールやファイル、メール、リモートサーバーなど、適切な宛先へとメッセージを振り分ける「メッセージの配達係」のような役割を担っています。

例えば、あなたが工場を管理していると想像してください。製品(ログメッセージ)はそれぞれ異なる場所へ運ばれる必要があります。倉庫に送られるものもあれば、出荷されるもの、そして履歴として保管されるものもあります。配達係は各製品の送り先を決定する役割を持ち、これがハンドラの役目です。

各ハンドラには、例えば「重大度レベル(例:エラーメッセージのみ送る)」「出力フォーマット(例:タイムスタンプを含めるかどうか)」「出力先」などの設定が個別に指定できます。

これらのコンポーネントは、ログメッセージの振り分けや効率的なルーティングを実現するうえで非常に重要です。特に中規模以上のアプリケーションでは必須と言えます。ハンドラを使うことで、開発者はコンソール上でリアルタイムにエラーをデバッグしたり、詳細なログを保存して後から分析したり、緊急時には重要なメール通知を送信したり、監視情報を中央サーバーに送ったりすることが可能になります。これらすべてを複雑な設定なしで同時に実現できるのがハンドラの強みです。


ハンドラの仕組み

ハンドラが実際にどのように機能するかを理解するために、ライブラリの例を見てみましょう。下の図は、メッセージログの基本的な流れを示しています。

現在のフローにおいて、CLogifyクラスの主な関数は、ログエントリの重大度レベル、メッセージ、ソース、時間などのログデータを受け取るAppendメソッドです。このメソッドは受け取ったデータからMqlLogifyModel型の変数を生成し、その変数をネイティブのPrint関数を通じて端末のコンソールに送信します。

このフローは動作しますが、制約もあります。すべてのログはコンソールにのみ表示され、他の場所でメッセージを処理したり保存したりする柔軟性がありません。

しかし、ハンドラを実装することで、このフローは大幅に改善されました。以下の新しい図をご覧ください。

新しいフローでは以下のようになります。

  1. Appendメソッドは引き続き、ログ情報(重大度、メッセージ、ソース、時間など)を受け取ります。
  2. 受け取ったデータを格納するために、同じくMqlLogifyModel型の変数を生成します。
  3. これまでのように直接コンソールに送信する代わりに、ログはHandlers配列で管理される複数のハンドラに渡されます。

各ハンドラは独立してデータを処理できるため、ログメッセージを複数の宛先に振り分けることが可能になります。

このシステムで利用できる基本的なハンドラの例を3つ紹介します。

  • HandlerTerminal:MetaTrader 5の端末にログを直接表示し、リアルタイムの診断やデバッグに役立ちます。
  • HandlerFile:ログを.txtや.log形式のファイルに保存し、実行履歴の記録や将来の分析のための詳細なレポート作成に最適です。
  • HandlerDatabase:SQLiteなどのデータベースにログを保存し、傾向分析やより複雑な監査に対応する高度なデータクエリを可能にします。

ハンドラの有用性を具体例で説明しましょう。たとえば、取引ロボットを開発し、その実行状況を効率的に監視するためのログシステムが必要だとします。ハンドラは次のように設定できます。

  • 市場のエントリー・エグジットを含むすべての操作を記録するために、DEBUGとINFOレベルのメッセージのみをファイルに保存する。
  • 問題をリアルタイムで追跡できるよう、WARNとERRORレベルのメッセージを端末に表示する。
  • 重大なエラーはデータベースに保存し、エンジニアやアナリストが後から情報を取得・分析できるようにする。

このように構成することで、堅牢かつ整理された効率的なログシステムが実現します。ハンドラを活用することで、ログの処理方法や保存場所を自在にコントロールできるのです。


ハンドラ基底クラスの実装

まず、すべてのハンドラの共通の基底クラス(親クラス)となるCLogifyHandlerを実装しましょう。ライブラリのルートディレクトリに「Handlers」というフォルダを作成し、その中に「LogifyHandler」というファイルを新規作成します。このファイル内に、CLogifyHandlerクラスを定義します。最初は基本的なコンストラクタとデストラクタだけを持つシンプルなクラスです。初期のコードは以下のようになります。

//+------------------------------------------------------------------+
//|                                                LogifyHandler.mqh |
//|                                                     joaopedrodev |
//|                       https://www.mql5.com/ja/users/joaopedrodev |
//+------------------------------------------------------------------+
#property copyright "joaopedrodev"
#property link      "https://www.mql5.com/ja/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)
  {
  }
//+------------------------------------------------------------------+

この時点で、CLogifyHandlerクラスは「骨組み」として機能しており、今後さらに機能を拡張していきます。

次に、必要なインポートを追加しましょう。まずは、ハンドラで使用するログモデルが定義されているLogifyModel.mqhファイルをインクルードします。

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

このファイルには、重大度レベル、メッセージ、ソースなど、各ログメッセージのデータをカプセル化するために使われるMqlLogifyModelクラスまたは構造体の定義が含まれています。

次に、クラスに以下の2つのprotected属性を追加します。

  • m_name:ハンドラの名前を保持します。デバッグやレポート作成時の識別に役立ちます。
  • m_level:ハンドラが処理するログの重大度レベルを定義します(例:DEBUG、INFO、ERROR)。

また、これらの属性を設定・取得するためのpublicメソッドも実装します。

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

m_name属性は、派生クラスのコンストラクタ内でのみ設定可能とし、セキュリティとカプセル化を強化しています。そのため、SetNameメソッドは用意していません。

すべてのハンドラが実装すべき基本的なメソッドは以下の3つです。

  1. Emit(MqlLogifyModel &data):ログメッセージを処理し、指定された宛先(ファイル、コンソール、データベースなど)に送信します。
  2. Flush():保留中の操作を終了またはクリアします。
  3. Close():ハンドラを閉じ、関連するリソースを解放します。

現時点では、これらの関数は仮想関数として定義し、デフォルトでは空の実装とします。これにより、各派生クラスが必要に応じて動作をカスタマイズできるようになります。

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

この段階では、各メソッドは何も処理をおこないません。具体的な動作は、HandlerFileHandlerDatabaseといった子クラスが実装することになります。


ハンドラの実装

基底クラスCLogifyHandlerを実装したら、それを継承する専門的なハンドラの作成に取りかかることができます。このアプローチは、継承やポリモーフィズムなどオブジェクト指向プログラミングの基本原則に則っており、コードのモジュール性と柔軟性を高めます。各専門ハンドラは、基底クラスの共通構造を活用しつつ、Emit、Flush、Closeメソッドに対して独自のロジックを実装し、それぞれの方法でログを処理します。

ハンドラの実装に入る前に、プロジェクトを整理しましょう。Handlersフォルダ内に、LogifyHandlerConsole.mqh、LogifyHandlerDatabase.mqh、LogifyHandlerFile.mqhの3つのファイルを新規作成します。最終的なフォルダ構成は以下のようになります。

LogifyHandlerConsole.mqhファイルでは、基底クラスCLogifyHandlerの属性とメソッドを継承するCLogifyHandlerConsoleクラスを作成します。最初の変更点のひとつとして、m_name変数の値をクラスのコンストラクタ内で「console」に設定します。これにより、実行時にハンドラを明確に識別しやすくなります。以下はクラスの初期定義です。

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

Emit関数は、主にログメッセージを処理し、適切な宛先に送信する役割を持ちます。コンソールの場合は、フォーマットされたメッセージをMetaTraderの端末に表示するだけです。以下がそのメソッドの実装です。

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

メッセージを表示する前に、ログレベル(data.level)がハンドラで設定されたレベルと一致しているかを確認している点に注意してください。これにより、重要または関連性のあるメッセージのみが表示されます。

コンソールハンドラと同様の考え方で、データベースやファイル用の他の専用ハンドラも作成可能です。対象ファイルはLogifyHandlerDatabase.mqhとLogifyHandlerFile.mqhです。これらのハンドラは基本的なロジックを共有しつつも、Emitメソッドの実装はそれぞれ異なる場合があります。

このハンドラはログをデータベースに保存することを目的としていますが、ここではデモ用にコンソールにメッセージを表示する形で示します。Emit関数のコードは以下のようになります。

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

LogifyHandlerFileハンドラは、ログを特定のファイルに書き込むために使用されます。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);
     }
  }
//+------------------------------------------------------------------+

基底クラスでFlushメソッドとCloseメソッドを定義していますが、すべてのハンドラがすぐにこれらを実装する必要はありません。

  • Flushメソッドは、ファイル書き込みやリアルタイムストリーミングのような、より複雑なハンドラで役立ちます。
  • Closeメソッドは、データベース接続の解放や書き込みストリームのクローズなど、リソースを解放する際に必須です。

コンソールハンドラの場合は、これらのメソッドは空のままにしており、追加の処理はおこないません。なお、ここで示しているのはコードの断片であり、完全版は記事の最後からダウンロード可能です。


CLogifyクラスへのハンドラの追加

ハンドラを実装して個別に動作することを確認したので、次はライブラリのメインクラスであるCLogifyに統合します。そのために、まずはすべてのハンドラに共通の基盤となるクラスCLogifyHandlerをインポートします。これにより、ハンドラの基本構造を利用できるようになります。

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

CLogifyクラスの実装では、使用するハンドラを格納するためのprivate属性を追加します。ハンドラは動的に管理されるため、CLogifyHandler型のポインタ配列を選択しました。

また、ハンドラを管理するための専用メソッドもクラスに用意します。

  • AddHandler:配列に新しいハンドラを追加します。
  • HasHandler:特定のハンドラが名前を基準としてリスト内に既に存在するかどうかを確認します。
  • GetHandler:名前または配列内のインデックスによってハンドラを取得します。
  • SizeHandlers:リスト内のハンドラの合計数を返します。

以下は、CLogifyクラスの更新されたコードです。次のメソッドが追加されています。

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

ハンドラ管理用のメソッドが整ったので、ログ処理時にハンドラを利用するようにAppend関数の動作を調整しましょう。

Appendメソッドは、配列内のすべてのハンドラを順に処理し、それぞれのEmitメソッドを呼び出してログを適切な宛先(コンソールやデータベースなど)に送信します。

以下は、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);
  }
//+------------------------------------------------------------------+

観察点

  • フォーマット済みのログはdata.formattedに格納されており、すべてのハンドラで完全な情報を利用可能にしています。
  • 各ハンドラは独立してログを処理し、それぞれのEmitメソッドを呼び出します。

最後の調整として、クラスのデストラクタでハンドラ配列のポインタを削除してメモリリークを防止します。

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


ハンドラのテスト

この例では、前述のテストファイル「LogifyTest.mq5」を使用します。目的は、それぞれ異なるログレベルで動作する2つのログハンドラを設定し、設定されたフィルターに基づいてログがどのように記録されるかを示すことです。

まず、異なる場所とレベルでログを記録する2つのハンドラを作成します。

  • コンソール:CLogifyHandlerConsoleのインスタンスで、DEBUGレベルのメッセージ、つまり最も詳細なものから重大なエラーまで、すべてのメッセージを記録するように設定します。
  • ファイル:CLogifyHandlerFileのインスタンスで、INFOレベル以上のメッセージのみを取得し、DEBUGメッセージは除外するように設定します。

以下はこれらのハンドラを設定するコードです。

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

ハンドラを設定した後、次のステップは、アプリケーションのすべてのログを管理する基底クラスであるCLogifyにこれらのハンドラを追加することです。

さらに、ログの表示形式を定義するフォーマッターも追加します。この例で使うフォーマッターは、ログを「時:分:秒, [ログレベル], メッセージ」というパターンで整形します。

ハンドラとフォーマッターを設定した後、異なるレベルのログメッセージを3つ出力します。以下にこのステップの完全なコードを示します。

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

上記のコードを実行すると、コンソールに次の出力が表示されます。

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

結果の理解

  • コンソールハンドラ(handler_console):このハンドラはDEBUGからERRORまでのすべてのメッセージをキャプチャしました。したがって、発行されたログごとに3つのエントリがコンソールに記録されました。
  • ファイルハンドラ(handler_file):こちらはINFOレベル以上のメッセージのみを記録するように設定されていました。そのため、DEBUGログは無視され、INFOとERRORメッセージのみが記録され、ログファイルには合計2つのエントリが保存されました。


結論

この記事を通じて、MQL5ログライブラリの構築において重要な一歩を踏み出しました。ハンドラの概念を理解し、ログメッセージを異なる宛先へ「導く」役割を果たす重要な存在であることを学びました。ハンドラがフォーマッターと連携し、一体的でモジュール化されたログ処理システムを形成する様子も確認しました。

実践では、将来のすべての実装の基盤となる抽象クラスとしてハンドラの基本構造を作成しました。また、初期ハンドラとしてConsoleDatabaseFileの3種類を開発しました。それぞれがコンソール、データベース、ファイルにログを出力する役割を担っています。現時点ではすべてPrint()関数でのシミュレーションですが、この堅牢な基盤をもとに、今後の記事で各クラスを拡張し、実用的な機能を持たせていくことが可能です。

テストを通してハンドラとライブラリの統合が確認でき、柔軟にハンドラを追加・利用する方法を示しました。この過程で、ハンドラがさまざまなログニーズに対応できるモジュール型コンポーネントとしての大きな可能性を持つことが明らかになりました。


この記事で使用したすべてのコードは以下に添付されています。ライブラリ内の各ファイルの説明を記載した表を以下に示します。

ファイル名
詳細
Experts/Logify/LogiftTest.mq5
ライブラリの機能をテストするファイル。実用的な例が含まれています。
Include/Logify/Formatter/LogifyFormatter.mqh
ログレコードのフォーマット、プレースホルダーを特定の値に置き換えるクラス
Include/Logify/Handlers/LogifyHandler.mqh
レベル設定やログ送信を含むログハンドラを管理するための基本クラス
Include/Logify/Handlers/LogifyHandlerConsole.mqh
フォーマットされたログをMetaTraderの端末コンソールに直接送信するログハンドラ
Include/Logify/Handlers/LogifyHandlerDatabase.mqh
フォーマットされたログをデータベースに送信するログハンドラ(現在は出力のみが含まれているが、すぐに実際のSQLiteデータベースに保存する予定)
Include/Logify/Handlers/LogifyHandlerFile.mqh
フォーマットされたログをファイルに送信するログハンドラ(現在は出力のみが含まれているが、すぐに実際のSQLiteデータベースに保存する予定)
Include/Logify/Logify.mqh
ログ管理、レベル、モデル、フォーマットの統合のためのコアクラス
Include/Logify/LogifyLevel.mqh
Logifyライブラリのログレベルを定義するファイル。詳細な制御が可能
Include/Logify/LogifyModel.mqh
レベル、メッセージ、タイムスタンプ、コンテキストなどの詳細を含むログレコードをモデル化する構造
次回の記事では、各ハンドラを完全に実装し、ログをファイルに保存する方法や、データベースへの格納、端末での特定の出力設定について詳しく解説していきます。


MetaQuotes Ltdにより英語から翻訳されました。
元の記事: https://www.mql5.com/en/articles/16866

添付されたファイル |
LogifyfPart3a.zip (11.96 KB)
流動性狩り取引戦略 流動性狩り取引戦略
流動性狩り(Liquidity Grab)取引戦略は、市場における機関投資家の行動を特定し、それを活用することを目指すSmart Money Concepts(SMC)の重要な要素です。これには、サポートゾーンやレジスタンスゾーンなどの流動性の高い領域をターゲットにすることが含まれます。市場がトレンドを再開する前に、大量の注文によって一時的な価格変動が引き起こされます。この記事では、流動性狩りの概念を詳しく説明し、MQL5による流動性狩り取引戦略エキスパートアドバイザー(EA)の開発プロセスの概要を紹介します。
トレンドフォロー型ボラティリティ予測のための隠れマルコフモデル トレンドフォロー型ボラティリティ予測のための隠れマルコフモデル
隠れマルコフモデル(HMM)は、観測可能な価格変動を分析することで、市場の潜在的な状態を特定する強力な統計手法です。取引においては、市場レジームの変化をモデル化・予測することで、ボラティリティの予測精度を高め、トレンドフォロー戦略の構築に役立ちます。本記事では、HMMをボラティリティのフィルターとして活用し、トレンドフォロー戦略を開発するための一連の手順を紹介します。
MQL5でSHA-256暗号化アルゴリズムをゼロから実装する MQL5でSHA-256暗号化アルゴリズムをゼロから実装する
これまで、DLLを使用せずに暗号通貨取引所との統合を構築することは長らく課題とされてきました。しかし、本ソリューションは、市場へ直接接続するための包括的なフレームワークを提供します。
プライスアクション分析ツールキットの開発(第7回):Signal Pulse EA プライスアクション分析ツールキットの開発(第7回):Signal Pulse EA
ボリンジャーバンドとストキャスティクスオシレーターを組み合わせたMQL5エキスパートアドバイザー(EA)「Signal Pulse」で、多時間枠分析の可能性を引き出しましょう。高精度で勝率の高い取引シグナルを提供します。この戦略の実装方法や、カスタム矢印を用いた売買シグナルの可視化手法を学び、実践的な活用を目指しましょう。複数の時間枠にわたる自動分析を通じて、トレード判断力を高めたいトレーダーに最適なツールです。