###############################log4j.properties###############################
##### Global Log Level(OFF,FATAL,ERROR,WARN,INFO,DEBUG,ALL) #############
log4j.rootLogger=DEBUG,STDOUT,DB

###### STDOUT Logger ###############
log4j.appender.STDOUT=org.apache.log4j.ConsoleAppender
#輸出目的Appender的日誌級別,Appender的級別設定要優先於logger的
#級別設定,即先使用Appender的,而不管logger的日誌級別是怎樣設定的
log4j.appender.STDOUT.Threshold=DEBUG
log4j.appender.STDOUT.layout=org.apache.log4j.PatternLayout
log4j.appender.STDOUT.layout.ConversionPattern=[%p] [%l] %10.10c - %m%n

###### File Logger ###############
#開發時,使用DEBUG,釋出時最好修改成INFO,如果未設定級別,則使用
#父日誌記錄器的,設定了就使用logger的,不管父日誌怎樣設定
log4j.logger.com.mypakge=DEBUG,FILELOGER
#開發時設為true,表示需要螢幕輸出,釋出時這裡最好設定為false,表示不繼承父日誌記錄器的Appender
log4j.additivity.com.mypakge=true
log4j.appender.FILELOGER=org.apache.log4j.RollingFileAppender
#設定日誌輸出編碼方式為UTF-8,如果不指定,會以當前執行作業系統的編碼方式記錄,這樣在有的Linux上會出面亂碼
log4j.appender.FILELOGER.encoding=UTF-8
#${LOGS_PATH}為JVM環境變數,我們可以在執行裡給JVM加上該引數 -DLOGS_PATH=e:/tmp/log
log4j.appender.FILELOGER.File=${LOGS_PATH}/system.log
log4j.appender.FILELOGER.MaxFileSize=1024KB
log4j.appender.FILELOGER.MaxBackupIndex=10
#檔案採用追加方式
log4j.appender.FILELOGER.Append=true
log4j.appender.FILELOGER.layout=org.apache.log4j.PatternLayout
log4j.appender.FILELOGER.layout.ConversionPattern=[%d{yyy-MM-dd HH:mm:ss.SSS}] [%p] [%t] [%c] [%l] - [%m]%n

###### THREAD Logger ###############
#執行緒日誌一般記入到另一個檔案,執行緒日誌與主執行緒日誌基本上沒有什麼邏輯關係
log4j.logger.threadlogger=DEBUG,THREADLOGER
log4j.additivity.threadlogger=true
log4j.appender.THREADLOGER=org.apache.log4j.RollingFileAppender
log4j.appender.THREADLOGER.encoding=UTF-8
log4j.appender.THREADLOGER.File=${LOGS_PATH}/threadLog.log
log4j.appender.THREADLOGER.MaxFileSize=2000KB
log4j.appender.THREADLOGER.MaxBackupIndex=10
log4j.appender.THREADLOGER.layout=org.apache.log4j.PatternLayout
log4j.appender.THREADLOGER.layout.ConversionPattern=[%d{yyy-MM-dd HH:mm:ss.SSS}] [%p] [%t] [%c] [%l] - [%m]%n

###### SOCKET Logger ###############
log4j.addivity.org.apache=true 
log4j.appender.SOCKET=org.apache.log4j.net.SocketAppender
#注,SocketAppender沒有encoding屬性,而接收日誌的伺服器端類org.apache.log4j.net.Socke
#tServer也不能設定編碼方式,這裡在考慮他們在通訊時是不是傳遞的物件,而不是傳遞的字串呢?
#log4j.appender.SOCKET.encoding=UTF-8
log4j.appender.SOCKET.RemoteHost=localhost
log4j.appender.SOCKET.Port=8089
log4j.appender.SOCKET.LocationInfo=true
log4j.appender.SOCKET.layout=org.apache.log4j.PatternLayout
#這裡的格式配置不是很中要,好像不是要所這裡的格式要輸出那些訊息,這裡還是這個疑問就是在通訊時是否是
#傳遞的是序列化後的物件?因為伺服器接收到訊息後能以任何格式輸出,可見傳遞的資訊是完整的。~@!@#!哈
#剛跟了一下org.apache.log4j.net.SocketAppender原始碼,在獲取輸出流的時候使用的是物件流,如下:
#oos = new ObjectOutputStream(socket.getOutputStream());,這樣就進一步證了我的想法,在
#通訊時時傳遞的是物件,所以就不存在字元編碼的問題與客戶端日誌格式輸出問題。
log4j.appender.SOCKET.layout.ConversionPattern=%m

