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