ロガーの作り方
ロガーとはログを書き出す仕組みのこと。
C++を使っているのであれば、多態を使って柔軟なロガーを作ることができる。
ロガーを作るには、まずロガークラスの基底を書き出す。
class logger{ public: virtual void print(const char* str)=0;//純粋仮想関数 public: virtaul ~logger(){}//基底のデストラクタはvirtualで定義(宣言でない)しなければならない。 };
以上のインターフェースクラスを継承して実装クラスを作ってやる。
たとえばテキストにログを書き出すクラスは以下のようになる。
class text_logger{ public: void print(const char* str){fprintf(fp,str);} public: text_logger(const char * filename){fp = fopen(filename,"wt");} ~text_logger(){if(fp)fclose(fp);} private: text_logger(const text_logger&); //コピー不可 tex_logger& operator=(const text_logger&);//コピー不可 FILE *fp; };
上記のようにインターフェースクラスloggerを派生していろいろな形でログをはきだせるようにしておく。
例
- 標準出力
- 内部のstringstreamをもって後で使用
- Window(MessageBox)に出力
- socketに出力
- etc...
さらに複数のロガーをまとめそれらに出力するクラスを作ってあげると便利。
class multi_logger{ public: void print(const char* str){ for(std::size_t i = 0;i<mv_.size();i++){mv_[i]->print(str);} } public: void add(logger* plg){mv_.push_back(plg);} ~multi_logger(){ for(std::size_t i = 0;i<mv_.size();i++){delete mv_[i];} } private: //デフォルトで作られるコピーメンバを使用できなくする。 //なぜなら、newで動的に生成されたオブジェクトの"ポインタ"を持っているため。 multi_logger(const multi_logger& rhs); //コピー不可 multi_logger& operator=(const multi_logger& rhs);//コピー不可 std::vector<logger*> mv_; };
ロガーというものはエラーや例外を出力するものであるから、オブジェクト指向で構造化した仕組みには必ずしも適合しない。このためどこからでも呼び出し可能な関数があると便利。
logger& get_logger(){//ヘッダに公開する必要はない。 static multi_logger mlogger;//実際に生成してやる。 return mlogger; } void set_logger(logger* plg){//ロガーをセットする。 get_logger().add(plg); } void print_log(const char *str, ...){//フォーマットつき出力 using namespace std; char buffer[1024];//staticでも良い。どちらにしても、マルチスレッドのときは排他を行わなければならないため。 va_list list; va_start( list, str ); vsnprintf(buffer,sizeof(buffer),str,list);//整形して va_end(list); get_logger().print(buffer);//出力 }
以上のようにしてやれば、アプリケーションのはじめでロガーの設定関数を呼び出すことで、いつでもログ出力することができる。
#include "logger.h"//上記のヘッダ int main(){ set_logger(new text_logger("out.txt"));//out.txtにログを出力 set_logger(new html_logger("out.html"));//out.htmlにもログを出力 ・・ ・・ print_log("エラーなど"); ・・ ・・ }