在應用程序中添加日誌記錄總的來講基於三個目的:監視代碼中變量的變化狀況,週期性的記錄到文件中供其餘應用進行統計分析工做;跟蹤代碼運行時軌跡,做爲往後審計的依據;擔當集成開發環境中的調試器的做用,向文件或控制檯打印代碼的調試信息。html
在應用程序中添加日誌記錄總的來講基於三個目的:監視代碼中變量的變化狀況,週期性的記錄到文件中供其餘應用進行統計分析工做;跟蹤代碼運行時軌跡,做爲往後審計的依據;擔當集成開發環境中的調試器的做用,向文件或控制檯打印代碼的調試信息。java
最普通的作法就是在代碼中嵌入許多的打印語句,這些打印語句能夠輸出到控制檯或文件中,比較好的作法就是構造一個日誌操做類來封裝此類操做,而不是讓一系列的打印語句充斥了代碼的主體。apache
在強調可重用組件開發的今天,除了本身從頭至尾開發一個可重用的日誌操做類外,Apache爲咱們提供了一個強有力的日誌操做包-Log4j。服務器
Log4j是Apache的一個開放源代碼項目,經過使用Log4j,咱們能夠控制日誌信息輸送的目的地是控制檯、文件、GUI組件、甚至是套接口服務器、NT的事件記錄器、UNIX Syslog守護進程等;咱們也能夠控制每一條日誌的輸出格式;經過定義每一條日誌信息的級別,咱們可以更加細緻地控制日誌的生成過程。最使人感興趣的就是,這些能夠經過一個配置文件來靈活地進行配置,而不須要修改應用的代碼。網絡
此外,經過Log4j其餘語言接口,您能夠在C、C++、.Net、PL/SQL程序中使用Log4j,其語法和用法與在Java程序中同樣,使得多語言分佈式系統獲得一個統一一致的日誌組件模塊。並且,經過使用各類第三方擴展,您能夠很方便地將Log4j集成到J2EE、JINI甚至是SNMP應用中。app
本文介紹的Log4j版本是1.2.3。做者試圖經過一個簡單的客戶/服務器Java程序例子對比使用與不使用Log4j 1.2.3的差異,並詳細講解了在實踐中最常使用Log4j的方法和步驟。在強調可重用組件開發的今天,相信Log4j將會給廣大的設計開發人員帶來方便。加入到Log4j的隊伍來吧!socket
咱們先來看一個簡單的例子,它是一個用Java實現的客戶/服務器網絡程序。剛開始咱們不使用Log4j,而是使用了一系列的打印語句,而後咱們將使用Log4j來實現它的日誌功能。這樣,你們就能夠清楚地比較出先後兩個代碼的差異。分佈式
2.1.1. 客戶程序佈局
package log4j ; import java.io.* ; import java.net.* ; /** * * <p> Client Without Log4j </p> * <p> Description: a sample with log4j</p> * @version 1.0 */ public class ClientWithoutLog4j { /** * * @param args */ public static void main ( String args [] ) { String welcome = null; String response = null; BufferedReader reader = null; PrintWriter writer = null; InputStream in = null; OutputStream out = null; Socket client = null; try { client = new Socket ( "localhost", 8001 ) ; System.out.println ( "info: Client socket: " + client ) ; in = client.getInputStream () ; out = client.getOutputStream () ; } catch ( IOException e ) { System.out.println ( "error: IOException : " + e ) ; System.exit ( 0 ) ; } try{ reader = new BufferedReader( new InputStreamReader ( in ) ) ; writer = new PrintWriter ( new OutputStreamWriter ( out ), true ) ; welcome = reader.readLine () ; System.out.println ( "debug: Server says: '" + welcome + "'" ) ; System.out.println ( "debug: HELLO" ) ; writer.println ( "HELLO" ) ; response = reader.readLine () ; System.out.println ( "debug: Server responds: '" + response + "'") ; System.out.println ( "debug: HELP" ) ; writer.println ( "HELP" ) ; response = reader.readLine () ; System.out.println ( "debug: Server responds: '" + response + "'" ) ; System.out.println ( "debug: QUIT" ) ; writer.println ( "QUIT" ) ; } catch ( IOException e ) { System.out.println ( "warn: IOException in client.in.readln()" ) ; System.out.println ( e ) ; } try{ Thread.sleep ( 2000 ) ; } catch ( Exception ignored ) {} } }
2.1.2. 服務器程序ui
package log4j ; import java.util.* ; import java.io.* ; import java.net.* ; /** * * <p> Server Without Log4j </p> * <p> Description: a sample with log4j</p> * @version 1.0 */ public class ServerWithoutLog4j { final static int SERVER_PORT = 8001 ; // this server's port /** * * @param args */ public static void main ( String args [] ) { String clientRequest = null; BufferedReader reader = null; PrintWriter writer = null; ServerSocket server = null; Socket socket = null; InputStream in = null; OutputStream out = null; try { server = new ServerSocket ( SERVER_PORT ) ; System.out.println ( "info: ServerSocket before accept: " + server ) ; System.out.println ( "info: Java server without log4j, on-line!" ) ; // wait for client's connection socket = server.accept () ; System.out.println ( "info: ServerSocket after accept: " + server ) ; in = socket.getInputStream () ; out = socket.getOutputStream () ; } catch ( IOException e ) { System.out.println( "error: Server constructor IOException: " + e ) ; System.exit ( 0 ) ; } reader = new BufferedReader ( new InputStreamReader ( in ) ) ; writer = new PrintWriter ( new OutputStreamWriter ( out ) , true ) ; // send welcome string to client writer.println ( "Java server without log4j, " + new Date () ) ; while ( true ) { try { // read from client clientRequest = reader.readLine () ; System.out.println ( "debug: Client says: " + clientRequest ) ; if ( clientRequest.startsWith ( "HELP" ) ) { System.out.println ( "debug: OK!" ) ; writer.println ( "Vocabulary: HELP QUIT" ) ; } else { if ( clientRequest.startsWith ( "QUIT" ) ) { System.out.println ( "debug: OK!" ) ; System.exit ( 0 ) ; } else{ System.out.println ( "warn: Command '" + clientRequest + "' not understood." ) ; writer.println ( "Command '" + clientRequest + "' not understood." ) ; } } } catch ( IOException e ) { System.out.println ( "error: IOException in Server " + e ) ; System.exit ( 0 ) ; } } } }
2.2.1. 客戶程序
package log4j ; import java.io.* ; import java.net.* ; // add for log4j: import some package import org.apache.log4j.PropertyConfigurator ; import org.apache.log4j.Logger ; import org.apache.log4j.Level ; /** * * <p> Client With Log4j </p> * <p> Description: a sample with log4j</p> * @version 1.0 */ public class ClientWithLog4j { /* add for log4j: class Logger is the central class in the log4j package. we can do most logging operations by Logger except configuration. getLogger(...): retrieve a logger by name, if not then create for it. */ static Logger logger = Logger.getLogger ( ClientWithLog4j.class.getName () ) ; /** * * @param args : configuration file name */ public static void main ( String args [] ) { String welcome = null ; String response = null ; BufferedReader reader = null ; PrintWriter writer = null ; InputStream in = null ; OutputStream out = null ; Socket client = null ; /* add for log4j: class BasicConfigurator can quickly configure the package. print the information to console. */ PropertyConfigurator.configure ( "ClientWithLog4j.properties" ) ; // add for log4j: set the level // logger.setLevel ( ( Level ) Level.DEBUG ) ; try{ client = new Socket( "localhost" , 8001 ) ; // add for log4j: log a message with the info level logger.info ( "Client socket: " + client ) ; in = client.getInputStream () ; out = client.getOutputStream () ; } catch ( IOException e ) { // add for log4j: log a message with the error level logger.error ( "IOException : " + e ) ; System.exit ( 0 ) ; } try{ reader = new BufferedReader ( new InputStreamReader ( in ) ) ; writer = new PrintWriter ( new OutputStreamWriter ( out ), true ) ; welcome = reader.readLine () ; // add for log4j: log a message with the debug level logger.debug ( "Server says: '" + welcome + "'" ) ; // add for log4j: log a message with the debug level logger.debug ( "HELLO" ) ; writer.println ( "HELLO" ) ; response = reader.readLine () ; // add for log4j: log a message with the debug level logger.debug ( "Server responds: '" + response + "'" ) ; // add for log4j: log a message with the debug level logger.debug ( "HELP" ) ; writer.println ( "HELP" ) ; response = reader.readLine () ; // add for log4j: log a message with the debug level logger.debug ( "Server responds: '" + response + "'") ; // add for log4j: log a message with the debug level logger.debug ( "QUIT" ) ; writer.println ( "QUIT" ) ; } catch ( IOException e ) { // add for log4j: log a message with the warn level logger.warn ( "IOException in client.in.readln()" ) ; System.out.println ( e ) ; } try { Thread.sleep ( 2000 ) ; } catch ( Exception ignored ) {} } }
2.2.2. 服務器程序
package log4j; import java.util.* ; import java.io.* ; import java.net.* ; // add for log4j: import some package import org.apache.log4j.PropertyConfigurator ; import org.apache.log4j.Logger ; import org.apache.log4j.Level ; /** * * <p> Server With Log4j </p> * <p> Description: a sample with log4j</p> * @version 1.0 */ public class ServerWithLog4j { final static int SERVER_PORT = 8001 ; // this server's port /* add for log4j: class Logger is the central class in the log4j package. we can do most logging operations by Logger except configuration. getLogger(...): retrieve a logger by name, if not then create for it. */ static Logger logger = Logger.getLogger ( ServerWithLog4j.class.getName () ) ; /** * * @param args */ public static void main ( String args[]) { String clientRequest = null ; BufferedReader reader = null ; PrintWriter writer = null ; ServerSocket server = null ; Socket socket = null ; InputStream in = null ; OutputStream out = null ; /* add for log4j: class BasicConfigurator can quickly configure the package. print the information to console. */ PropertyConfigurator.configure ( "ServerWithLog4j.properties" ) ; // add for log4j: set the level // logger.setLevel ( ( Level ) Level.DEBUG ) ; try{ server = new ServerSocket ( SERVER_PORT ) ; // add for log4j: log a message with the info level logger.info ( "ServerSocket before accept: " + server ) ; // add for log4j: log a message with the info level logger.info ( "Java server with log4j, on-line!" ) ; // wait for client's connection socket = server.accept() ; // add for log4j: log a message with the info level logger.info ( "ServerSocket after accept: " + server ) ; in = socket.getInputStream() ; out = socket.getOutputStream() ; } catch ( IOException e ) { // add for log4j: log a message with the error level logger.error ( "Server constructor IOException: " + e ) ; System.exit ( 0 ) ; } reader = new BufferedReader ( new InputStreamReader ( in ) ) ; writer = new PrintWriter ( new OutputStreamWriter ( out ), true ) ; // send welcome string to client writer.println ( "Java server with log4j, " + new Date () ) ; while ( true ) { try { // read from client clientRequest = reader.readLine () ; // add for log4j: log a message with the debug level logger.debug ( "Client says: " + clientRequest ) ; if ( clientRequest.startsWith ( "HELP" ) ) { // add for log4j: log a message with the debug level logger.debug ( "OK!" ) ; writer.println ( "Vocabulary: HELP QUIT" ) ; } else { if ( clientRequest.startsWith ( "QUIT" ) ) { // add for log4j: log a message with the debug level logger.debug ( "OK!" ) ; System.exit ( 0 ) ; } else { // add for log4j: log a message with the warn level logger.warn ( "Command '" + clientRequest + "' not understood." ) ; writer.println ( "Command '" + clientRequest + "' not understood." ) ; } } } catch ( IOException e ) { // add for log4j: log a message with the error level logger.error( "IOException in Server " + e ) ; System.exit ( 0 ) ; } } } }
2.2.3. 配置文件
2.2.3.1. 客戶程序配置文件
log4j.rootLogger=INFO, A1 log4j.appender.A1=org.apache.log4j.ConsoleAppender log4j.appender.A1.layout=org.apache.log4j.PatternLayout log4j.appender.A1.layout.ConversionPattern=%-4r %-5p [%t] %37c %3x - %m%n
2.2.3.2. 服務器程序配置文件
log4j.rootLogger=INFO, A1 log4j.appender.A1=org.apache.log4j.ConsoleAppender log4j.appender.A1.layout=org.apache.log4j.PatternLayout log4j.appender.A1.layout.ConversionPattern=%-4r %-5p [%t] %37c %3x - %m%n
比較這兩個應用能夠看出,採用Log4j進行日誌操做的整個過程至關簡單明瞭,與直接使用System.out.println語句進行日誌信息輸出的方式相比,基本上沒有增長代碼量,同時可以清楚地理解每一條日誌信息的重要程度。經過控制配置文件,咱們還能夠靈活地修改日誌信息的格式,輸出目的地等等方面,而單純依靠System.out.println語句,顯然須要作更多的工做。
下面咱們將之前面使用Log4j的應用做爲例子,詳細講解使用Log4j的主要步驟。
Log4j由三個重要的組件構成:日誌信息的優先級,日誌信息的輸出目的地,日誌信息的輸出格式。日誌信息的優先級從高到低有ERROR、WARN、INFO、DEBUG,分別用來指定這條日誌信息的重要程度;日誌信息的輸出目的地指定了日誌將打印到控制檯仍是文件中;而輸出格式則控制了日誌信息的顯示內容。
其實您也能夠徹底不使用配置文件,而是在代碼中配置Log4j環境。可是,使用配置文件將使您的應用程序更加靈活。
Log4j支持兩種配置文件格式,一種是XML格式的文件,一種是Java特性文件(鍵=值)。下面咱們介紹使用Java特性文件作爲配置文件的方法:
配置根Logger,其語法爲:
log4j.rootLogger = [ level ] , appenderName, appenderName, …
其中,level 是日誌記錄的優先級,分爲OFF、FATAL、ERROR、WARN、INFO、DEBUG、ALL或者您定義的級別。Log4j建議只使用四個級別,優先級從高到低分別是ERROR、WARN、INFO、DEBUG。經過在這裏定義的級別,您能夠控制到應用程序中相應級別的日誌信息的開關。好比在這裏定義了INFO級別,則應用程序中全部DEBUG級別的日誌信息將不被打印出來。
appenderName就是指定日誌信息輸出到哪一個地方。您能夠同時指定多個輸出目的地。
配置日誌信息輸出目的地Appender,其語法爲
log4j.appender.appenderName = fully.qualified.name.of.appender.class log4j.appender.appenderName.option1 = value1 … log4j.appender.appenderName.option = valueN
其中,Log4j提供的appender有如下幾種:
org.apache.log4j.ConsoleAppender(控制檯),
org.apache.log4j.FileAppender(文件),
org.apache.log4j.DailyRollingFileAppender(天天產生一個日誌文件),org.apache.log4j.RollingFileAppender(文件大小到達指定尺寸的時候產生一個新的文件),
org.apache.log4j.WriterAppender(將日誌信息以流格式發送到任意指定的地方)
配置日誌信息的格式(佈局),其語法爲:
log4j.appender.appenderName.layout = fully.qualified.name.of.layout.class log4j.appender.appenderName.layout.option1 = value1 … log4j.appender.appenderName.layout.option = valueN
其中,Log4j提供的layout有如下幾種:
org.apache.log4j.HTMLLayout(以HTML表格形式佈局),
org.apache.log4j.PatternLayout(能夠靈活地指定佈局模式),
org.apache.log4j.SimpleLayout(包含日誌信息的級別和信息字符串),
org.apache.log4j.TTCCLayout(包含日誌產生的時間、線程、類別等等信息)
下面將講述在程序代碼中怎樣使用Log4j。
3.2.1.獲得記錄器
使用Log4j,第一步就是獲取日誌記錄器,這個記錄器將負責控制日誌信息。其語法爲:
public static Logger getLogger( String name),
經過指定的名字得到記錄器,若是必要的話,則爲這個名字建立一個新的記錄器。Name通常取本類的名字,好比:
static Logger logger = Logger.getLogger ( ServerWithLog4j.class.getName () ) ;
3.2.2.讀取配置文件
當得到了日誌記錄器以後,第二步將配置Log4j環境,其語法爲:
BasicConfigurator.configure (): 自動快速地使用缺省Log4j環境。
PropertyConfigurator.configure ( String configFilename) :讀取使用Java的特性文件編寫的配置文件。
DOMConfigurator.configure ( String filename ) :讀取XML形式的配置文件。
3.2.3.插入記錄信息(格式化日誌信息)
當上兩個必要步驟執行完畢,您就能夠輕鬆地使用不一樣優先級別的日誌記錄語句插入到您想記錄日誌的任何地方,其語法以下:
Logger.debug ( Object message ) ;
Logger.info ( Object message ) ;
Logger.warn ( Object message ) ;
Logger.error ( Object message ) ;
若是您想更深刻地瞭解Log4j,請常常訪問下面說起的相關連接。
Log4j項目主頁 www.log4j.org
Log4j FAQ www.log4j.org/log4j/faq.html
-----------------------------------------------------------------------------------------------
log4j日誌配置
關鍵字: apache log4j
一、配置根Logger:
log4j.rootLogger = [ level ] , appenderName, appenderName2
level:日誌的級別,指定這條日誌信息的重要性。分爲ALL < DEBUG < INFO < WARN 通常經常使用的爲
DEBUG , INFO ,WARN ,ERROR四種,分別對應Logger類的四種方法
debug(Object message ) ;
info(Object message ) ;
warn(Object message ) ;
error(Object message ) ;
若是設置級別爲INFO,則優先級大於等於INFO級別(如:INFO、WARN、ERROR)的日誌信息將能夠被輸出,
小於該級別的如:DEBUG將不會被輸出
appenderName :就是指定日誌信息輸出目的地,好比(打印到控制檯,輸出到文件等)。同一條日誌信息
能夠配置多個輸出目的地。
二、配置log輸出目的地:
org.apache.log4j.ConsoleAppender(控制檯)
org.apache.log4j.FileAppender(文件)
org.apache.log4j.DailyRollingFileAppender(天天產生一個日誌文件)
org.apache.log4j.RollingFileAppender(文件大小到達指定尺寸的時候產生一個新的文件)
org.apache.log4j.WriterAppender(將日誌信息以流格式發送到任意指定的地方)
三、log信息的格式:
org.apache.log4j.HTMLLayout(HTML表格形式)
org.apache.log4j.SimpleLayout(簡單格式的日誌,只包括日誌信息的級別和指定的信息字符串 ,如:DEBUG - Hello)
org.apache.log4j.TTCCLayout(日誌的格式包括日誌產生的時間、線程、類別等等信息)
org.apache.log4j.PatternLayout(靈活地自定義日誌格式)
當使用org.apache.log4j.PatternLayout來自定義信息格式時,可使用
log4j.appender.A1.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %p -%m%n 來格式化信息
%c 輸出所屬類的全名,可寫爲 %c{Num} ,Num類名輸出的範圍 如:"com.sun.aaa.classB", %C{2}將使日誌輸出輸出範圍爲:aaa.classB
%d 輸出日誌時間其格式爲 可指定格式 如 %d{HH:mm:ss}等
%l 輸出日誌事件發生位置,包括類目名、發生線程,在代碼中的行數
%n 換行符
%m 輸出代碼指定信息,如info(「message」),輸出message
%p 輸出日誌的優先級,即 FATAL ,ERROR 等
%r 輸出從啓動到顯示該條日誌信息所耗費的時間(毫秒數)
%t 輸出產生該日誌事件的線程名
四、同時使用commons-logging和Log4j
1)首先在classpath下尋找本身的配置文件commons-logging.properties,若是找到,則使用其中定義的
Log實現類
2)若是找不到commons-logging.properties文件,則在查找是否已定義系統環境變量
org.apache.commons.logging.Log,找到則使用其定義的Log實現類
3)不然,查看classpath中是否有Log4j的包,若是發現,則自動使用Log4j做爲日誌實現類
4)不然,使用JDK自身的日誌實現類(JDK1.4之後纔有日誌實現類)
5)不然,使用commons-logging本身提供的一個簡單的日誌實現類SimpleLog
5.多個日誌文件(log4j.rootLogger=INFO, A1 ,A2)
#A2 輸出到文件 RollingFileAppender的擴展,能夠提供一種日誌的備份功能。
log4j.appender.A2=org.apache.log4j.RollingFileAppender
#日誌文件的名稱 log4j.appender.A2.File=log4j.log
#日誌文件的大小 log4j.appender.A2.MaxFileSize=100KB
#保存一個備份文件 log4j.appender.A2.MaxBackupIndex=1
log4j.appender.A2.layout=org.apache.log4j.TTCCLayout
#log4j.appender.A2.layout.ConversionPattern=%-d{yyyy-MM-dd HH:mm:ss} [%c]-[%p] %m%n
附例:(log4j.properties)
例1:
log4j.rootLogger=DEBUG, stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%c{1} - %m%n
例2:
#指定根Logger,及日誌輸出級別,大於等於該級別的日誌將被輸出( DEBUG < INFO < WARN < ERROR < FATAL ) 設爲OFF能夠關閉日誌
log4j.rootLogger=DEBUG, A1,A2
#指定log輸出目的,這裏設爲輸出日誌到指定目錄的文件my.log中
log4j.appender.A1=org.apache.log4j.FileAppender
log4j.appender.A1.File=\\logs\\my.log #當前根目錄下
#指定日誌信息的格式
log4j.appender.A1.layout=org.apache.log4j.PatternLayout
log4j.appender.A1.layout.ConversionPattern=%r %d{yyyy-MM-dd HH:mm:ss} %c %p -%m%n
#把A2輸出到控制檯
log4j.appender.A2=org.apache.log4j.ConsoleAppender
log4j.appender.A2.layout=org.apache.log4j.SimpleLayout
#還能夠單獨指定輸出某個包的日誌級別 #log4j.logger.com.study.HelloLog4j=INFO