- PR -

log4jの使い方について

投稿者投稿内容
hiro
常連さん
会議室デビュー日: 2004/09/02
投稿数: 21
投稿日時: 2005-03-15 19:38
いつもお世話になっています。
現在log4jを利用してアプリケーションログをファイルに出力しているのですが、
1つのLoggerから複数のログファイルに出力する方法が思いつきません。
以下のようなロジックではマルチに動作した場合、最後に生成したLoggerの出力先にすべてのログが出力されてしまいます。

ロジック↓
------------------------------------------
log = Logger.getLogger(this.getClass());
((RollingFileAppender)log.getAppender("A2")).setFile(outdir);
((RollingFileAppender)log.getAppender("A2")).activateOptions();
log.info("LogTestThread コンストラクタ");
------------------------------------------

上記のsetFile()で出力先を変更しています。
log4j.propertiesにLoggerおよびAppenderを複数定義すれば、それぞれのファイルに出力できることは確認しています。
ログ出力先が増えるたびにlog4j.propertiesを編集したくないので、同一のLoggerから実施したいと思っています。
このようなことは、そもそもlog4jの仕様にあわないのでしょうか?
どなたか対応策をご存知であれば教えてください。
よろしくお願いします。
uk
ぬし
会議室デビュー日: 2003/05/20
投稿数: 1155
お住まい・勤務地: 東京都
投稿日時: 2005-03-15 20:10
なんとなく、いろいろな質問が混ざっているように思いますが、
まず複数の出力先に一つのロガーから出力したいのであれば、ロガーに対してアペンダを複数
指定すればできます。もし、プログラム内から出力先を追加したいのであれば、アペンダの
インスタンスを生成してロガーに対してaddAppenderをすればできます。

これで答えになっていますか?
hiro
常連さん
会議室デビュー日: 2004/09/02
投稿数: 21
投稿日時: 2005-03-15 20:40
早速の返信ありがとうございます。
質問内容が不明瞭で申し訳ございません。
早速ですが、以下のように実施した場合、

引用:

まず複数の出力先に一つのロガーから出力したいのであれば、ロガーに対してアペンダを複数
指定すればできます。もし、プログラム内から出力先を追加したいのであれば、アペンダの
インスタンスを生成してロガーに対してaddAppenderをすればできます。



アプリごとにログファイルは作成されるのですが、次のような問題があります。
・ログファイル1の内容
line 1:ログファイル1開始
line 2:処理1−1開始
line 3:処理1−1終了
line 4:処理1−2開始
line 5:処理1−2終了

・ログファイル2の内容
line 1:ログファイル2開始
line 2:処理2−1開始
line 3:処理2−1終了
line 4:処理1−2開始
line 5:処理1−2終了

このように「ログファイル1」の内容が、「ログファイル2」にも反映されてしまいます。
要件として、アプリケーションごとのログ出力を実現したいと思っているので、
addAppenderでは、難しいということになるでしょうか?
uk
ぬし
会議室デビュー日: 2003/05/20
投稿数: 1155
お住まい・勤務地: 東京都
投稿日時: 2005-03-15 20:46
「アプリごと」ということは複数のアプリケーションが動いている、と言うことだと思いますが、
どういう構成なのですか? それから、最終的に実現したいのは、

引用:

要件として、アプリケーションごとのログ出力を実現したいと思っているので、


これですか? 何をどのようにしたいのか、もう少し整理してください。
hiro
常連さん
会議室デビュー日: 2004/09/02
投稿数: 21
投稿日時: 2005-03-15 21:13
uk殿

お世話になっております。
実現したい要件は、
1.Loggerのインスタンス生成(取得?)を共通処理で実施する。
2.各アプリケーションは、共通処理にファイル名称を指示する。
3.各アプリケーションの実行時ログファイルが作成できる。

以上です。
この時、log4j.propertiesの内容を変更することなく実装可能な方法を検討しています。
よろしくお願いします。
uk
ぬし
会議室デビュー日: 2003/05/20
投稿数: 1155
お住まい・勤務地: 東京都
投稿日時: 2005-03-15 22:12
ですから、各アプリケーションはいったいどのように構成されているアプリケーションなんですか?
Webアプリケーション? それ以外のサーバアプリケーション? スタンドアロンのアプリケーション?

もしWebアプリケーションであれば、「共通クラス処理」のクラスとlog4jのライブラリを
各アプリケーションローカル(WEB-INF/lib、WEB-INF/classes)に配置すればいいのでは
ないですか?
hiro
常連さん
会議室デビュー日: 2004/09/02
投稿数: 21
投稿日時: 2005-03-16 10:06
uk殿
お世話になっております。
各アプリケーションの意味は、業務ロジック単位ということです。
(アプリケーションの使い方を間違っていました。すみません。。。)
用は、Webアプリケーションであれ、サーバまたはスタンドアロンアプリケーションであれ、
任意の業務処理でログ管理の共通処理に対し、ファイル名を指定して対象のLoggerを取得することを実現したいです。
イメージとしては以下のような感じです。

