ひょんなことからエンコードを指定して Syslog にログ出力をしたいと思い立ったものの、
どうも log4j では対応していないらしく、OS デフォルトエンコードでしか出力できないらしい。
変更個所は少ないのでちょこっと書き換えてみた。
rsyslog を扱うのは初めてだったので以下設定メモ。
まずは設定ファイル /etc/rsyslog.conf を編集。
デフォルトでは外部からのログを受け付けていないので、以下のコメントアウトされている箇所を外す。
/var/log/local0.log に「test」と出力されていることを確認。設定はできているようだ。
どうも log4j では対応していないらしく、OS デフォルトエンコードでしか出力できないらしい。
変更個所は少ないのでちょこっと書き換えてみた。
rsyslog の設定
CentOS 6.0 を使って検証してみようとしたところ、デフォでインストールされているのは rsyslog だった。rsyslog を扱うのは初めてだったので以下設定メモ。
まずは設定ファイル /etc/rsyslog.conf を編集。
デフォルトでは外部からのログを受け付けていないので、以下のコメントアウトされている箇所を外す。
# provides UDP syslog reception $ModLoad imudp $UDPServerRun 514適当にファシリティとテンプレートを追加。
$template testtemplate,"%timegenerated%,%msg%\n" local0.* /var/log/local0.log;testtemplate設定ファイルを編集したので
service rsyslog reloadでリロードする。logger -p local0.info "test"のようにテストしてみる。/var/log/local0.log に「test」と出力されていることを確認。設定はできているようだ。
現状の log4j の挙動を確認
Layout layout = new PatternLayout("%d|%p|%m");
String syslogHost = "xxx.xxx.xxx.xxx";
int syslogFacility = SyslogAppender.getFacility("LOCAL0");
SyslogAppender appender = new SyslogAppender(layout, syslogHost, syslogFacility);
Logger logger = Logger.getLogger(Main.class);
logger.addAppender(appender);
logger.setLevel(Level.WARN);
logger.warn("警告ですよ!!");
SyslogAppender にエンコード指定箇所は無いのでこんな感じ。ソースファイルのエンコードを MS932 で Windows から実行してログ出力された内容を見ると、
菱形はてなマークに表示されている。
(ソースファイルのエンコードを UTF-8 にすると正常に出力される)
log4j のソースを一部書き換える
org.apache.log4j.net.SyslogAppender はフィールドにorg.apache.log4j.helpers.SyslogQuietWriter を持っており、
さらに SyslogQuietWriter が持っている org.apache.log4j.helpers.SyslogWriter が
string.getBytes() したバイト列を送っている。
SyslogAppenderにエンコードを指定したコンストラクタを追加する。
private String encoding;
public
SyslogAppender(Layout layout, String syslogHost, int syslogFacility, String encode) {
this(layout, syslogHost, syslogFacility);
setEncoding(encode);
}
public String getEncoding() {
return encoding;
}
public void setEncoding(String encoding) {
if(encoding == null)
return;
if (sqw != null)
sqw.setEncoding(encoding);
this.encoding = encoding;
}
SyslogAppender から値を受け取るエンコードを SyslogWriter に渡すようにSyslogQuietWriterを変更する。
public
void setEncoding(String encoding) {
if (out instanceof SyslogWriter) {
((SyslogWriter) out).setEncoding(encoding);
}
}
SyslogWriterにgetter/setter を追加し、write() メソッドを変更。
public String getEncoding() {
return encoding;
}
public void setEncoding(String encoding) {
this.encoding = encoding;
}
public
void write(final String string) throws IOException {
if(this.ds != null && this.address != null) {
byte[] bytes;
if (encoding == null) {
bytes = string.getBytes();
} else {
bytes = string.getBytes(encoding);
}
//
// syslog packets must be less than 1024 bytes
//
int bytesLength = bytes.length;
if (bytesLength >= 1024) {
bytesLength = 1024;
}
DatagramPacket packet = new DatagramPacket(bytes, bytesLength,
address, port);
ds.send(packet);
}
}
修正点は以上。(あとは SyslogAppenderTest にエンコード指定用のテストケースを追加した。)
エンコード指定してログ出力してみる
コンストラクタから指定して、後は同じ。
SyslogAppender appender = new SyslogAppender(layout, syslogHost, syslogFacility, "UTF-8");
文字化けせずログ出力できたことを確認する。
Nov 27 03:00:31,00:53,991|WARN|警告ですよ!!できたできた!
参考:
rsyslog の設定をしてみる - いますぐ実践! Linuxシステム管理 / Vol.207
rsyslogdの初期設定 - ほげおメモ