ロガーの作り方

ロガーとはログを書き出す仕組みのこと。
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("エラーなど");
    ・・
    ・・
}