1概述
一般的系統對程序的調試信息只進行了簡單的粗放處理,將這些信息直接用System.out.println()語句輸出到控制檯中。由於在調度過程中程序員爲了能夠跟蹤程序的運行情況往往將大量信息輸出到控制檯,而在調度成功後沒有相應地將這些信息屏蔽掉,在程序部署運行後,往往一個簡單的業務功能調用也會輸出大容量的過程調度信息,一方面造成了大量IO的讀寫,佔用硬盤空間,另一方面則因爲日誌量大,很難查找到運行期有用的日誌信息。
程序異常,資源釋放操作失敗這些信息是發現程序問題,定位出錯點的信息依據,得不到這些信息將導致程序錯誤被屏蔽,要想使問題浮出水面程序必須能夠提供詳細而簡潔的日誌信息。
?log4J是爲java語言量身定做的一個日誌模塊,用統一的接口寫日誌,通過配置文件信息控制日誌信息的輸出格式、目的及輸出級別(指定輸出級別後,只有比輸出級別更高的日誌會被輸出)。可以在不更改程序輸出日誌的情況下方便日誌輸出的控制,爲日誌的操作提供了很大的靈活性。
2 log4J的基本操作
2.1寫日誌的API
log4J將日誌分爲5個級別,從低到高分別是DEBUG,INFO,WARN,ERROR,FATAL,相應地log4J爲記錄這5個級別提供了5個方法,它們分別是:
public void debug(Object obj)
public void info(Object obj)
public void warn(Object obj)
public void error(Object obj)
public void fatal(Object obj)
同時每個方法還對應一個帶Throwable入參的重載函數,用於將異常一併記錄到日誌中:
public void debug(Object obj,Throwable ex)
public void info(Object obj,Throwable ex)
public void warn(Object obj,Throwable ex)
public void error(Object obj,Throwable ex)
public void fatal(Object obj,Throwable ex)
5個級別記錄信息的重要性依次提升,下面就每個記錄方法對應的應用場合舉例如下:
2.1.1 寫日誌API的使用示例
在程序中如何恰當級別的日誌記錄API記錄日誌信息是非常重要的,一般的我們將信息以其重要性調用將其劃分爲5個級別,分別調用相應的API來記錄,我們以一個查詢數據庫的代碼段來說明各級別的劃分:
Connection conn = null; String sqlStr = “select * from table1 where a=’”+a+”’”; //測試變量是否正確,在調度時查看,以後不會用 logger.debug(“sqlStr字串爲:”+sqlStr); ... try { conn = DBBean.getConnection(); Statement stat = conn.createStatement(); ResultSet rs = stat.executeQuery(sqlStr); if(rs.next()) { logger.info(“有記錄”); } else { logger.warn(“因配置要求至少要有一條記錄,請覈對配置信息。”); //假設配置信息要求一條配置記錄,當找不到記錄時應該警告, } }catch(SQLException e) { logger.error(“數據查詢時發生異常”,e); //發生了查詢異常,可能是sqlStr語句的語法錯誤造成的 } finally { try { if(conn != null) { conn.close(); conn = null; } } catch(SQLException e) { logger.warn(“數據連接無法關閉,連接將無法釋放”,e); //數據連接無法關閉將導致資源泄漏,可能是系統原因產生的 } } |
fatal日誌級別是表示,一旦這個事情發生,系統即無法運行的情況。如系統有一個伺服線程,它如果崩潰後,系統服務無法正常運行,則此時可以用fatal()寫日誌:
try { while(true) { ServiceThread.run(); } } catch { logger.fatal("[SYS001]伺服線程異常終止"); } |
2.1.2日誌信息構成
通過配置,日誌信息包括兩部分,一部分是由日誌引擎通過配置生成的信息,如信息來源的包、類、對應源碼的行數,日誌級別等信息,而另一部分是用戶通過接口入參手工設置的對象信息,在寫日誌前,將調用對象的toString()將其轉換成字符串。對於 error和fatal級別的日誌,我們約定必須爲每個日誌指定錯誤日誌的類型,錯誤的日誌的類型和日誌信息一起作爲入參傳入寫日誌引擎,錯誤類型用[]括起來。如:
logger.error(“[DB001]關閉數據連接時出錯。”)
logger.fatal(“[HIB001]關閉Hibernate會話時發生異常。”);
logger.error(“[CFG001]審批流程配置信息不正確。”); |
此外必須爲每條日誌類型構造說明字典:
錯誤編號 |
說明 |
產生原因 |
解決方法 |
DB001 |
關閉數據連接失敗 |
數據連接打開的光標太多,會話因網絡終止 |
仔細檢查程序,查看該連接創建的Statement或PrepareStatemetn在用完後沒有及時關閉。檢查數據庫的配置,或網絡連接方面的硬件問題 |
HIB001 |
關閉Hibernate會話失敗 |
會話對應的數據連接打開的光標太多,會話因網絡終止 |
仔細檢查程序,查看該會話對應的數據連接創建的Statement或PrepareStatemetn在用完後沒有及時關閉。檢查數據庫的配置,或網絡連接方面的硬件問題 |
CFG001 |
審批流程配置信息不正確 |
沒有正確配置T_FLOW表的信息 |
每個流程在T_Flow表中都必須配置且只須配置一條配置信息,配置信息必須包括流程名、流程編號的信息,流程編號不能和其他流程編號重複。 |
… |
… |
… |
… |
3 log4J的配置
log4J通過一個配置文件決定輸出日誌的級別、目的以及格式,文件名爲:log4j.properties
可以在web.xml中通過容器上下文參數指定該文件的地址:
…
logConfFile WEB-INF/log4j.properties 相對於應用程序根目錄
…
|
必須通過一個類讀取該參數以初始化log4J的配置信息,我們在SysInit.java中設置該配置信息:
public void contextInitialized(ServletContextEvent sce) {??? … System.out.println("初始化基於log4j的日誌引擎..."); String prefix =sce.getServletContext().getRealPath("/"); String logFileConf = sce.getServletContext().getInitParameter("logConfFile"); PropertyConfigurator.configure(prefix+System.getProperty("file.separator")+logFileConf); System.out.println("日誌引擎就緒,日誌配置文件位於"+prefix+System.getProperty("file.separator")+logFileConf+"/n");? … } |
因爲SysInit是實現容器監聽器接口的類,這樣在WEB容器初始化時,就會初始化該日誌的配置信息.
log4J的配置文件內容如下:
log4j.rootLogger=DEBUG,R #log4j.appender.A1=org.apache.log4j.ConsoleAppender
#log4j.appender.A1.layout=org.apache.log4j.PatternLayout
#log4j.appender.A1.layout.ConversionPattern=%d %5p [%t] (%F:%L) - %m%n
log4j.appender.R=org.apache.log4j.RollingFileAppender log4j.appender.R.File=e:/tomcat/webLogs/log4j.log log4j.appender.R.MaxFileSize=100KB log4j.appender.R.MaxBackupIndex=1 log4j.appender.R.layout=org.apache.log4j.PatternLayout log4j.appender.R.layout.ConversionPattern=%d %5p [%t] (%F:%L) - %m%n |
該配置指定日誌寫入到e:/tomcat/webLogs/log4j.log文件中,大小爲100K,以原文本方式寫日誌,日誌信息中包括類名,方法名,行數等信息.