log4j本身是支持syslog的,但是有很多不足,所以需要改造。
1.log4j在支持syslog时,默认同Msg大小是1024,这也是syslog的RFC3164标准。但是对于在实际应用中超过1024的MSG,我们还是
希望能完整地log下来,所以log4j对大于1024的MSG进行拆包。
这一拆就带来了麻烦。
因为priority,tag这些syslog标准的属性都是包含在MSG本身而当不是专门的字段,所以在拆包时只能拆在第一条,而后面的MSG就失去了这些关键属性。比如:
Apr 28 10:22:59 myhost myapp:
实际的MSG是"myapp:
Apr 28 10:22:59 myhost myapp:
Apr 28 10:22:59 myhost xxxxxxxxxxxxxx
第二条以后的记录就失去了tag和priority,文档分类就不知道把这条消息放在哪个文件档中了。所以要么我们自己手工分割消息,将分割后小于1024的消息传给log4j,这样它会作为多条消息处理,就不会把关键属性去掉。
这条路还是走不通,因为MSG拆分后,UDP传输不可能保证消息顺序和完整,消息并不是按你拆开的顺序完整地发送给syslog.那么也就不能保证被还原。即使加上序列ID也难以保证。
2.所以我尽量能寻找支持1024以上消息长度的方案。一开始,我的测试环境是log4j加ubuntu下的syslogd(sysklogd).我修改了log4j的源码,从UDP层取消1024的限制,但是消息发送到syslogd后,被服务端截断。即syslogd也按照RFC3164标准将消息裁断了。但UDP协议是可以发送大于1024的消息的。
3.后来改用syslog-ng,修改了相关参数,出现一个惊喜,可以发送64K的消息,这已经是UDP包的限制了。当然一条日志超过64K就不叫日志了。
现在就是修改log4j的appender了。这个工作主要是重新实现SyslogAppender中UDP发送。
如果把它们重新分发到我们自己的包中需要修改三个类,主要实现SyslogWriter,然后是SyslogAppender,让他调用我们自己的SyslogQuiteWriter,然后在SyslogQuiteWriter中调用修改过的SyslogWriter。
如果要增加一些控制,比如增加字符集,因为SyslogWriter默认getBytes是没有字符集参数,使用系统默认字符集,有可能不是我们
想要的结果,所以如果增加配置项,需要先在SyslogAppender中增加setter方法,LoggerFactory中初始化时是读一个配置项然后
反射调用appender的set方法,比如你配置了log4j.appender.syslog.axman=12345
那么初始化时会反射调用SyslogAppender的setAxman方法把配置项注入进去而不是放在一个数据结构中的。
这样经过修改后,只要将log4j.appender.syslog指向我们的SyslogAppender:
log4j.appender.syslog=com.axman.SyslogAppender,并且com.axman.SyslogAppender在classpath中就可以正确地工作。其它的没有任何影响,这时如果你把ConversionPattern配置成 myapp:<%p> 其它选项......%m%n
就可以把日志按myapp,priority来分到不同文件中,特别是按$LEVEL来分档,可以把fatal(对应syslog是emerg)的日志先发给监控处理而info的可以发给其它业务处理,非常方便。