Tomcat 的內(nèi)部日志使用 JULI 組件,這是一個 Apache Commons 日志的重命名的打包分支,默認被硬編碼,使用 java.util.logging
架構。這能保證 Tomcat 內(nèi)部日志與 Web 應用的日志保持獨立,即使 Web 應用使用的是 Apache Commons
Logging。
假如想用另外的日志框架來替換 Tomcat 的內(nèi)部日志系統(tǒng),那么就必須采用一種能夠保持完整的 Commons 日志機制的 JULI 實現(xiàn),用它來替換通過硬編碼使用 java.util.logging
的 JULI 實現(xiàn)。通常這種替代實現(xiàn)都是以額外組件的形式出現(xiàn)的。利用 Log4j 框架用于
Tomcat 內(nèi)部日志的配置如下文所示。
在 Apache Tomcat 上運行的 Web 應用可以使用:
java.util.logging
。javax.servlet.ServletContext.log(...)
。各個應用可以使用不同的日志框架,詳情參見類加載器。java.util.logging
則是例外。如果日志庫直接或間接地用到了這一 API,那么 Web 應用就能共享使用它的元素,因為該 API 是由系統(tǒng)類加載器所加載的。
Apache Tomcat 本身已經(jīng)實現(xiàn)了 java.util.logging
API 的幾個關鍵元素。這種實現(xiàn)就是 JULI。其中的關鍵組件是一個自定義的 LogManager 實現(xiàn),它能分辨運行在 Tomcat 上的不同 Web 應用(以及它們所用的不同的類加載器),還能針對每一應用進行私有的日志配置。另外,當 Web 應用沒能從內(nèi)存中加載時,Tomcat 會給予它相應通知,從而清除相應的引用類,防止內(nèi)存泄露。
在啟動 Java 時,通過提供特定的系統(tǒng)屬性,可以啟用 java.util.logging
實現(xiàn)。Apache Tomcat 啟動腳本可以實現(xiàn)這個操作,但如果使用不同工具來運行 Tomcat(比如 jsvc,或者從某個 IDE 中運行 Tomcat),就必須自己來啟用實現(xiàn)。
關于 java.util.logging
實現(xiàn)的詳細情況可以查閱 JDK 文檔,具體位于 java.util.logging
包的相關 javadoc 頁面中。
關于 Tomcat JULI 的詳細介紹見下文。
Tomcat 內(nèi)部日志能夠處理對 javax.servlet.ServletContext.log(...)
的調(diào)用,從而寫入日志消息。這種消息都被記錄到一種特定類別中,命名方式如下:
org.apache.catalina.core.ContainerBase.[${engine}].[${host}].[${context}]
這種日志是依照 Tomcat 日志配置而執(zhí)行的,無法在 Web 應用中重寫。
Servlets logging API 的問世要先于 Java 所提供的 java.util.logging
API,所以,它無法提供太多的選項,比如無法用它來控制日志級別。然而需要注意的是,在 Tomcat 實現(xiàn)中, 對 ServletContext.log(String)
和 GenericServlet.log(String)
的調(diào)用都被記錄在 INFO 級別。對 ServletContext.log(String, Throwable)
或 GenericServlet.log(String, Throwable)
的調(diào)用都被記錄在
ERROR 級別。
在 UNIX 系統(tǒng)下運行 Tomcat 時,控制臺輸出經(jīng)常會重定向到 catalina.out
的文件中。通過一個環(huán)境變量,可以配置該文件(參見啟動腳本)。
寫入 System.err/out
的任何內(nèi)容都會被 catalina.out
文件所捕獲。這些內(nèi)容可能包括:
java.lang.ThreadGroup.uncaughtException(..)
所輸出的未捕獲異常。在 Windows 上以服務形式運行時,控制臺輸出也會被捕獲及重定向,但文件名有所不同。
Tomcat 默認的日志配置會將同樣的消息寫入控制臺和一個日志文件中。這一特點非常有利于使用 Tomcat 進行開發(fā),但往往并不適用于生產(chǎn)環(huán)境。
老的應用可能還在使用 System.out
或 System.err
,可以通過在 Context 元素上設置 swallowOutput
屬性來調(diào)整。如該屬性設為 true
,那么在請求階段對 System.out/err
的調(diào)用就會被攔截,它們的輸出也會通過 javax.servlet.ServletContext.log(...)
調(diào)用反饋給日志系統(tǒng)。
注意:swallowOutput
雖然是一個小技巧,但還是有局限性的:它需要直接調(diào)用 System.out/err
,并且要在請求處理周期內(nèi)完成。而且,它可能還并不適用于應用所創(chuàng)建的其他線程。不能將其用于攔截本身寫入系統(tǒng)流的日志框架(它們可能早先已經(jīng)啟動,并且在重定向發(fā)生前就已經(jīng)獲取了對流的直接引用)。
Access 日志功能相近,但還是有所不同。它是一個 Valve
,使用自包含的邏輯來編寫日志文件。訪問日志的基本需求是以較低開銷處理大型連續(xù)數(shù)據(jù)流,所以只能使用 Commomns Logging 來處理自身的調(diào)試消息。這種實現(xiàn)方法避免了額外的開銷,并且可能具有較復雜的配置。請參考 Valves 文檔了解更多配置詳情,其中包含了各種報告格式。
JDK 所提供的默認 java.util.logging 實現(xiàn)功能太過局限,所以根本沒有什么使用價值。其關鍵局限在于不能實現(xiàn)針對每一應用進行日志記錄,因為配置是針對每一 VM 的。所以按照默認配置,Tomcat 會用 JULI 這種非常適用于容器的實現(xiàn)來代替默認的 LogManager 實現(xiàn),從而避免了 LogManager 的缺點。
跟標準 JDK 的 java.util.logging
一樣,JULI 也支持同樣的配置機制,或者使用編程方式,或者指定屬性值。它與 java.util.logging
的不同在于,它可以分別設置每一個類加載器屬性文件(能夠啟用簡單的、便于重新部署的應用配置),屬性文件還支持擴展構造,能夠更加自由地定義 handle 并將其指定給 logger。
JULI 是默認啟用的,除了普通的全局 java.util.logging 配置之外,它支持每個類加載器配置。這意味著可以在下列層級來配置日志:
${catalina.base}/conf/logging.properties
文件。該文件通過由啟動腳本設置的系統(tǒng)屬性 java.util.logging.config.file
來指定。如果它不可讀或沒有配置,默認采用 JRE 中的 ${java.home}/lib/logging.properties
文件。WEB-INF/classes/logging.properties
。JRE 中默認的 logging.properties
指定了 ConsoleHandler
,用于將日志輸出至 System.err
。Tomcat 中默認的 conf/logging.properties
也添加了幾個能夠?qū)懭胛募?FileHandlers
。
handler 的日志級別容差值默認為 INFO,取值范圍為:SEVERE、WARNING、INFO、CONFIG、FINE、FINER、FINEST 或 ALL。你也可以從特殊的包中收集日志,然后為這種日志指定相應的級別。
為了啟用 部分 Tomcat 內(nèi)部的調(diào)試日志功能,應該配置適合的 logger 和 handle 來使用 FINEST
或 ALL
級別。比如:
org.apache.catalina.session.level=ALL
java.util.logging.ConsoleHandler.level=ALL
當啟用調(diào)試日志功能時,建議將范圍盡量縮小,因為該功能會產(chǎn)生大量信息。
JULI 所使用的配置與純 java.util.logging
所支持的配置基本相同,只不過使用了一些擴展,以便更靈活地配置 logger 和 handler。主要的差別在于:
.
結(jié)尾。比如 22foobar.
就是個有效的前綴。還有一些額外的實現(xiàn)類,它們可以與 Java 所提供的類一起使用。在這些類中,最著名的就是 org.apache.juli.FileHandler
。
org.apache.juli.FileHandler
支持日志緩存。日志緩存默認是沒有啟用的。使用 handler 的 bufferSize
屬性可以配置它:屬性值為 0
時,代表使用系統(tǒng)默認的緩存(通常使用 8k 緩存);屬性值小于 0 時,將在每個日志寫入上強制使用 writer flush(將緩存區(qū)中的數(shù)據(jù)強制寫出到系統(tǒng)輸出)功能;屬性值大于 0 時,則使用帶有定義值的 BufferedOutputStream 類——但要注意的是,這也將應用于系統(tǒng)默認的緩存。
以下是一個 $CATALINA_BASE/conf
中的 logging.properties
文件:
handlers = 1catalina.org.apache.juli.FileHandler, \
2localhost.org.apache.juli.FileHandler, \
3manager.org.apache.juli.FileHandler, \
java.util.logging.ConsoleHandler
.handlers = 1catalina.org.apache.juli.FileHandler, java.util.logging.ConsoleHandler
############################################################
# Handler specific properties.
# Describes specific configuration info for Handlers.
############################################################
1catalina.org.apache.juli.FileHandler.level = FINE
1catalina.org.apache.juli.FileHandler.directory = ${catalina.base}/logs
1catalina.org.apache.juli.FileHandler.prefix = catalina.
2localhost.org.apache.juli.FileHandler.level = FINE
2localhost.org.apache.juli.FileHandler.directory = ${catalina.base}/logs
2localhost.org.apache.juli.FileHandler.prefix = localhost.
3manager.org.apache.juli.FileHandler.level = FINE
3manager.org.apache.juli.FileHandler.directory = ${catalina.base}/logs
3manager.org.apache.juli.FileHandler.prefix = manager.
3manager.org.apache.juli.FileHandler.bufferSize = 16384
java.util.logging.ConsoleHandler.level = FINE
java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter
############################################################
# Facility specific properties.
# Provides extra control for each logger.
############################################################
org.apache.catalina.core.ContainerBase.[Catalina].[localhost].level = INFO
org.apache.catalina.core.ContainerBase.[Catalina].[localhost].handlers = \
2localhost.org.apache.juli.FileHandler
org.apache.catalina.core.ContainerBase.[Catalina].[localhost].[/manager].level = INFO
org.apache.catalina.core.ContainerBase.[Catalina].[localhost].[/manager].handlers = \
3manager.org.apache.juli.FileHandler
# For example, set the org.apache.catalina.util.LifecycleBase logger to log
# each component that extends LifecycleBase changing state:
#org.apache.catalina.util.LifecycleBase.level = FINE
下例是一個用于 servlet-examples 應用的 WEB-INF/classes
中的 logging.properties
文件:
handlers = org.apache.juli.FileHandler, java.util.logging.ConsoleHandler
############################################################
# Handler specific properties.
# Describes specific configuration info for Handlers.
############################################################
org.apache.juli.FileHandler.level = FINE
org.apache.juli.FileHandler.directory = ${catalina.base}/logs
org.apache.juli.FileHandler.prefix = ${classloader.webappName}.
java.util.logging.ConsoleHandler.level = FINE
java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter
查看下列資源獲取額外的詳細信息:
可能需要注意以下方面:
ConsoleHandler
從配置中移除。默認(多謝 .handlers
設置)日志會使用 FileHandler
和 ConsoleHandler
。后者的輸出經(jīng)常會被捕獲到一個文件中,比如 catalina.out
。從而導致同一消息可能生成了兩個副本。host-manager
),可以考慮將 FileHandlers
移除。encoding
屬性可以修改設置,詳情查看相關的 javadoc 文檔。前面介紹了用于 Tomcat 內(nèi)部日志的 java.util.logging,接下來本部分內(nèi)容介紹如何通過配置 Tomcat 使用 log4j。
注意:當你想重新配置 Tomcat 以便利用 log4j 來進行自身日志記錄時,下面的步驟都是必需的;而當你只是想在自己的 Web 應用上使用 log4j 時,這些步驟則不是必需的。在后一種情況下,只需將 log4j.jar
和 log4j.properties
放到 Web 應用的 WEB-INF/lib
和 WEB-INF/classes
中即可。
通過下列步驟可配置 log4j 輸出 Tomcat 的內(nèi)部日志:
1.創(chuàng)建一個包含下列配置的 log4j.properties
文件,將其保存到 $CATALINA_BASE/lib
。
log4j.rootLogger = INFO, CATALINA
# Define all the appenders
log4j.appender.CATALINA = org.apache.log4j.DailyRollingFileAppender
log4j.appender.CATALINA.File = ${catalina.base}/logs/catalina
log4j.appender.CATALINA.Append = true
log4j.appender.CATALINA.Encoding = UTF-8
# Roll-over the log once per day
log4j.appender.CATALINA.DatePattern = '.'yyyy-MM-dd'.log'
log4j.appender.CATALINA.layout = org.apache.log4j.PatternLayout
log4j.appender.CATALINA.layout.ConversionPattern = %d [%t] %-5p %c- %m%n
log4j.appender.LOCALHOST = org.apache.log4j.DailyRollingFileAppender
log4j.appender.LOCALHOST.File = ${catalina.base}/logs/localhost
log4j.appender.LOCALHOST.Append = true
log4j.appender.LOCALHOST.Encoding = UTF-8
log4j.appender.LOCALHOST.DatePattern = '.'yyyy-MM-dd'.log'
log4j.appender.LOCALHOST.layout = org.apache.log4j.PatternLayout
log4j.appender.LOCALHOST.layout.ConversionPattern = %d [%t] %-5p %c- %m%n
log4j.appender.MANAGER = org.apache.log4j.DailyRollingFileAppender
log4j.appender.MANAGER.File = ${catalina.base}/logs/manager
log4j.appender.MANAGER.Append = true
log4j.appender.MANAGER.Encoding = UTF-8
log4j.appender.MANAGER.DatePattern = '.'yyyy-MM-dd'.log'
log4j.appender.MANAGER.layout = org.apache.log4j.PatternLayout
log4j.appender.MANAGER.layout.ConversionPattern = %d [%t] %-5p %c- %m%n
log4j.appender.HOST-MANAGER = org.apache.log4j.DailyRollingFileAppender
log4j.appender.HOST-MANAGER.File = ${catalina.base}/logs/host-manager
log4j.appender.HOST-MANAGER.Append = true
log4j.appender.HOST-MANAGER.Encoding = UTF-8
log4j.appender.HOST-MANAGER.DatePattern = '.'yyyy-MM-dd'.log'
log4j.appender.HOST-MANAGER.layout = org.apache.log4j.PatternLayout
log4j.appender.HOST-MANAGER.layout.ConversionPattern = %d [%t] %-5p %c- %m%n
log4j.appender.CONSOLE = org.apache.log4j.ConsoleAppender
log4j.appender.CONSOLE.Encoding = UTF-8
log4j.appender.CONSOLE.layout = org.apache.log4j.PatternLayout
log4j.appender.CONSOLE.layout.ConversionPattern = %d [%t] %-5p %c- %m%n
# Configure which loggers log to which appenders
log4j.logger.org.apache.catalina.core.ContainerBase.[Catalina].[localhost] = INFO, LOCALHOST
log4j.logger.org.apache.catalina.core.ContainerBase.[Catalina].[localhost].[/manager] =\
INFO, MANAGER
log4j.logger.org.apache.catalina.core.ContainerBase.[Catalina].[localhost].[/host-manager] =\
INFO, HOST-MANAGER
2.下載 log4j(Tomcat 需要 1.2.x 版本)。
3.下載或構建 tomcat-juli.jar
和 tomcat-juli-adapters.jar
,以便作為 Tomcat 的額外組件使用。詳情參考 Additional Components documentation。
`tomcat-juli.jar` 跟默認的版本不同。它包含所有的 Commons Logging 實現(xiàn),從而能夠發(fā)現(xiàn) log4j 并配置自身。
4.如果希望全局性地使用 log4j,則如下配置 Tomcat:
log4j.jar
和 tomcat-juli-adapters.jar
從 extras 中放入 $CATALINA_HOME/lib
中。tomcat-juli.jar
替換 $CATALINA_HOME/bin/tomcat-juli.jar
。5.如果是利用獨立的 $CATALINA_HOME
和 $CATALINA_BASE
來運行 Tomcat,并想在一個 $CATALINA_BASE
中配置使用 log4j,則需要:
$CATALINA_BASE/bin
和 $CATALINA_BASE/lib
目錄——如果它們不存在的話。log4j.jar
與 tomcat-juli-adapters.jar
從 extras 放入 $CATALINA_BASE/lib
中。tomcat-juli.jar
轉(zhuǎn)換成 $CATALINA_BASE/bin/tomcat-juli.jar
。如果使用安全管理器運行,則需要編輯 $CATALINA_BASE/conf/catalina.policy
文件來修改它,以便使用不同版本的 tomcat-juli.jar
。
注意:其中的工作原理在于:優(yōu)先將庫加載到 $CATALINA_HOME
中同樣的庫中。
注意:tomcat-juli.jar
之所以從 $CATALINA_BASE
/bin 加載(而不是從 $CATALINA_BASE
/lib 加載),是因為它是用作引導進程的,而引導類都是從 bin 加載的。
6.刪除 $CATALINA_BASE/conf/logging.properties
,以防止 java.util.logging
生成零長度的日志文件。
7.啟動 Tomcat。
log4j 配置沿用了默認的 java.util.logging 設置:管理器與主機管理器應用各自獲得了獨立的日志文件,而所有其余內(nèi)容都發(fā)送到 catalina.log
日志文件中。
你可以(也應該)更加挑剔地選擇日志所包括的包。Tomcat 使用 Engine 和 Host 名稱來定義 logger。比如,要想得到更詳細的 Catalina localhost log,可以將它放在 log4j.properties
屬性中。注意,在 log4j 基于 XML 的配置文件的命名慣例上,目前存在一些問題,所以建議使用所前所述的屬性文件,直到未來版本的 log4j 允許使用這種慣例。
log4j.logger.org.apache.catalina.core.ContainerBase.[Catalina].[localhost]=DEBUG
log4j.logger.org.apache.catalina.core=DEBUG
log4j.logger.org.apache.catalina.session=DEBUG
警告:設定為 DEBUG 級別,會產(chǎn)生數(shù)以兆計的日志,從而拖慢 Tomcat 的啟動。只有當需要調(diào)試 Tomcat 內(nèi)部操作,才應該使用這一級別。
你的 Web 應用當然應該使用各自的 log4j 配置。上面的配置是有效的。你可以將相似的 log4j.properties
文件放到你的 Web 應用的 WEB-INF/classes
目錄中,將 log4jx.y.z.jar 放入 WEB-INF/lib
中。 然后指定包級別日志。這是基本的 log4j 配置方法,不需要 Commons-Logging。更多選項可參考 log4j 文檔,該頁面只是一種引導指南。
額外注意:
java.util.logging
API 仍適用于直接使用它的 Web 應用。${catalina.base}/conf/logging.properties
文件仍然可被 Tomcat 啟動腳本所引用。詳情可查看本頁的簡介部分。
如前面相關步驟所述,刪除了 ${catalina.base}/conf/logging.properties
文件,會導致 java.util.logging
回退到 JRE 默認的配置,從而使用 ConsoleHandler,然而卻不創(chuàng)建任何標準日志文件。所以必須確保:在禁止標準機制之前,所有的日志文件必須是由 log4j 創(chuàng)建的。
更多建議: