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