Show page source of NDC #80661

[[PageNavi(NavigationList)]]

=== NDCとは ===
{{{ html
<span style="float:right">
}}}

{{{ GoogleAdsense
<script type="text/javascript"><!--
google_ad_client = "ca-pub-0702888637712330";
/* 20120131 */
google_ad_slot = "8641490082";
google_ad_width = 300;
google_ad_height = 250;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>
}}}

{{{ html
</span>
}}}


NDCはnested diagnostic contextsの略で、日本語にすると「ネスト化診断コンテキスト」となります。

どういう物かを説明するより、どんなときに、何のために使うのかを説明した方が分かりやすいと思いますから、
その方針で説明してきます。

どんなときに:
 主に、Tomcatのようなサーバサイドのプログラムで、スレッドをプールし、使いまわす。[[BR]]
 クライアントから要求が来たらプールしていたスレッドを使い、クライアントからの要求を処理する。[[BR]]
 ※もちろん、クライアントからの要求は複数同時に来ることがあるし、サーバはそれらを同時に処理します。

何のために使うのか:
 ログを出力するときに、どのクライアントからの要求だったのかが分かるようにしたい。

ログにスレッドIDやスレッド名を出力すれば?
 これらではダメなんです。[[BR]]
 スレッドIDはプログラムを実行するたびに変わるので、訳が分からなくなります。[[BR]]
 スレッド名は、この例ではスレッドをプールしていて、使いまわしているのでダメなんです。

そこでNDCを使います。
 クライアントから要求が来たら、[http://log4cpp-jp.sourceforge.jp/api/classlog4cpp_1_1NDC.html#ad4f07aa423a2855ce00f6d7642ec86be NDC.push]を呼んで、クライアントのIDや名前を入れてあげれば良いです。処理が終わったら、[http://log4cpp-jp.sourceforge.jp/api/classlog4cpp_1_1NDC.html#ab0d6de25209c63a51889eba89dd6181d NDC.clear]を呼べば良いです。[[BR]]
 ちなみに、[http://log4cpp-jp.sourceforge.jp/api/classlog4cpp_1_1NDC.html#ad4f07aa423a2855ce00f6d7642ec86be NDC.push]や[http://log4cpp-jp.sourceforge.jp/api/classlog4cpp_1_1NDC.html#ab0d6de25209c63a51889eba89dd6181d NDC.clear]はstaticメンバ関数ですが、データはグローバル領域に保持されるのではなく、
 スレッド固有のデータ([http://ja.wikipedia.org/wiki/%E3%82%B9%E3%83%AC%E3%83%83%E3%83%89%E5%B1%80%E6%89%80%E8%A8%98%E6%86%B6 TLS:Thread local storage])に保持されるものです。
 なので、これらのstaticメンバ関数を呼んでも他のスレッドのNDCには影響しません。

==== サンプル ====
log4cppの中にサンプルがありますので、そのソースと、それを実行した結果を以下に示します。[[BR]]
ソース(tests/testNDC.cpp):
{{{ code cpp
#include <iostream>
#include "log4cpp/NDC.hh"

using namespace log4cpp;

int main(int argc, char** argv) {
    std::cout << "1. empty NDC: " << NDC::get() << std::endl;

    NDC::push("context1");
    std::cout << "2. push context1: " << NDC::get() << std::endl;
    
    NDC::push("context2");
    std::cout << "3. push context2: " << NDC::get() << std::endl;
    NDC::push("context3");
    std::cout << "4. push context3: " << NDC::get() << std::endl;
    std::cout << "5. get depth: " << NDC::getDepth() << std::endl;

    std::cout << "6. pop: " << NDC::pop() << std::endl;

    NDC::clear();
    std::cout << "7. clear: " << NDC::get() << std::endl;

    return 0;
}
}}}

実行結果:
{{{
1. empty NDC: 
2. push context1: context1
3. push context2: context1 context2
4. push context3: context1 context2 context3
5. get depth: 3
6. pop: context3
7. clear:
}}}

==== 参考資料 ====
APIドキュメント内でのNDCの説明
 http://log4cpp-jp.sourceforge.jp/api/classlog4cpp_1_1NDC.html

Log4J徹底解説~使い方(1)
 http://www.nurs.or.jp/~sug/soft/log4j/log4j2.htm
 
Log4j Q&Aの中の「Q3:特定のクライアントのログの追跡を行うには?」
 http://www.oki-osk.jp/esc/log4j/web/A3.html

[[PageNavi(NavigationList)]]