import java.io.FilterWriter; import java.io.IOException; import java.lang.reflect.Field; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetAddress; import org.apache.log4j.Layout; import org.apache.log4j.Level; import org.apache.log4j.Logger; import org.apache.log4j.PatternLayout; import org.apache.log4j.helpers.SyslogQuietWriter; import org.apache.log4j.helpers.SyslogWriter; import org.apache.log4j.net.SyslogAppender; public class SyslogAppendarTest { public void execute(String syslogHost, int syslogFacility) throws NoSuchFieldException, IllegalAccessException { Layout layout = new PatternLayout("%d|%p|%m"); SyslogAppender appender = new SyslogAppender(layout, syslogHost, syslogFacility); // Writer を入れ替える setEncodeSpecifiableWriter(appender, "UTF-8"); Logger logger = Logger.getLogger(SyslogAppendarTest.class); logger.addAppender(appender); logger.setLevel(Level.WARN); logger.warn("警告ですよ!!"); } private static void setEncodeSpecifiableWriter( SyslogAppender appender, String encode) throws NoSuchFieldException, IllegalAccessException { // SyslogAppender が持っている SyslogQuietWriter を取得 Field sqwField = SyslogAppender.class.getDeclaredField("sqw"); sqwField.setAccessible(true); SyslogQuietWriter writer = (SyslogQuietWriter) sqwField.get(appender); // SyslogQuietWriter が持っている SyslogWriter を EncodeSpecifiableSyslogWriter に入れ替える Field outField = FilterWriter.class.getDeclaredField("out"); outField.setAccessible(true); outField.set(writer, new EncodeSpecifiableSyslogWriter(appender.getSyslogHost(), encode)); } // SyslogWriter を継承した Writer を実装する。 private static class EncodeSpecifiableSyslogWriter extends SyslogWriter { private final String encode; public EncodeSpecifiableSyslogWriter(String syslogHost, String encode) { super(syslogHost); this.encode = encode; } // write をオーバーライドする。string.getBytes(encode) 以外は親クラスと同じ。 @Override public void write(String string) throws IOException { if (getDs() != null && getAddress() != null) { byte[] bytes = string.getBytes(encode); int bytesLength = bytes.length; if (bytesLength >= 1024) bytesLength = 1024; DatagramPacket packet = new DatagramPacket( bytes, bytesLength, getAddress(), getPort()); getDs().send(packet); } } private DatagramSocket getDs() { try { Field field = SyslogWriter.class.getDeclaredField("ds"); field.setAccessible(true); return (DatagramSocket) field.get(this); } catch (Exception e) { e.printStackTrace(); return null; } } private InetAddress getAddress() { try { Field field = SyslogWriter.class.getDeclaredField("address"); field.setAccessible(true); return (InetAddress) field.get(this); } catch (Exception e) { e.printStackTrace(); return null; } } private int getPort() { try { Field field = SyslogWriter.class.getDeclaredField("port"); field.setAccessible(true); return ((Integer) field.get(this)).intValue(); } catch (Exception e) { e.printStackTrace(); return 514; } } } public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException { new SyslogAppendarTest().execute( "xxx.xxx.xxx.xxx", SyslogAppender.getFacility("LOCAL0")); } }できた。(ドヤ)
なるほど、log4j 自体には手を入れたくないけれどエンコード指定したい、というときには
強引ながらも手はある、ということのようだ。