原文連接
原做者:Rohit Joshi
譯者:smallclover
我的翻譯,水平有限,若有錯誤歡迎指出,謝謝!java
在本文中,咱們將討論關於Java的日誌(logging
)功能。日誌,用簡單的話來講就是記錄應用程序的活動。日誌一般被用於存儲異常(exceptions
)、信息(information
)、警告(warnings
)的消息,這些消息可能會出如今程序的整個執行過程。日誌在程序員調式(debug
)程序的過程當中會有所幫助。程序員
Java 包(package)java.util.logging
與日誌記錄的功能有關。這個包由一些用於日誌功能的類(class)和接口(interface)組成。系統使用Logger
對象(object)來記錄消息。windows
這個Logger
對象會被分配一個LogRecord
對象,該LogRecord
對象存儲了記錄的消息。這個LogRecord
對象會被轉發到全部的handler,再由handler分派給Logger
對象。logger和handler能夠視須要使用一個與它們有關聯的過濾器(Filter
)來過濾日誌消息。而後,handler會發布這些被日誌記錄的消息到外部的系統。網絡
讓咱們從這個包中一些比較重要的類開始。框架
建立一個Logger
類的logger對象來記錄消息。logger對象會要求使用者提供一個名稱和一組用於設置記錄消息的等級的方法。雖然你能夠提供任何一個名字到logger,可是建議使用包和類名來建立logger。
Level類提供7種日誌級別ide
SEVERE (最高級別)函數
WARNINGthis
INFOspa
CONFIG翻譯
FINE
FINER
FINEST (最低級別)
在Level
中全部的級別(level)都被定義成靜態常量字段(static final field
)。你能使用任何一個級別,而後根據這些級別來記錄消息。另外,它還提供了一個level OFF
能夠關閉日誌記錄,一個level All
用於打開全部級別的日誌。
咱們看一個關於如何建立和使用logger的示例。
LoggerExample.java
01 package com.javacodegeeks.corejava.util.logging; 02 03 import java.io.IOException; 04 import java.util.logging.Level; 05 import java.util.logging.Logger; 06 07 public class LoggerExample { 08 09 private static final Logger LOGGER = Logger.getLogger(LoggerExample.class.getName()); 10 public static void main(String[] args) throws SecurityException, IOException { 11 12 LOGGER.info("Logger Name: "+LOGGER.getName()); 13 14 LOGGER.warning("Can cause ArrayIndexOutOfBoundsException"); 15 16 //An array of size 3 17 int []a = {1,2,3}; 18 int index = 4; 19 LOGGER.config("index is set to "+index); 20 21 try{ 22 System.out.println(a[index]); 23 }catch(ArrayIndexOutOfBoundsException ex){ 24 LOGGER.log(Level.SEVERE, "Exception occur", ex); 25 } 26 27 28 } 29 30 }
若是咱們運行以上代碼,咱們將獲得以下結果:
1 Jun 08, 2014 1:19:30 PM com.javacodegeeks.corejava.util.logging.LoggerExample main 2 INFO: Logger Name: com.javacodegeeks.corejava.util.logging.LoggerExample 3 Jun 08, 2014 1:19:31 PM com.javacodegeeks.corejava.util.logging.LoggerExample main 4 WARNING: Can cause ArrayIndexOutOfBoundsException 5 Jun 08, 2014 1:19:31 PM com.javacodegeeks.corejava.util.logging.LoggerExample main 6 SEVERE: Exception occur 7 java.lang.ArrayIndexOutOfBoundsException: 4 8 at com.javacodegeeks.corejava.util.logging.LoggerExample.main(LoggerExample.java:22)
在上面這個示例中,咱們使用getLogger
靜態方法(static method)建立了一個logger對象。而後,咱們記錄了不一樣級別的日誌消息。爲了闡述Logger
的使用咱們也嘗試拋出了ArrayIndexOutOfBoundsException
。
讓咱們看一看在本例中使用的方法。
Logger.getLogger(String name):該方法經過傳遞的name參數來建立或者發現一個logger。
void info(String msg):該實例方法用於記錄INFO級別的日誌消息,可是前提是當前的logger可以使用INFO級別的日誌消息,不然該級別的日誌消息將會被忽略。
void warning(String msg): 該實例方法用於記錄WARNING級別的日誌消息,可是前提是當前的logger可以使用INFO級別的日誌消息,不然該級別的日誌消息將會被忽略。
void config(String msg): 該實例方法用於記錄CONFIG級別的日誌消息,可是前提是當前的logger可以使用INFO級別的日誌消息,不然該級別的日誌消息將會被忽略。
void log(Level level, String msg, Object param1):該方法根據傳遞的日誌級別來記錄消息,同時傳遞的參數還有一個object。當你想存儲一個對象在日誌中的時候你可以使用這個方法。正如咱們上面的示例同樣,咱們記錄了一個SEVERE級別的exception object。
請注意,INFO級別是logger的默認級別。全部低於INFO級別的消息記錄將會被忽略。正如你所看到的那樣,WARNING級別的消息記錄被忽略了,並無被打印在控制檯上。(此處原文可能有誤)
譯者注:這裏原文可能有錯誤,首先WARNING的級別是高於INFO級別的,其次WARNING級別的日誌的確打印在控制檯上。因此,譯者認爲這裏應該是CONFIG級別。請讀者注意。
Handler是日誌框架的組件之一,它負責打印日誌消息到目標目的地。這個目的地能夠是控制檯(console)也能夠是文件(file)。Handler
得到一個LogRecord
對象形式的日誌消息,並輸出到目標目的地。一個Logger
能夠關聯一個或者多個Handler
,最後將日誌消息轉發給全部的Handler
。Handler
在Java 包 java.util.logging
中是一個抽象類,同時它也是各類Handler
的父類。
在Java中內置4種handler。
ConsoleHandler: ConsoleHandler 記錄全部的System.in的日誌消息,默認狀況下,Logger是與此Handler相關聯的。
FileHandler: FileHandler 記錄全部的來自特定的文件或者一組文件集合的日誌消息。
StreamHandler: StreamHandler會發布全部的日誌消息到一個OutputStream.
SocketHandler: SocketHandler會發布LogRecords到一個網絡鏈接流中。
MemoryHandler: 它是用來保持LogRecords內存緩衝區。若是緩衝區滿了,新的LogRecords會覆蓋舊的LogRecords。
HandlerExample.java
01 package com.javacodegeeks.corejava.util.logging; 02 03 import java.io.IOException; 04 import java.util.logging.ConsoleHandler; 05 import java.util.logging.FileHandler; 06 import java.util.logging.Handler; 07 import java.util.logging.Level; 08 import java.util.logging.Logger; 09 10 public class HandlerExample { 11 12 private static final Logger LOGGER = Logger.getLogger(LoggerExample.class.getName()); 13 public static void main(String[] args) { 14 15 Handler consoleHandler = null; 16 Handler fileHandler = null; 17 try{ 18 //Creating consoleHandler and fileHandler 19 consoleHandler = new ConsoleHandler(); 20 fileHandler = new FileHandler("./javacodegeeks.log"); 21 22 //Assigning handlers to LOGGER object 23 LOGGER.addHandler(consoleHandler); 24 LOGGER.addHandler(fileHandler); 25 26 //Setting levels to handlers and LOGGER 27 consoleHandler.setLevel(Level.ALL); 28 fileHandler.setLevel(Level.ALL); 29 LOGGER.setLevel(Level.ALL); 30 31 LOGGER.config("Configuration done."); 32 33 //Console handler removed 34 LOGGER.removeHandler(consoleHandler); 35 36 LOGGER.log(Level.FINE, "Finer logged"); 37 }catch(IOException exception){ 38 LOGGER.log(Level.SEVERE, "Error occur in FileHandler.", exception); 39 } 40 41 LOGGER.finer("Finest example on LOGGER handler completed."); 42 43 } 44 45 }
若是咱們運行以上代碼,咱們將會獲得如下結果:
1 Jun 08, 2014 1:43:19 PM com.javacodegeeks.corejava.util.logging.HandlerExample main 2 CONFIG: Configuration done.
該示例還會在項目的根目錄下生成日誌文件javacodegeeks.log。
該文件包含如下記錄:
01 <?xml version="1.0" encoding="windows-1252" standalone="no"?> 02 <!DOCTYPE log SYSTEM "logger.dtd"> 03 <log> 04 <record> 05 <date>2014-06-08T13:43:19</date> 06 <millis>1402215199326</millis> 07 <sequence>0</sequence> 08 <logger>com.javacodegeeks.corejava.util.logging.LoggerExample</logger> 09 <level>CONFIG</level> 10 <class>com.javacodegeeks.corejava.util.logging.HandlerExample</class> 11 <method>main</method> 12 <thread>1</thread> 13 <message>Configuration done.</message> 14 </record> 15 <record> 16 <date>2014-06-08T13:43:19</date> 17 <millis>1402215199376</millis> 18 <sequence>1</sequence> 19 <logger>com.javacodegeeks.corejava.util.logging.LoggerExample</logger> 20 <level>FINE</level> 21 <class>com.javacodegeeks.corejava.util.logging.HandlerExample</class> 22 <method>main</method> 23 <thread>1</thread> 24 <message>Finer logged</message> 25 </record> 26 <record> 27 <date>2014-06-08T13:43:19</date> 28 <millis>1402215199376</millis> 29 <sequence>2</sequence> 30 <logger>com.javacodegeeks.corejava.util.logging.LoggerExample</logger> 31 <level>FINER</level> 32 <class>com.javacodegeeks.corejava.util.logging.HandlerExample</class> 33 <method>main</method> 34 <thread>1</thread> 35 <message>Finest example on LOGGER handler completed.</message> 36 </record> 37 </log>
在該示例中,咱們經過FileHandler
和ConsoleHandler記錄日誌消息。
咱們將討論上面的示例。
ConsoleHandler():構造函數,建立一個與system.err有關的ConsoleHandler
FileHandler(String pattern):構造函數,建立一個FileHandler,記錄消息到指定文件。
void addHandler(Handler handler):該實例方法來自類Logger,分配一個handler給logger對象。你也能夠分配多個handler給一個logger對象。就像該示例同樣,咱們分配了ConsoleHandler 和 FileHandler給了一個logger對象。
void setLevel(Level newLevel):Logger和Handler類都有該方法,logger對象經過它來設置指定的日誌級別,規定哪些級別的消息能夠被記錄。消息級別小於指定的級別的將會被忽略。
void removeHandler(Handler handler):該方法會移除與logger對象相關聯的handler,一旦該handler被移除,它將沒有能力發佈任何日誌消息。在該示例中,咱們移除了ConsoleHandler以後,接下來全部的日誌消息將不會被打印在控制檯。
void finer(String msg):該示例方法用來記錄FINER級別的消息,若是當前容許FINER級別的日誌消息則記錄,不然忽略。
該日誌消息經過FileHandler 發佈,在上面的示例中被髮布爲XML格式。該格式是FileHandler 的默認格式,咱們能夠改變該handler 的格式。
在下一節中,咱們將討論關於Formatter
類和它的使用。
Formatter
用於格式化LogRecord
。每一個handler會關聯一個formatter。Java提供了兩個內置的超類formatter:SimpleFormatter
和 XMLFormatter
。讓咱們來看一些示例:
FormatterExample.java
01 package com.javacodegeeks.corejava.util.logging; 02 03 import java.io.IOException; 04 import java.util.logging.Formatter; 05 import java.util.logging.FileHandler; 06 import java.util.logging.Handler; 07 import java.util.logging.Level; 08 import java.util.logging.Logger; 09 import java.util.logging.SimpleFormatter; 10 11 public class FormatterExample { 12 13 private static final Logger LOGGER = Logger.getLogger(LoggerExample.class.getName()); 14 public static void main(String[] args) { 15 16 Handler fileHandler = null; 17 Formatter simpleFormatter = null; 18 try{ 19 20 // Creating FileHandler 21 fileHandler = new FileHandler("./javacodegeeks.formatter.log"); 22 23 // Creating SimpleFormatter 24 simpleFormatter = new SimpleFormatter(); 25 26 // Assigning handler to logger 27 LOGGER.addHandler(fileHandler); 28 29 // Logging message of Level info (this should be publish in the default format i.e. XMLFormat) 30 LOGGER.info("Finnest message: Logger with DEFAULT FORMATTER"); 31 32 // Setting formatter to the handler 33 fileHandler.setFormatter(simpleFormatter); 34 35 // Setting Level to ALL 36 fileHandler.setLevel(Level.ALL); 37 LOGGER.setLevel(Level.ALL); 38 39 // Logging message of Level finest (this should be publish in the simple format) 40 LOGGER.finest("Finnest message: Logger with SIMPLE FORMATTER"); 41 }catch(IOException exception){ 42 LOGGER.log(Level.SEVERE, "Error occur in FileHandler.", exception); 43 } 44 } 45 46 }
若是咱們運行以上代碼,咱們將獲得如下結果:
1 Jun 08, 2014 4:57:02 PM com.javacodegeeks.corejava.util.logging.FormatterExample main 2 INFO: Finnest message: Logger with DEFAULT FORMATTER
該示例也會在項目的根目錄下生成一個日誌文件:javacodegeeks.formatter.log。
在上面的示例中,咱們使用SimpleFormatter
以一種簡單的,可讀的格式打印LogRecord
。請注意在設置handler的格式爲 SimpleFormatter
以前,咱們的消息會發布到一個XML格式的文件中。由於FileHandler
的默認格式是XMLFormatter
。同時還要注意這個LogRecord
也會被髮布到控制檯,由於 ConsoleHandler
和 Logger
是默認關聯的。
SimpleFormatter():這個構造函數用來建立一個SimpleFormatter對象.
void setFormatter(Formatter newFormatter):這個方法來自handler類,handler經過它設置formatter。
Filter
接口(interface)位與java.util.logging
包下。 Handler
經過它來控制消息的記錄。每個Logger
和Handler
能夠選擇一個Filter
。Filter
有一個isLoggable
方法,該方法返回一個boolean
值。在Logger
或者Handler
發佈消息以前會調用此方法,若是返回值爲true就發佈消息,不然就忽略。
FilterExample.java
01 package com.javacodegeeks.corejava.util.logging; 02 03 import java.util.logging.Filter; 04 import java.util.logging.LogRecord; 05 import java.util.logging.Logger; 06 07 public class FilterExample implements Filter{ 08 09 private static final Logger LOGGER = Logger.getLogger(LoggerExample.class.getName()); 10 public static void main(String[] args) { 11 //Setting filter FilterExample 12 LOGGER.setFilter(new FilterExample()); 13 //Since this message string does not contain the word important. Despite of being the Level SEVERE this will be ignored 14 LOGGER.severe("This is SEVERE message"); 15 //This will get published 16 LOGGER.warning("This is important warning message"); 17 18 } 19 20 // This method will return true only if the LogRecord object contains the message which contains the word important 21 @Override 22 public boolean isLoggable(LogRecord record) { 23 if(record == null) 24 return false; 25 26 String message = record.getMessage()==null?"":record.getMessage(); 27 28 if(message.contains("important")) 29 return true; 30 31 return false; 32 } 33 34 }
若是咱們運行以上代碼,咱們將獲得如下的結果:
1 Jun 08, 2014 5:13:46 PM com.javacodegeeks.corejava.util.logging.FilterExample main 2 WARNING: This is important warning message
boolean isLoggable(LogRecord record):該方法來自Filter的接口,它會檢查LogRecord是否能夠發佈。
void setFilter(Filter newFilter): 該方法設置一個 Filter 控制 Logger的輸出。
你能夠經過一個配置文件把配置的屬性提供給Logger
。這有助於你移除配置代碼而且提供一種更加簡單的方法在不改變代碼的狀況下一次又一次的更改配置。經過類LogManager
咱們可使用這種靈活的方式。
ConfigurationExample.java
01 package com.javacodegeeks.corejava.util.logging; 02 03 import java.io.FileInputStream; 04 import java.io.IOException; 05 import java.util.logging.Level; 06 import java.util.logging.LogManager; 07 import java.util.logging.Logger; 08 09 public class ConfigurationExample { 10 11 private static final LogManager logManager = LogManager.getLogManager(); 12 private static final Logger LOGGER = Logger.getLogger("confLogger"); 13 static{ 14 try { 15 logManager.readConfiguration(newFileInputStream("./javacodegeeks.properties")); 16 } catch (IOException exception) { 17 LOGGER.log(Level.SEVERE, "Error in loading configuration",exception); 18 } 19 } 20 public static void main(String[] args) { 21 LOGGER.fine("Fine message logged"); 22 } 23 }
該示例讀取了包含如下屬性的屬性文件:
屬性文件
1 handlers=java.util.logging.ConsoleHandler 2 .level=ALL 3 java.util.logging.ConsoleHandler.level=ALL 4 java.util.logging.ConsoleHandler.formatter=java.util.logging.SimpleFormatter 5 confLogger.level=ALL
若是運行以上代碼,咱們將得到如下結果:
1 Jun 08, 2014 5:23:25 PM com.javacodegeeks.corejava.util.logging.ConfigurationExample main 2 FINE: Fine message logged
讓咱們討論該示例的代碼和它所配置的屬性。
handlers: 設置全部的logger使用默認的handler。
.level:設置全部logger的默認日誌級別,值ALL表示開啓全部級別的日誌消息。
java.util.logging.ConsoleHandler.level: 設置全部ConsoleHandler 的默認日誌級別爲ALL,即對於ConsoleHandler開啓全部級別的日誌消息。
java.util.logging.ConsoleHandler.formatter: 設置 ConsoleHandler 的默認格式爲SimpleFormatter.
confLogger.level: 設置名稱爲confLogger的默認級別爲開啓全部的級別的日誌消息。
須要注意的是這些屬性均可以在代碼中被覆蓋。
LogManager.getLogManager():該方法是一個靜態方法,用於獲取LogManager對象。該LogManager對象是全局的,用來維護一組共享狀態和日誌服務。
void readConfiguration(InputStream ins):該方法被用來從新初始化日誌記錄的屬性,經過從stream中從新讀取日誌配置,該配置應該符合java.util.Properties
的格式
你能夠從這裏下載這個示例的源代碼:LoggingExample.zip
失敗是成功之母。
failure is mother of success.
失敗は成功の母。