・業務処理(Logic1.java)
// ログ共通処理呼出
Logger log = LogManager.setupLog("Logic1");
log.info("処理1開始");
 :

・共通関数(LogManager.java)
Logger log = Logger.getLogger("DefaultLogger");
FileAppender fileapd = log.getAppender(apd).....
fileapd.setFile(outfile);
 :

・log4j.properties
#Logger設定
log4j.logger.DefaultLogger=debug,A1,A2
#"A1"Appender設定(コンソール)
 :
#"A2"Appender設定(ファイル)
 :

このときデフォルトのLogger設定にコンソールやファイル出力の設定(レイアウトやファイルサイズなど)をしておき、
任意のログファイルにも同様の設定を生かしたいです。
現状は、共通処理で任意のログファイル用にAppenderをインスタンスしデフォルトのLoggerにaddしているのですが、
この方法では、以前も書いたように最後に取得したLoggerにすべてのログが出力されてしまいます。
最後に取得したといってもLoggerのオブジェクトは同一であるので(DefaultLogger)仕方ないような気がしますが...
Appenderを生成するようにLoggerを生成することができれば可能なような気もしているのですが。。。
このような説明で理解していただけたでしょうか?
何かと説明に不備があり大変申し訳ございません。
よろしくお願いします。
hiro
常連さん
会議室デビュー日: 2004/09/02
投稿数: 21
投稿日時: 2005-03-16 13:42
自己スレです。

共通関数で以下のようにCategoryを新規作成することで実現できそうです。

・共通関数(LogManager.java)
--------------------------------------------------------------------------------
private static HashMap logger_map = null;
/**
* log4jのLogger獲得
*
* @param obj:呼出元オブジェクト
* @param logname:ログ名称
* @return 準備済みのLogger
*/
public static Logger setupLog(Object obj, String logname) {
try {
// Loggerキャッシュなし?
if( null==logger_map ) logger_map = new HashMap();
// 作成済みであればそれを返す
if( null!=logger_map.get(logname) ) return (Logger)logger_map.get(logname);

// CommonsのLog取得
Log log = LogFactory.getLog(obj.getClass());

// Log4Jを利用しているかチェック
if(log instanceof org.apache.commons.logging.impl.Log4JLogger){
//log.debug("Log4Jです log="+log);
try{
// DefaultのLogger取得
Logger nlogger = Logger.getLogger("DefaultLogger");
//log.debug("nlogger="+nlogger);

// デフォルトのAppenderを取得
// コンソール用
Appender A1 = nlogger.getAppender("A1");
// ファイル出力用
RollingFileAppender A2 = (RollingFileAppender) nlogger.getAppender("A2");
// 対象ファイル用のAppenderを新規作成
RollingFileAppender rfapd = new RollingFileAppender();
// デフォルトのAppenderオプション設定
rfapd.setMaximumFileSize(A2.getMaximumFileSize());
rfapd.setMaxBackupIndex(A2.getMaxBackupIndex());
rfapd.setAppend(A2.getAppend());
rfapd.setLayout(A2.getLayout());
// 出力先設定
rfapd.setFile(Param.getInstance().log_path + logname + ".log");
// オプションを有効化
rfapd.activateOptions();

// 対象Loggerを作成
Logger obj_logger = (Logger) Logger.getInstance(obj.getClass());
// ログ出力レベルを設定
obj_logger.setLevel(nlogger.getLevel());
// Appenderを追加
obj_logger.addAppender(A1);
obj_logger.addAppender(rfapd);
//log.info("setupLog: ログ出力先設定完了: "+Param.getInstance().log_path + logname + ".log");

// ヘッダを出力
String sep = System.getProperty("line.separator");
obj_logger.info(sep + sep + "<< ログ出力開始[" + Param.getInstance().log_path + logname + ".log" + "]>>");

// Loggerをキャッシュする
logger_map.put(logname,obj_logger);

// Log4JのLoggerをreturn(正常)
return obj_logger;

}catch(Exception ee){
System.out.println("エラー: ログが出力できません: log4j.propertiesがCLASSPATH上に見つかりません");
ee.printStackTrace();
}

}

} catch (Exception e) {
System.out.println("エラー: ログが出力できません: その他のエラー: "+e.toString());
e.printStackTrace();
}

//System.out.println("仮のLoggerを新規作成");
Logger logger = Logger.getLogger(obj.getClass());

return logger;
}
--------------------------------------------------------------------------------

LoggerはCategoryを継承しているので以上のような実現方法でも問題ないでしょうか?
またこの時、任意作成したLoggerをキャッシュして再利用するようにしているのですが、
log4jがスレッドセーフであるので共通関数で排他処理は実施していません。

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