ひょんなことからエンコードを指定して 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の初期設定 - ほげおメモ