work > C/C++ > Logging and Tracing in C++ Simplified(翻訳)

Logging and Tracing in C++ Simplifiedページの翻訳版を記述します。 翻訳は、上記ページを「The翻訳インターネット V7.0LE」または「Excite 翻訳」で翻訳したものを、さらに一部簡単に修正したものです。いい日本語訳などあれば、ご指摘くださると幸いです。

簡略化された C++ のロギングとトレース

By Mo Budlong, August 2001
この情報およびコードの例は好意としてSUNより提供されており、「そのまま」であり、SUNは特定の目的、または非侵害のための適応、商用のいかなる保障を含め、それに関係する全ての保証を放棄します。

概要

トレースとロギングは、デバッグの共通の支援であり、デバッグのための重要なパスです。オープンソースlog4CppパッケージはC++アプリケーションでのロギングおよびトレースのセットアップの過程を簡略化します。log4Cppについてのドキュメンテーションは、log4cppオブジェクト一式の使用についてのいくつかの簡単な例が抜けています、そして、この記事はlog4Cppの小さなバグの単純な解決方はもちろん例および説明も提供します。

ロギングとトレース

あなたはトレースするべきです。。 わかりますか?あなたは確かに行います、しかし少しバックアップします。もし、あなたが500行以上のアプリケーションを書くか、アプリケーションがデーモンかサービスとして走るか、またはあなたが多くのデバッグの頭痛から自分自身を救いたいのであれば、トレースするべきです。つまり、オリジナルのステートメントを一周できます。あなたは、トレースするべきです。
ああ、しかし、C++プログラムはどのようにそのトレースを行いますか?
手続き型言語(すなわちC)のランクを通って近づいて来たならば、恐らく老練でしょう:

#ifdef DEBUG
	fprintf(trace_file,"Here is a useless trace messagen");
#endif


しかし、オブジェクト指向言語は、うーむ・・・オブジェクトは適応させました。トレースファイルに無作為のメッセージを吐くのは全く十分上品であるというわけではありません、まさしくobjectilatedされて、objectiviedされなかった平野は言うまでもなく… 何でも。
あなたは、トレースしロギングするクラスを必要とします。
いいえ、いいえ、既に世話をされるので、それはあなたのためにここで書かれていません。 Ceki Gulcuは、log4jという名のJavaでロギングしトレースするオブジェクトの強力なセットを作成しました。 Bastiaan Bakkerは、同じセットのオブジェクトの大部分をC++に移植し、それをlog4cppと呼びます。それらは、両方ともオープンソースパッケージであり、sourceforge.net および他のオープンソースリポジトリで自由に利用可能です。
ハンマーとのみを使用して、コードが最初に著されて以来、ロギングとトレースをコードへ挿入することは周囲にありました。技術は低次技術です。しかし、それも非常に有効です。それが正確に行われる場合、ソフトウェアを監査する基礎をさらに形成し、実効誤差を記録するツールになることができます。
ロギングはプログラムを遅くすることができます。また、log4jとlog4cppの著者は緩慢を引き起こすコードの部分をぐいとひねるために非常に熱心に働きました。
マトリクスはトレースメッセージのボリュームにおける広い矛盾のために、引用するのが難しい。片端では、あなたは厳しいメッセージしかたどることができません。

#ifdef DEBUG
	trace("Captain, the dilithium crystals are meltingn");
#endif


