- PR -

Windows上でlog4jを使用した所UTF-8で出力されない

投稿者投稿内容
takamaro
大ベテラン
会議室デビュー日: 2004/10/12
投稿数: 100
投稿日時: 2004-11-30 07:20
申し訳無い、オーバーライドするのはsetFile()じゃなくてsetQWForFiles()の方です。
お詫びと言ってはなんですが、簡単な動作確認したものを載せておきます。

コード:

import java.io.IOException;
import java.io.Writer;

import org.apache.log4j.RollingFileAppender;
import org.apache.log4j.helpers.CountingQuietWriter;
import org.apache.log4j.spi.LoggingEvent;
import org.apache.log4j.Layout;

public class I18nRollingFileAppender extends RollingFileAppender {
	public I18nRollingFileAppender() {
		super();
	}
	public I18nRollingFileAppender(Layout layout, String filename, 
		boolean append, String encoding) throws IOException {
		this.encoding = encoding;
		this.layout = layout;
		this.setFile(filename, append, false, bufferSize);
	}
	public I18nRollingFileAppender(Layout layout, String filename,
				String encoding)throws IOException {
		this.encoding = encoding;
		this.layout = layout;
		this.setFile(filename, fileAppend, true, bufferSize);
	}
	protected void setQWForFiles(Writer writer) {
		String enc;
		if((enc = getEncoding()) == null ) {
			enc = System.getProperty("file.encoding");
		}
		qw = new I18nCountingQuietWriter(writer, errorHandler, enc);
	}
	protected void subAppend(LoggingEvent event) {
		qw.write(layout.format(event));
		StringBuffer buff = new StringBuffer();
		if(layout.ignoresThrowable()) {
			String[] s = event.getThrowableStrRep();
			if (s != null) {
				int len = s.length;
				for(int i = 0; i < len; i++) {
					buff.append(s[i]);
					buff.append(Layout.LINE_SEP);
				}
			}
		}
		long filesize = ((CountingQuietWriter) qw).getCount();
		
		if((fileName != null) && (filesize >= maxFileSize)){
			rollOver();
		}
		qw.write(buff.toString());
		
		if(immediateFlush) {
			qw.flush();
		}
	}
}



コード:

import java.io.Writer;
import java.io.IOException;

import org.apache.log4j.helpers.CountingQuietWriter;
import org.apache.log4j.spi.ErrorHandler;
import org.apache.log4j.spi.ErrorCode;

public class I18nCountingQuietWriter extends CountingQuietWriter {
	
	protected String encoding;
	
	public I18nCountingQuietWriter(Writer writer, ErrorHandler eh, String encoding) {
		super(writer, eh);
		this.encoding = encoding;
	}
	public void write(String string) {
		try {
			count += string.getBytes(encoding).length;
			out.write(string);
		}
		catch(IOException e) {
			errorHandler.error("Write failure.", e, ErrorCode.WRITE_FAILURE);
		}
	}
}



使い方は、単純に、、、
RollingFileAppender->I18nRollingFileAppender
とするだけです(コンストラクタを替えたので引数の末尾に文字コード指定だけが異なる)
変更箇所が一番少なく済むという理由だけで書きました。
本当は別のやり方で他の問題点も含め、直そうとは思ったのですが、例えばファイルサイズの
後判定を前判定にしようとすると様々な条件が出てくるんですよね。。。
「1サイクルのログが指定ファイルサイズを超えていた場合どうするの?」とか...etc
この提示したソースにしても「無駄に処理が増えて処理に時間が掛かる」とか言った問題
がありますが(痛..)取り敢えずは、ということで。
本来ならせっかく一度エンコードしてるわけですから、バイトをそのままストリームに
流し込むのが最善だとは思うのですが、そうすると見直し箇所が膨大になっちゃいそうで、
そうなると、そこまでマーサさんが望んでいるのかって問題になっちゃいますし、、、
マーサ
ベテラン
会議室デビュー日: 2004/11/26
投稿数: 87
投稿日時: 2004-11-30 16:18
申し訳ありません。
私の投稿にコードがちゃんと載ってなかったみたいですね。。。

動作確認までして頂いて恐縮です。
setFileをオーバーライドさせていましたが、setQWForFilesもオーバーライドさせていました。
subAppendはroollOverしているので、必要なのかな?と考えている所でした。

引用:

本当は別のやり方で他の問題点も含め、直そうとは思ったのですが、例えばファイルサイズの
後判定を前判定にしようとすると様々な条件が出てくるんですよね。。。
「1サイクルのログが指定ファイルサイズを超えていた場合どうするの?」とか...etc



上記のですと「起動時と実行時にサイズが超えていたら切り替える」で、考えいます。

引用:

この提示したソースにしても「無駄に処理が増えて処理に時間が掛かる」とか言った問題
がありますが(痛..)取り敢えずは、ということで。
本来ならせっかく一度エンコードしてるわけですから、バイトをそのままストリームに
流し込むのが最善だとは思うのですが、そうすると見直し箇所が膨大になっちゃいそうで、
そうなると、そこまでマーサさんが望んでいるのかって問題になっちゃいますし、、、



