- PR -

Log4jをラップしたクラスの作成

1
投稿者投稿内容
tottmo
会議室デビュー日: 2004/05/30
投稿数: 11
投稿日時: 2004-09-27 21:50
次の環境でアプリケーションを開発しております。
JDK 1.4
log4j 1.2.8
commons-logging

このアプリケーションでは
commons-loggingを使いlog4jからログ出力を行っているのですが、
ログをデータベースにも出力するという要件が発生した為
2つの出力を両方行うログクラスを自分で作成しました。

作成したログクラス Logger.java
public class Logger {
/** commons-logging */
private Log log = null;
private static Logger instance = null;
/** constructor */
private Logger(Class clazz) {
log = LogFactory.getLog(clazz);
}
public static Logger getLogger(Class clazz) {
if (instance == null) {
instance = new Logger(clazz);
}
return instance;
}
public fatal( String message ){
log.fatal(message);
//ログをデータベースに出力
・・・
}
・・・
}

Log4j設定ファイル log4j.properties
log4j.rootCategory=info,A1
log4j.appender.A1=org.apache.log4j.RollingFileAppender
log4j.appender.A1.File=D:\\test.log
log4j.appender.A1.layout=org.apache.log4j.PatternLayout
log4j.appender.A1.layout.ConversionPattern=%5p %d{yyyy/MM/dd-HH:mm:ss} [%F:%L] - %m %n

ログを出力したいクラス Test.java
public class Test {
private final Logger log = Logger.getLogger(Test.class);
public static void main(){
log.fatal("this is log message!!!")
・・・
}
}

このクラスを使うことによりログは出力されるのですが、
Log4jに出力されたログは以下のようになります。

FATAL 2004/09/27-18:55:03 [Logger.java:35] - this is log message!!!

ログを出力しているTest.javaが出力元としてログに出力して欲しいのですが、
(当然ですが)実際にcommons-loggingを使用しているLogger.javaがログ出力元なっています。
これをどうにかして Test.java をログ出力元として出力したいのですが。。。

ご存知の方がおられましたら、アドバイスよろしくお願いします。
javan
会議室デビュー日: 2003/03/03
投稿数: 18
投稿日時: 2004-09-27 22:17
commons-logging はあまり使ったことないのですが、
log4jをラップした場合のログ出力元はどうしてもorg.apache.log4j.Loggerの
メソッドを呼んだクラスになってしまいます。

これを解決するには、
1.org.apache.log4j.spi.LocationInfoというクラスを修正
2.自前のLocationInfoを作成し[Logger.java:35] の部分を自作し、
  出力レイアウトには[%F:%L] を指定しない。
のいずれかになると思います。

私は2の方法で対処しました。

org.apache.log4j.spi.LocationInfoが何を行っているかはソースを
参照してください。


[ メッセージ編集済み 編集者: javan 編集日時 2004-09-27 22:18 ]

[ メッセージ編集済み 編集者: javan 編集日時 2004-09-27 22:25 ]
le
会議室デビュー日: 2004/09/28
投稿数: 5
投稿日時: 2004-09-28 18:21
tottmoさん

データベースがjdbc接続可能ならば、ラッピングクラスを作成しなくとも
org.apache.log4j.RollingFileAppender
org.apache.log4j.jdbc.JDBCAppender
の2つのAppenderを設定し、出力先として指定すれば済む気がするのですが、
jdbc接続がサポートされていないデータベースへ出力するということでしょうか?

なお、log4jの設定については
http://www.okisoft.co.jp/esc/log4j/
に丁寧な説明があります。
tottmo
会議室デビュー日: 2004/05/30
投稿数: 11
投稿日時: 2004-09-28 22:39
javanさん、leさん 返信ありがとうございます。

>javanさん
私も2.でやってみようと思います。
org.apache.log4j.spi.LocationInfo
を一見しましたがなかなか敷居が高い感じがしました。(^_^;
がんばってみます。

>leさん
確かにおっしゃるとおりです。
はじめの文ではデータベースにただ書き込みたいがためのように書きましたが、(すみません)
実はベータベースへの出力は メッセージ以外に実行ユーザーや実行対象要素名などその他の属性も出力する必要があり、Log4JのJDBC出力をそのまま使う方法は採用しませんでした。
メッセージ以外の文字列をメッセージとは別のカラムに出力できればよいのですが…
le
会議室デビュー日: 2004/09/28
投稿数: 5
投稿日時: 2004-09-29 01:01
なるほどそういうことですか。
因みに私は、似たような用件があったときにはメッセージの先頭の固定長部分を、
ユーザー名や、その他必要な情報の編集部分として、

log.debug(util.str.StringUtil.FixedStr("user1" , "element") + "debugログ出力");

(ここで、util.str.StringUtil.FixedStr(String str1 , String str2)は固定長の
レイアウトを編集するクラスメソッドです。)
といった具合に編集して、
lox4j.xml 側で、
<param name="ConversionPattern" value="INSERT INTO JBOSS_LOG_TABLE
(LOG_DATE, LOG_TIME, PRIORITY, CLASS,METHOD, LINE, USER1, element1, MESSAGE)
VALUES
('%d{yyyy-MM-dd}', '%d{HH:mm:ss,SSS}', '%p', '%C', '%M', '%L', trim(substr('%m',1,10)), trim(substr('%m',11,50)), substr('%m',61));" />
といった具合に分解してやることで逃げておりました。
(SQLはpostgreSQLの場合の例です)
佐々木
大ベテラン
会議室デビュー日: 2003/03/30
投稿数: 121
投稿日時: 2004-09-29 01:02
引用:

メッセージ以外の文字列をメッセージとは別のカラムに出力できればよいのですが…


Log4JにはMDCという便利なヤツがあります。ひょっとしたら役に立つかもしれません。
ぜひ一度ご検討あれ。
わたびん
常連さん
会議室デビュー日: 2003/02/26
投稿数: 24
投稿日時: 2004-09-29 10:53
私も以前似たようなことを考えました。
そのときにパフォーマンスとか設計とか関係なしに
こうすればイメージした動きだなぁって思ったことがあります。


コード:
	static Logger logger;

	private MyLogger(Class clazz) {
		logger = Logger.getLogger(clazz);
	}

	public static MyLogger getLogger(Class clazz) {
		return new MyLogger(clazz);
	}
	
	public void debug(Object obj){
		logger.debug(obj);
	}

tottmo
会議室デビュー日: 2004/05/30
投稿数: 11
投稿日時: 2004-09-29 20:48
leさん、佐々木さん、わたびんさん 返信ありがとうございます。

MDCで実現できました。
ありがございます。しかも案外簡単にでした。

code:----------------
MDC.put("user","tottmo");

と書けば、%X{user}で"tottmo"がデータベースに出力されました。
commons-loggingを使用しているなかでMDCの部分だけLog4Jによった実装をすることに違和感がありますが、そこはプロジェクトの中で調整しきたいと思います。

leさん
ConversionPatternにtrimやsubstrが書けるんですね。勉強になりました。

わたびんさん
ちょっと良く分からないのですが、Loggerをstaticにすると[%F:%L]などで ラッピングクラスではなく、ログを出力するクラスの情報が得られるということでしょうか?
Loggerはもともとインスタンスがひとつの気がしますが…
1

スキルアップ/キャリアアップ(JOB@IT)