他方では、コードのほとんどすべてのラインをトレースすることができます。
トレースのクラスに重要なことは、アプリケーションにおける単なる存在が過度にアプリケーションを遅くするべきでないということです。log4cppパッケージはこの点に関して優れた働きをします。
log4cppがどこで落ちるかは、ドキュメンテーションです。それぞれの個々のクラスは徹底的にドキュメント化されますが、log4cppを使用するためにどうオブジェクトを結びつけるかが少ししかもしくは何もありません。あなたがlog4jについてのドキュメンテーションを追い詰めれば、それは、log4jの使用へはじまりという1つの説となります。
したがって、ロギングとトレースに興味を持っていて、優れて、自由に利用可能なトレースツールを使用したい場合は、読み続けてでください。
log4cppは3つの主なコンポーネントを持っています: カテゴリー、付加およびレイアウト。
レイアウトクラスは、出力メッセージがどのように見るかコントロールします。望む任意のスタイルの出力メッセージを指定するためにLayoutから自分のクラスを引き出してもよい。log4Cppは、2つのレイアウトクラス、SimpleLayoutおよびBasicLayoutがあります。
付加クラスはトレースメッセージをあるデバイスに書きます。メッセージはレイアウトオブジェクトによってフォーマットされています。log4Cppは標準出力、名前付きのファイル、ストリングバッファーに「追加する」クラスがあります。Appenderクラスは、Layoutのクラスと共に密接に働いています、また、もう一度、ソケット、シェアード・メモリー・バッファーあるいはある種の遅れた書き込みデバイスに記録したければ、自分のappenderクラスを引き出してもよい。log4Cppは3の有用なappendersがあります: FileAppender、OstreamAppenderおよびStringQueueAppender。
カテゴリーのクラスは実際のロギングを行います。カテゴリーの2つの主要部分はそのappendersとその優先度です。優先度は、特定のクラスがどのメッセージを記録することができるかコントロールします。カテゴリーオブジェクトが作成される場合、それは標準出力の標準appenderと優先度無しで動き始めます。ログ出力先リストに、1つもしくは複数のappendersを追加することができます。瞬間に、より多くappendersが存在するでしょう。カテゴリーの優先度は、「logginess」の順序あるいは各メッセージの重要レベルの昇順に、NOTSET、DEBUG、INFO、NOTICE、WARN、ERROR、CRIT、ALERTあるいはFATAL/EMERGと設定することができます。FATALとEMERGは重要な同じ最高水準をもつ2つの名前です。各メッセージはカテゴリーオブジェクトに記録されます。カテゴリーオブジェクトは優先レベルを持っています。メッセージはそれ自身、ログにゆっくり進むようにさらに優先レベルを持っています。メッセージの優先度がカテゴリの優先度より大きな場合、あるいは等しい場合、その時、ロギングは起こります、さもなければ、メッセージが無視されます。カテゴリー優先度は下記のように並べられます:

NOTSET < DEBUG < INFO < NOTICE < WARN < ERROR < CRIT < ALERT < FATAL = EMERG