###### MAIL Logger ###############
log4j.appender.MAIL=org.apache.log4j.net.SMTPAppender
log4j.appender.MAIL.Threshold=ERROR
log4j.appender.MAIL.BufferSize=10
[email protected]
log4j.appender.MAIL.SMTPHost=smtp.126.com
#如果含有中文,則需使用native2asii log4j.properties log4jxx.properties 進行轉換,否則亂碼
log4j.appender.MAIL.Subject=Log4J\u63D0\u9192\u60A8\uFF1A\u7CFB\u7EDF\u53D1\u751F\u4E86\u4E25\u91CD\u9519\u8BEF
[email protected]
[email protected]
log4j.appender.MAIL.SMTPPassword=XXX
log4j.appender.MAIL.layout=org.apache.log4j.PatternLayout
log4j.appender.MAIL.layout.ConversionPattern=[framework] %d - %c -%-4r [%t] %-5p %c %x - %m%n

###### DB Logger ###############
log4j.appender.DB=org.apache.log4j.jdbc.JDBCAppender
log4j.appender.DB.driver=com.mysql.jdbc.Driver
log4j.appender.DB.URL=jdbc:mysql://127.0.0.1/test
log4j.appender.DB.bufferSize=1
log4j.appender.DB.user=root
log4j.appender.DB.password=111111
log4j.appender.DB.sql=insert into oplog
(UserName,opttype,createTime,LogLevel,methodinfo,MSG) values
('%X{UserName}','%X{opttype}','%d{yyyy-MM-dd
HH:mm:ss.SSS}','%p','%l','%m')    
log4j.appender.DB.layout=org.apache.log4j.PatternLayout

配置日誌伺服器

日誌伺服器的伺服器端由以下類啟動:
  log4j jar包中的org.apache.log4j.net.SocketServer 
 三個引數 【監聽埠】【日誌伺服器配置檔案】【客戶端配置檔案目錄】
  第三個引數【配置檔案目錄】其實指的是針對每個客戶端的配置檔案,名命規則為 "客戶端IP.lcf"

基本原理

當日志保存請求發過來時,伺服器會根據客戶端的IP去在指定的目錄(上面第三個引數)下搜尋各自的配置檔案,如果沒有找到的話,再找是否配置了公用的客戶端日誌配置檔案

generic.lcf,如果也沒有配置的話,它將日誌與伺服器執行日誌記錄在同一檔案中(這裡為server.log),如果找到了,會把收到的日誌按照配置檔案要求記錄,我在這
裡使用的客戶端配置檔案與log4j.properties是一樣的,所以這裡會產生與客戶機儲存的日誌是一樣的。

在執行前還得要修改一下 org.apache.log4j.net.SocketServer 這個類,這個類在取客戶端時有問題,網上其他人也這麼認為(我使用的是1.215版本),找到 String key = s.substring(0, i); 這一行,修改成 String key = s.substring(i + 1); 即可,然後把修改好的class放入log4j-1.2.15.jar包中(後面附上修改好的包)。

socketserver.properties

#檔名socketserver.properties
#如果需要顯示日誌介面,可以將本行啟用
log4j.rootCategory=, A1
log4j.rootLogger=DEBUG,A3,STDOUT
log4j.category.org.apache.log4j.net=INFO log4j.appender.STDOUT=org.apache.log4j.ConsoleAppender
log4j.appender.STDOUT.layout=org.apache.log4j.PatternLayout
log4j.appender.STDOUT.layout.ConversionPattern=[%p] [%l] %10.10c - %m%n log4j.appender.A1=org.apache.log4j.lf5.LF5Appender
log4j.appender.A1.MaxNumberOfRecords=700 log4j.appender.A3=org.apache.log4j.RollingFileAppender
log4j.appender.A3.file=${LOGS_PATH}/server.log
log4j.appender.A3.MaxFileSize=1024KB
log4j.appender.A3.MaxBackupIndex=10
log4j.appender.A3.layout=org.apache.log4j.PatternLayout
log4j.appender.A3.layout.ConversionPattern=\n\n[%-5p] %d{yyyy-MM-dd HH\:mm\:ss,SSS} method\:%l%n%m%n

