« 2009年2月 | トップページ

log4jの設定について。

Java/log4j

log4jの設定について。

log4jの設定ファイル(log4j.xmlとlog4j.propertiesがあるけどここではpropertiesについて。xmlについては適宜読み替えて下さい)の設定について。

log4jの基本的な使い方やpropertiesの基本的な書き方は他にちゃんと詳しくてこのブログのように胡散臭くないサイトさんやブログがあるのでそちらに譲るとして。今回は私の備忘録です。
今まであんまり真面目に勉強してこなくて、そのツケが回りに回って調査に一日かかった…orz

log4jの設定は、
・Category(Logger)
・Appender
・Layout
の3つからなる。
■Appenderは、出力情報の設定。
出力ログのファイルパスや、追加で出力するとか上書きするとかの設定や、日次でファイル変えていくだのそういった辺りを設定。
■Layoutは、Appenderにくっついていて、出力するログのレイアウト(日時出してログ出力クラス名出して、とかの出力される1行ログの書式)。
Appenderの下にいるのに、設定はこの3つからなる!てAppenderと肩並べてるのはAppender的に思うところもあるだろうなぁ。
■Categoryは、Javaのソースに記述されるログの設定名みたいなもの、と理解。
log4j.category.FOR_DEBUG=DEBUG, a1,a2
と書くと、"FOR_DEBUG"という名前のカテゴリのログレベルはDEBUGで、Appenderにはa1とa2を指定、という意味。
Appenderは複数指定可能。a1がコンソール出力、a2がファイル出力、という感じで区別すると良い。
Javaの方では、
Logger debugLogger = Logger.getLogger("FOR_DEBUG");
(なんかソース)
debugLogger.debug("でばっぐ");
という風に書く。

で、CategoryとLoggerの関係については分かったような情報が曖昧なような。
一応、LoggerはCategoryを継承しているので、実体としてはまぁ違いはないよ、と。
但し、Categoryは非推奨化していて、その内消え去る運命だということで、log4jのバージョンによって、CategoryとLoggerを使い分けないといけないとのことです。
この辺りから若干情報が怪しくなってくる(^^;)
ソースが教えてgooしかないとかそんなレベルです。まぁこの辺りはあまりまじめに調べてないのですすみません。。。
今回のアプリの設定ファイルではrootLogger宣言して、log4j.categoryを設定して、JavaではLoggerクラスを使ってる。この入り乱れてるのが普通なのか統一すべきなのかの判断が付かないのですが、今回は元が私が作ったアプリでないので、あまり大きな変更勝手に加えると怒られるので放置してます。
ネットって解決策は見つかることが多いけど、それが「普通」のやり方なのかを判断するのは難しいですヨネ。

話が逸れましたが。

で、category設定で少し悩んだのが、log4j.category[logger].xxxと記述するところの xxx 部分に、パッケージを書くんだ、と書いているサイトが多かったこと。
例えば、log4j.category[logger].com.foo.bar とか。すんごい適当ですが。
まず、誤解しそうになりますが、「パッケージを書く」というのは「書かなければいけない」ではないということ。
前述した例のように、適当な名前を付けてもOKです。
むしろこっちの方が分かりやすいような気も私はするんだけど…うーん。
利点は、パッケージのように、"."で繋げて書くと、設定の継承が使えるトコロ。
log4j.category[logger].com.foo.barは、log4j.category[logger].com.foo の設定を継承できます。
後は、例えばSQLを発行しているような共通部分のクラスのパッケージ名を書いてやって、レベルをDEBUGにしておくと、SQLがDEBUGログに出力されるとか。
で、Logger.getLogger()については、
・Logger.getLogger(String)
・Logger.getLogger(String, LoggerFactory)
の他に、
・Logger.getLogger(Class)
をというコンストラクタがあって、中でクラス名を取ってくれているのです。
具体的には Logger.getLogger(this.class); とか書いてやればOK。
これのお陰で、「パッケージを記述する」ってのが簡単に使えている、という背景もあるんだろうけれど。

後書いておきたいのが、ルートロガーとその他のカテゴリ(ロガー)の関係。
というか、ルートロガーに何が出力されるのかがもう分かんなくて分かんなくて。
(……でも書いてる内容間違ってるって!って場合は是非教えて頂ければ幸いです。)

まずカテゴリで設定されているログを、アプリログ、それ以外のクラス(例えばPreparedStatement.classとか)から出力されているログを、共通ログと定義します(名前が適切でないなどの突っ込みはご容赦下さい。。。)。

