Logging and Tracing in C++ Simplifiedページの翻訳版を記述します。 翻訳は、上記ページを「The翻訳インターネット V7.0LE」または「Excite 翻訳」で翻訳したものを、さらに一部簡単に修正したものです。いい日本語訳などあれば、ご指摘くださると幸いです。
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ステップがあります:
// 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;
}
date_time PRIORITY category_name : message
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
/*
* 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];
}
}
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];
}
}
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月