客戶端配置檔案 127.0.0.1.lcf

###############################log4j.properties###############################
##### Global Log Level(OFF,FATAL,ERROR,WARN,INFO,DEBUG,ALL) #############
log4j.rootLogger=DEBUG,FILELOGER ###### File Logger ###############
#開發時,使用DEBUG,釋出時最好修改成INFO,如果未設定級別,則使用
#父日誌記錄器的,設定了就使用logger的,不管父日誌怎樣設定
log4j.logger.com.mypakge=DEBUG,FILELOGER
#開發時設為true,表示需要螢幕輸出,釋出時這裡最好設定為false,表示不繼承父日誌記錄器的Appender
log4j.additivity.com.mypakge=true
log4j.appender.FILELOGER=org.apache.log4j.RollingFileAppender
#設定日誌輸出編碼方式為UTF-8,如果不指定,會以當前執行作業系統的編碼方式記錄,這樣在有的Linux上會出面亂碼
log4j.appender.FILELOGER.encoding=UTF-8
#${LOGS_PATH}為JVM環境變數,我們可以在執行裡給JVM加上該引數 -DLOGS_PATH=e:/tmp/log
log4j.appender.FILELOGER.File=${LOGS_PATH}/client.log
log4j.appender.FILELOGER.MaxFileSize=1024KB
log4j.appender.FILELOGER.MaxBackupIndex=10
#檔案採用追加方式
log4j.appender.FILELOGER.Append=true
log4j.appender.FILELOGER.layout=org.apache.log4j.PatternLayout
log4j.appender.FILELOGER.layout.ConversionPattern=[%d{yyy-MM-dd HH:mm:ss.SSS}] [%p] [%t] [%c] [%l] - [%m]%n

啟動:

java -classpath log4j-1.2.15.jar -DLOGS_PATH=e:/tmp/sverlog o
rg.apache.log4j.net.SocketServer 8089 socketserver.properties .

現在使用一個測試類記錄日誌時,它會往日誌伺服器傳送日誌事件,伺服器會根據伺服器端配置的客戶端配置檔案記錄日誌。

配置郵件日誌

由於剛開始使用1.2.9版本的包時
org.apache.log4j.net.SMTPAppender
傳送郵件時不支援使用者鑑權操作,而有的郵件伺服器在傳送時需要先登入後再發送,所以換用了1.2.15的包,SMTPAppender類支援SMTPUsername與SMTPPassword兩個鑑權引數,這樣就可以傳送日誌郵件了,具體配置參見文章開頭。

配置資料庫日誌

建立表:

create table oplog(
    UserName varchar(20),
    opttype varchar(20),
    createTime varchar(30),
    LogLevel varchar(20),
    methodinfo varchar(100),
    MSG varchar(1024),
    primary key (createTime)
)

表中的 UserName 與 opttype 表示使用者名稱與操作型別,插入資料時使用 MDC 類進行預先設定,且配置檔案中使用 %x{XXX} 來引用, MDC其實就是Java裡的ThreadLocal類的派生類。

測試程式碼:

Java程式碼
 
 

  1. import org.apache.commons.logging.Log;
  2. import org.apache.commons.logging.LogFactory;
  3. import org.apache.log4j.MDC;
  4. public class TestLog {
  5. private static Log log = LogFactory.getLog(TestLog.class);
  6. public void log() {
  7. log.debug("Debug info.");
  8. log.info("Info info");
  9. log.warn("Warn info");
  10. log.error("Error info");
  11. log.fatal("Fatal info");
  12. }
  13. public static void main(String[] args) {
  14. MDC.put("UserName", "jzj");
  15. MDC.put("opttype", "delete");
  16. TestLog test = new TestLog();
  17. test.log();
  18. }
  19. }