で、以下ルートロガーと各カテゴリとの関係。
(やっぱりルートカテゴリ-各カテゴリ、ルートロガー-各ロガー、って組み合わせにしないといけないような気がするなぁ…)

(1)アプリログはルートロガーで設定されているログレベルに関わらず、すべて出力される。但し、対象ログが各カテゴリで設定されているログレベルに満たなくて、各アプリログに出力されない場合はルートログにも出力されない。
(2)共通ログは、ルートロガーのログレベル以上の場合だけ出力される。
(3)log4j.properties に設定されていないカテゴリ名で出力されるログ
 例:Logger.getLogger("UNKNOWN");
 このUNKNOWNがlog4j.propertiesに設定されていない
…については、ルートロガーのログレベル以上の場合だけ出力される。

当然ながら、アプリログについては、各カテゴリで設定されているログレベル以上のログしか各Appenderには出力されない。

なので、開発環境→本番環境などで、ログレベル云々ではなく該当カテゴリに含まれるログすべてを出力したくない場合、そのカテゴリをコメントアウトしたり削除したりするのではなく、カテゴリに設定されているログレベルを上げることで対応すること。
そうでないと、出力先がないのでルートログに出力しておく、という判断になってすべてのログがルートログにでることになる(前述の通り、ルートロガーのログレベルにも依るけど)
まぁルートロガーを空にしておくと何も出ないんだけど。。。多分、出そうとして文字列の生成まではいくので、パフォーマンスに影響が出るような気がします。
ちゃんと調べてなくてアレですが。

まぁ、結論としては
log4j.category.FOR_DEBUG=DEBUG,a1
などの場合、
log4j.category.FOR_DEBUG=FATAL,a1
などにしてやると良い、ということです。なんか気持ちは悪いけども…

まとまりないですが、備忘録。
間違っていたらまた修正しにきます~

| | コメント (0) | トラックバック (0)

selectall_arrayref の使い方

perl/DBI

Perl-DBI…サイトを色々見ててもかゆい所に手が届きづらい感じなのはなんなんだろうか…orz

selectall_arrayref の使い方ですっごい躓いたので備忘録。
selectall_arrayref の引数は以下。
1:SQL文字列
2:取得形式
3:バインド変数

ここで躓いたのは2なんですが……

各サイトでよっく見かけた記述が「\%attr」…つったってだからそのアトリビュートに何入れるんだっつー話ですよコレが。
分かんねぇよ!……みんな分かってんのかな……まぁAPIちゃんと読めよという話なんでしょうか。うーん。

http://blog.scrapcode.net/article/598613.html
↑こちらのブログでようやくとっかかりを見つけました。これも間違ってないんですが不十分…
こちらでは、「{Columns => {}}」を渡せと書いてあります。空のハッシュです。これに詰めて配列にして返してねってことみたいです。

で、最終的にたどり着いたのがこちら。
http://yanor.net/wiki/index.php?Perl-DBI%2FSELECT

目から鱗がボロボロボロボ。ホントに有り難うございました。
パターンとしては以下。
・未指定 :配列の配列(※バインド変数有りの時は指定出来ない気がします。未確認)
・{Slice=>[]} :配列の配列
・{Slice=>{}} :ハッシュの配列
・{Columns=>{}} :ハッシュの配列
・{Slice=>[0, 1]} :配列の配列(1カラムめと2カラムめのみ)
・{Columns=>[1, 2]} :配列の配列(1カラムめと2カラムめのみ)(※Columnsだと1カラムめのインデックスが1になる)
・{Columns=>{id=>undef, name=>undef}} :ハッシュの配列(id列とname列のみ)

[ ] と書くと配列で、{ } と書くとハッシュで取得。
Slice と Columns では、配列のインデックスが違う、という感じ。

ソース例:
my $sql   = "SELECT ID, NAME FROM M_MEMBER WHERE SEX = ? AND AGE < ?";
my @param = ('MALE', 30);

# SQL実行(配列の配列のリファレンスを取得)
$rRows    = $$myDbh -> selectall_arrayref($sql, {Slice => []}, @param);

my @rows = @$rRows;  # @rows は配列の配列

# このあたりにfor文入れるハズ
my $rRow = $rows[0]; # $rRow は1件めの配列のリファレンス
my @row  = @$rRow;   # @row  は1件めの配列
print "$row[0]<BR>";

私はあんまり使わない気がするけど、selectall_hashref もちょっと面倒な書き方でした。上のサイトさん消えないと良いなあ…(^^;)

| | コメント (0) | トラックバック (0)

« 2009年2月 | トップページ