FATALとEMERGは等しく、最高水準です。NOTSETが最も低く、カテゴリーオブジェクトがNOTSET優先度に託される場合、それはどんなメッセージも受理し記録するでしょう。
NOTSETを除いて、これらの優先度のいずれもメッセージに与えることができます。
したがって、もしカテゴリーがWARNレベルに設定されたならば、DEBUGレベル、INFOおよびNOTICEを備えたメッセージは記録されないでしょう。 WARN、ERROR、CRIT、ALERT、FATALあるいはEMERGにセットされたメッセージが記録されるでしょう。
ルート・ノードを備えた木に配置されたカテゴリーは、トップのカテゴリーレベルになります。これは、あなたが層(カテゴリー)へトレースしながら、中断することを可能にします。子供カテゴリーは、最初に作成された時、それらの親カテゴリーの優先度を継承します。実際上、これはあまり有用ではありません。しかし、完全にはlog4Cppを訓練していません。
Appendersはカテゴリーオブジェクトに関する収集として蓄積します。 appenderがカテゴリーに加えられるとき、デフォルトの振る舞いはメッセージの記録のための、記録先リストに追加されるapenderのことである。それは、標準出力に反映させるのと同様に、同時に2ファイルへのログ/トレースをすることが可能でしょう。
実際上、あなたはめったに一度に1つを越える場所へ記録したいとは思わない、また、望む単一の目的地は、ほとんどが標準出力以外です。log4Cppは、additivityフラグを使うことで可能にします。もし、additivityプロパティが偽って設定されれば、そのとき、新しいappenderがカテゴリーオブジェクトに付けられる場合、それは目的地リストに加えられません。代わりに、それは、そのカテゴリーオブジェクト上のappendersの現在のリストを置き換えます。
このすべてがどのように結びつくでしょうか?
カテゴリークラスは1つの総合的な静的なルートカテゴリーオブジェクト(ルートと呼ばれた)を作成します。そのアプリケーションは、この1つの静的の親から子供カテゴリーのインスタンスを作成することができます。
ここに、log4Cppを使用する簡単な例があります。
もしあなたが標準出力に送られた単純なレイアウトの基礎的なロギングのセットアップを使用したくなければ、log4Cppログの使用に向けての最初の6ステップがあります:

  1. appenderオブジェクト生成。
  2. レイアウトオブジェクト生成。
  3. appenderにレイアウトオブジェクトを付与します。
  4. 静的な関数log4cpp::Category::getInstance("name")を呼ぶことでカテゴリーオブジェクト生成。
  5. 追加appender(デフォルト標準出力のappenderに加えて)としてカテゴリーにappenderオブジェクトを付与する、もしくは初めにAdditivityをfalseに設定し、そのカテゴリーのための唯一のappenderとしてappenderのインストールをします。
  6. もしあなたが単にすべてを記録したくなければ、カテゴリーのための優先度を設定してください。
    // TestLog4CPP.cpp : A small exerciser for log4cpp
    
    #include	"Category.hh"
    #include	"FileAppender.hh"
    #include	"BasicLayout.hh"
    
    int main(int argc, char* argv[])
    {
    
    // 1 instantiate an appender object that // will append to a log file log4cpp::Appender* app = new log4cpp::FileAppender("FileAppender", "/logs/testlog4cpp.log"); // 2. Instantiate a layout object // Two layouts come already available in log4cpp // unless you create your own. // BasicLayout includes a time stamp log4cpp::Layout* layout = new log4cpp::BasicLayout(); // 3. attach the layout object to the // appender object app->setLayout(layout); // 4. Instantiate the category object // you may extract the root category, but it is // usually more practical to directly instance // a child category log4cpp::Category main_cat = log4cpp::Category::getInstance("main_cat"); // 5. Step 1 // an Appender when added to a category becomes // an additional output destination unless // Additivity is set to false when it is false, // the appender added to the category replaces // all previously existing appenders main_cat.setAdditivity(false); // 5. Step 2 // this appender becomes the only one main_cat.setAppender(app); // 6. Set up the priority for the category // and is given INFO priority // attempts to log DEBUG messages will fail main_cat.setPriority(log4cpp::Priority::INFO); // so we log some examples main_cat.info("This is some info"); main_cat.debug("This debug message will fail to write"); main_cat.alert("All hands abandon ship"); // you can log by using a log() method with // a priority main_cat.log(log4cpp::Priority::WARN, "This will be a logged warning"); // gives you some programmatic control over // priority levels log4cpp::Priority::PriorityLevel priority; bool this_is_critical = true; if(this_is_critical) priority = log4cpp::Priority::CRIT; else priority = log4cpp::Priority::DEBUG; // this would not be logged if priority // == DEBUG, because the category priority is // set to INFO main_cat.log(priority,"Importance depends on context"); // You may also log by using stream style // operations on main_cat.critStream() << "This will show up << as " << 1 << " critical message" << log4cpp::CategoryStream::ENDLINE; main_cat.emergStream() << "This will show up as " << 1 << " emergency message" << log4cpp::CategoryStream::ENDLINE; // Stream operations can be used directly // with the main object, but are // preceded by the severity level main_cat << log4cpp::Priority::ERROR << "And this will be an error" << log4cpp::CategoryStream::ENDLINE; // This illustrates a small bug in version // 2.5 of log4cpp main_cat.debug("debug"); // this is correctly // skipped main_cat.info("info"); main_cat.notice("notice"); main_cat.warn("warn"); main_cat.error("error"); main_cat.crit("crit"); // this prints ALERT // main_cat : crit main_cat.alert("alert"); // this prints PANIC // main_cat : alert main_cat.emerg("emerg"); // this prints UNKOWN // main_cat : emerg main_cat.debug("Shutting down"); // this will // be skipped // clean up and flush all appenders log4cpp::Category::shutdown(); return 0;
    }
    

    この例におけるコードの最終セクションは、log4cppの中のバグを例証します。 BasicLayout()では、メッセージは次のように記録されます:
    date_time PRIORITY category_name : message
    

    次のリストはこのプログラムからの出力の例です。crit()メソッドが優先レベルとしてALERTを出力し、alert()メソッドが優先レベルとしてPANICを出力する、また、emerg()が優先レベルとしてUNKNOWNを出力することに注意してください。
    995871335 INFO main_cat : This is some info
    995871335 PANIC main_cat : All hands abandon ship
    995871335 WARN main_cat : This will be a logged warning
    995871335 ALERT main_cat : Importance depends on context
    995871335 ALERT main_cat : This will show up as 1 
    		critical message
    995871335 UNKOWN main_cat : This will show up as 1 
    		emergency message
    995871335 ERROR main_cat : And this will be an error
    995871335 INFO main_cat : info
    995871335 NOTICE main_cat : notice
    995871335 WARN main_cat : warn
    995871335 ERROR main_cat : error
    995871335 ALERT main_cat : crit
    995871335 PANIC main_cat : alert
    995871335 UNKOWN main_cat : emerg
    

    恐らく最後の最後、オープンソースの美に行き着きます。バグは見つかりましたか?ただ進んで、それを修正してください。
    次のリストは、log4cppの十分な分配の一部である、Priority.cppファイルのコピーです。
    優先度の名前は静的な配列から作成され、インデックスは優先度番号に基づいて作成されます。
    /*
     * Priority.cpp
     *
     * Copyright 2000, LifeLine Networks BV 
     * (www.lifeline.nl). All rights reserved. 
     * Copyright 2000, Bastiaan Bakker. All rights reserved.
     * See the COPYING file for the terms of usage and 
     * distribution.
     */
    
    #include "Portability.hh"
    #include "Priority.hh"
    
    namespace log4cpp 
    {
    
    
    const std::string& Priority::getPriorityName(int priority) throw() { static std::string names[9] = { "PANIC", "ALERT", "ERROR", "WARN", "NOTICE", "INFO", "DEBUG", "NOTSET", "UNKOWN" }; priority++; priority /= 100; return *1 ? names[8] : names[priority - 1]; }
    }
    

    しかし、優先順位番号は、この機能がPriority.hhからの抜粋で以下に示すように予期するより、わずかに異なります。
    typedef enum {
    
    EMERG = 0, FATAL = 0, ALERT = 100, CRIT = 200, ERROR = 300, WARN = 400, NOTICE = 500, INFO = 600, DEBUG = 700, NOTSET = 800
    } PriorityLevel;
    

    したがって、修正は以下のように(変更が強調されます)配列とコードを調節することです。
    /*
     * Priority.cpp
     *
     * Copyright 2000, LifeLine Networks BV (www.lifeline.nl). 
     * All rights reserved.
     * Copyright 2000, Bastiaan Bakker. All rights reserved.
     *
     * See the COPYING file for the terms of usage and 
     * distribution.
     */
    
    #include "Portability.hh"
    #include "Priority.hh"
    
    namespace log4cpp 
    {
    
    
    const std::string& Priority::getPriorityName(int priority) throw() { static std::string names[10] = { "PANIC", "ALERT", "CRITICAL", "ERROR", "WARN", "NOTICE", "INFO", "DEBUG", "NOTSET", "UNKOWN" }; priority++; priority /= 100; return *2 ? names[9] : names[priority]; }
    }
    

    log4cppは非常に柔軟で親しみがあります。あなたが望むすべての方法および多数の出力先へのログをフォーマットするためにそれを修正することができます。それは多くのプロジェクトで、あなたから多くの開発時間を省くでしょう。Bakker氏に敬意を評します。
    log4Cppは、まだまだ欠けている1つの重大な断片です。Javaバージョンlog4jは、コードを修正する必要なしに、プログラムの「logginess」を変更することができるようなXMLまたは他の設定ファイルから構成をとるConfiguratorクラスを含んでいました。これはlog4cppへのダイナマイトな追加になるでしょう。
    これは何か考えをあなたに与えますか?

リソース

sourceforge.netはオープンソースソフトウェアのための素晴らしいリソースです。 log4cppと log4jと同様に、あなたはPerlのためのlog4p、Pythonのための別の log4p、および log4dなど、デルフォイのための同様の口ギング機能を作成するための進行中のプロジェクトを見つけるでしょう。
log4jの使用への入門、およびlog4cppに対して適用性を持っている他のドキュメンテーションは、The JakartaProjectにあります。

著者に関して

Mo BudlongはKing Computer Servicesの社長で、15年以上の間UNIX(R) boxesの上のユーティリィティ、アプリケーションおよびクライアントサーバソリューションを作成しています。彼は、アセンブリ言語からXMLにまで及び、それらを対象に多数の本および記事を出版しました。彼はウェブ・ベースのUNIX 101カラムの著者で、すぐにUNIX basicsについての本を出版しています。さらに、Moは、ギター、バスおよびキーボードを演奏し、他のいくつかの楽器をいじる音楽家です。彼は、妻、娘および猫と南カリフォルニアで暮らします。
2001年8月

名前:
コメント:
最終更新:2009年04月20日 16:56

*1 priority < 1) || (priority > 8

*2 priority < 0) || (priority > 8