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:<INFO> msgdetailxxxxxxxxxxxxxxxxxxxxxxxxxx.
實際的MSG是"myapp:<INFO> msgdetailxxxxxxxxxxxxxxxxxxxxxxxxxx",如果要拆成兩條記錄,則:
Apr 28 10:22:59 myhost myapp:<INFO> msgdetailxxxxx
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的可以發給其它業務處理,非常方便。