見直し箇所が膨大になる(追加ロジックが増える等)は避けたいので、その部分については妥協するしかないかと思っています。
マーサ
ベテラン
会議室デビュー日: 2004/11/26
投稿数: 87
投稿日時: 2004-11-30 16:18
申し訳ありません。
私の投稿にコードがちゃんと載ってなかったみたいですね。。。

動作確認までして頂いて恐縮です。
setFileをオーバーライドさせていましたが、setQWForFilesもオーバーライドさせていました。
subAppendはroollOverしているので、必要なのかな?と考えている所でした。

引用:

本当は別のやり方で他の問題点も含め、直そうとは思ったのですが、例えばファイルサイズの
後判定を前判定にしようとすると様々な条件が出てくるんですよね。。。
「1サイクルのログが指定ファイルサイズを超えていた場合どうするの?」とか...etc



上記のですと「起動時と実行時にサイズが超えていたら切り替える」で、考えいます。

引用:

この提示したソースにしても「無駄に処理が増えて処理に時間が掛かる」とか言った問題
がありますが(痛..)取り敢えずは、ということで。
本来ならせっかく一度エンコードしてるわけですから、バイトをそのままストリームに
流し込むのが最善だとは思うのですが、そうすると見直し箇所が膨大になっちゃいそうで、
そうなると、そこまでマーサさんが望んでいるのかって問題になっちゃいますし、、、



見直し箇所が膨大になる(追加ロジックが増える等)は避けたいので、その部分については妥協するしかないかと思っています。
takamaro
大ベテラン
会議室デビュー日: 2004/10/12
投稿数: 100
投稿日時: 2004-12-01 05:19
遅かりし、ではありますが。。。
Log4J v1.3.* (最新は v1.3 alpha-3)からは当問題の対策が打たれているようです。
新たなRollingFileAppender(org.apache.log4j.RollingFileAppenderとはパッケージ
が異なる別クラス。。。。名前も別にしないとパッケージ指定が面倒になるのにw)では、
カウントに問題のあったCountingQuietWriterを放棄し、新たにカウント判定クラスを
Policyとして設定するようになってます(ファイルサイズにはSizeBasedTriggerPolicy)
で、その気になる判定方法ですが、、、

file.length()

と、なんともストレートな方法を取ってます(大丈夫なんだろか?)
まぁ確かに文字コードに依存しない方法ではありますw

引用:

上記のですと「起動時と実行時にサイズが超えていたら切り替える」で、考えいます。


私は結構気になるのですがね、、Log4Jの方々も気にはされていないようなので
大した問題じゃないのかもしれませんね。。。ちと考え過ぎだったかな。。。
マーサ
ベテラン
会議室デビュー日: 2004/11/26
投稿数: 87
投稿日時: 2004-12-01 19:00
引用:

遅かりし、ではありますが。。。
Log4J v1.3.* (最新は v1.3 alpha-3)からは当問題の対策が打たれているようです。


なるほど、v1.3では対策がされていましたか。
v1.3はalpha版と言う事で正式リリース版ではないので使用検討外としていました。
(では、何故1.2.9でなく1.2.8を使用しているのか?と言う話も有りますが。。。)

引用:

私は結構気になるのですがね、、Log4Jの方々も気にはされていないようなので
大した問題じゃないのかもしれませんね。。。ちと考え過ぎだったかな。。。


気になると言えば、書き込みに行くタイミングでしか切り替えが行われない点ですね。
ファイルオープン時にチェックして切り替えるのが普通だとは思いますが。。。
何とかしたい点ではありますが、見直す範囲が拡大しますし時間的余裕も無い為、切り替えサイズ自体は問題ないので妥協しようかと言う事です。(今後の課題となるかもしれませんが)

エンコーディング、ファイルサイズ共解決致しました。(上記の問題は有りますが、、、)

takamaroさん、今まで色々とご教授有難う御座いました。
また、何か困った事が発生した際には宜しくお願い致します。


PS
このスレを参照の皆様の中に同じような問題にぶち当たった方もいるかと思います。
私はこう言う方法で解決したと言う意見があれば、是非このスレに残して置いて欲しいです。

また、これから直面する方がいるかと思います。
是非参考にして下さい。
そして、新たなる良い方法を見つけ出して下さい。

[ メッセージ編集済み 編集者: マーサ 編集日時 2004-12-01 19:01 ]
NEW
会議室デビュー日: 2007/07/05
投稿数: 4
投稿日時: 2007-07-05 15:10
独り言:
#頭大丈夫かな?
#母国語の掲示板に質問投げれば良いのに。。。
mio
ぬし
会議室デビュー日: 2005/08/25
投稿数: 734
お住まい・勤務地: 神奈川県
投稿日時: 2007-07-05 15:37
良く見ないで、古い投稿にレスしてしまったので削除…(_ _;

[ メッセージ編集済み 編集者: mio 編集日時 2007-07-05 15:38 ]
山本 裕介
ぬし
会議室デビュー日: 2003/05/22
投稿数: 2415
お住まい・勤務地: 恵比寿
投稿日時: 2007-07-05 16:14
Log4J は開発した当人も興味を失っている(?)製品です。
同じ人が別途おこしているプロジェクト - Logback を利用してみるという手もあります。
http://logback.qos.ch/

ソースコードからはエンコーディングも正しく扱われているように見えます。
http://logback.qos.ch/xref/ch/qos/logback/core/WriterAppender.html#167

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