Tea

导航

Apache Tomcat 7 (22) –Logging in Tomcat

Posted on 2012-09-25 22:04  liuyf8688  阅读(2339)  评论(0编辑  收藏  举报

原地址:http://tomcat.apache.org/tomcat-7.0-doc/logging.html#Introduction

1.介绍

Apache Tomcat中的日志是通过借助Apache Commons Logging库实现的。这个库对不同的日志框架做了一个简单包装。使Tomcat有能力记录跨日志级别的多层次日志,而且不需要依赖特定的日志框架。

从Tomcat 6.0开始,Tomcat引入一个对Apache Commons Logging重命名包后的私有实现,从而允许web应用使用他们自己独立的原Apache Commons Logging库的lib包。在默认的发布包中,Apache Commons Logging私有实现是简单被硬编码到java.util.logging框架。

为了替换Tomcat内部默认的日志框架,需要做的是用一个全实现jar包来替换默认的jar。这个jar是以扩展组件的形式提供的。接下来介绍如何用Log4j框架来替换内部默认的日志框架。

运行在Apache Tomcat中的web应用可以:

  1. 使用系统日志API,java.util.logging。
  2. 使用Java Servlet规范提供的日志API,javax.servlet.ServletContext.log(…)
  3. 使用所选择的任意框架

不同的web应用使用彼此独立的日志框架。参见class loading了解更多细节。这个规则的例外的情况是java.util.logging,会直接或间接使用你的日志类库。这是因为他被系统加载且被web应用共享。

 

1.1 java日志API – java.util.logging

Apache Tomcat由一个自己的实现了java.util.logging多个关键元素的实现。这个实现被称为“JULI”。实现的核心组件是定制化的LogManager,可以获取运行在Tomcat中的不同web应用(以及不同的class loader)。他支持为应用配置单独的日志配置。当有web应用从内在中是被卸载时,会接到Tomcat的通知,以便他所引用的类可以被清除,避免内存泄露。

这个java.util.logging实现可以通过在启动Java提供一个系统属性来启用。Apache Tomcat的默认脚本中已经加入了这个属性,如果你是使用其它工具来运行Tomcat(例如,jsvc或在IDE中运行Tomcat),你需要自己设置。

更多关于java.util.logging的细节可以查阅JDK文档或java.util.logging docs。

接下来会介绍更多关于Tomcat JULI的细节。

1.2 Servlets logging API

Tomcat内部的日志框架会调用javax.servlet.ServletContext.log(…)来写日志信息。这样的信息是被记录以下命的目录中的

org.apache.catalina.core.ContainerBase.[${engine}].[${host}].[${context}]

这是个日志会根据Tomcat日志配置来执行。在web application不能重载他。

Servlets logging API早于java.util.logging API。同样的,他也没有提供更多的选项。例如,不能控制日志级别。尽管有人会提到在Apache Tomcat实现中调用ServletContext.log(String)或GenericServlet.log(String)是可以记录INFO级别的。调用ServletContext.log(String, Throwable)或GenericServlet.log(String, Throwable)是可以记录ERROR级别。

1.3 console

在类Unix的系统中运行Tomcat,控制台输入通常会被重定向到catalina.out文件中。文件名称是可以通过一个环境变量配置的(查看startup脚本)。所有写到System.err/out中的信息都会被捕捉到写入到这个文件。包括:

  1. 通过java.lang.ThreadGroup.uncaughtException(…)打印的未被捕获的异常信息
  2. 请求导出的线程运行信息

当运行作为一个Windows服务时,控制台输出也是被捕获并重定向,但文件名是不同的。Apache Tomcat默认的日志配置写相同的日志到控制台和日志文件。当使用Tomcat作为开发时,这一点非常好,但通常生产环境不需要这样做。

仍然在使用System.out或System.err的一些老的应用可以使用Context的swallowOuptput属性来设置。如果这个属性被设置为true,在请求处理中调用的System.out/err将会被拦截,并通过javax.servlet.ServletContext.log(…)提供给日志系统。

Note:swallowOutput属性实现是一个小技巧,存在一定限制。直接调用System.out/err时他才会起作用,且仅在请求处理周期内。对于应用创建的别的线程,不起作用。而且不能被用来拦截日志框架本身写到系统输出流中的情况,因为在重定向发生前他们已经开始或包含了一个流的直接引用。

1.4 Access logging

相关,但不同特性是访问日志。他可以被设置成Context或Host或Engine的一个值。参见:Values文档获取更多细节。

2. 使用java.util.logging(默认)

JDK提供的java.util.logging的默认实现也是有限制的。JDK日志API的显示出没有能力单独处理web应用的日志,由于同一个VM只有一份日志。导致的结果,默认配置情况下,Tomcat用一个对容器有利叫做JULI的实现替换默认的LogManager实现,来解决这些问题。他支持和标准JDK中java.util.logging相同的配置,既可以使用编程实现,也可以是配置文件。主要的区别是可以设置每个classloader配置文件(使web应用配置可以很容易实现重新部署),属性文件支持细小的扩展,允许自由的定义handler和给他们分配logger。

JULI默认被启用,支持每个classloader配置,另外支持正常的全局java.util.logging配置。这意味着日志可以在以下各层面配置:

  1. 全局。通常是使用${catalina.base}/conf/logging.properites文件。这个文件是通过在startup脚本中的java.util.logging.config.file系统属性来设置的。如果不可读或没有被配置,默认是使用JRE中的${java.home}/lib/logging.properties文件。
  2. 在web应用中。这个文件将是WEB-INF/classes/logging.properties

在JRE中默认的logging.properties文件指定了一个ConsoleHandler来转发logging到System.err。在Apache Tomcat的默认配置文件conf/logging.properites文件中也加入了多个FileHandler来写入到文件。

Hander的默认的日志级别是INFO,可用的有SEVERE,WARNING,INFO,CONFIG,FINE,FINER,FINEST或ALL。也可以为指定的包设置日志级别。

接下来介绍如何将Tomcat日志级别设定成Debug.需要确保ConsoleHandler(或FileHandler)的日志级别是被设置,像FINEST或ALL应该被设置。请参考JDK文档中java.util.logging全部细节:

org.apache.catalina.level=FINEST

JULI使用的配置和简单java.util.logging支持的非常相似,但还支持一些为了更灵活的分配logger的扩展设置。主要的不同是:

  1. 可以在handler名称前增加一个前缀,因此单个类的多个handler可以被初始化。前缀是一个数字开头的字符串,以‘.’来结尾。例如,22foobar.是一个有效的前缀。
  2. 可以通过${systemPropertyName}来替换系统属性。
  3. 在Java6中,logger可能通过loggerName.handlers属性来定义一系列的handler。
  4. 默认情况下,如果他们关联了handler,logger不会委托给他的父类。每个logger都可以通过loggerName.useParentHandlers属性来设置。他接收一个boolean值。
  5. root logger可以通过.handler属性来设置他的handler集合。

这儿有多个附加的实现类,可以被用来和Java提供的一块工作。值得关注的org.apache.juli.FileHandler。

org.apache.juli.FileHandler支持日志缓存。默认情况下缓存没有被启用。可以通过handler的bufferSize属性来配置。0值使用系统默认的缓存(典型将使用8K的缓存)。<0的值将会强制每个logger写操作都flush。>0的值使用一个指定值的BufferedOutputStream,但注意系统默认的buffer也将被使用。

logging.properites配置文件的例子文件是放在$CATALINA_BASE/conf下:

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-example应用中WEB-INF/classes中存放着servlet logging配置的文件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 = servlet-examples. 

java.util.logging.ConsoleHandler.level = FINE 
java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter

2.1 文档引用

附加类的类信息可以参考下面的资料:

Apache Tomcat Javadoc中org.apache.juli包。

Oracle Java 6 Javadoc中的java.util.logging包。

2.2 应用在产品中时的注意事项

你需要注意接下来的情况:

  1. 考虑从配置中移出ConsoleHandler。默认(感谢.hanlders设置)情况下日志有FileHandler和ConsoleHandler。后者的输出是常常捕获到一个文件,例如,catalina.out。因此你有同一份信息的两份备份。
  2. 考虑移出应用不使用的FileHandlers。例如host-manager。
  3. 默认的handlers通过系统默认编码来写日志文件。可能通过encoding属性来配置。细节参见Javadoc。
  4. 考虑配置Access Log。

3. 使用Log4j

这章节解释了怎样在配置让Tomcat使用log4j框架,从而替换内部默认的java.util.logging。

Note:这节配置的步骤,是你想要重新配置Tomcat内部所使用的日志,将其改为log4j。这些步骤不适用于你自己的应用想要使用log4j的情况。对于这种情况,仅需要放log4j.jar和log4j.properties文件到你应用的WEB-INF/lib和WEB-INF/classes即可。

接下来的步骤描述了采用log4j输出Tomcat内部日志。

  1. 用包含下面内容的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
  3. 下载或建造tomcat-juli.jar和tomcat-juli-adapters.jar,这两个是Tomcat的“extras”组件。查阅附加组件文档获取更多细节。
    这个tomcat-juli.jar与默认的jar包不同。他包含了Apache Commons Logging implementation全部实现,因此能够找到log4j并自身配置采用log4j。
  4. 如果我想要配置Tomcat全部采用log4j:
    放log4j.jar和extras中的tomcat-juli-adapters.jar到$CATALINA_HOME/lib。
    用extras中的tomcat-juli.jar替换$CATALINA_HOME/bin/tomcat-juli.jar。
  5. 如果你的Tomcat是分别设置了$CATALINA_HOME和$CATALINA_BASE,想要为单独的$CATALINA_BASE配置log4j。
    如果不存在$CATALINA_BASE/bin和$CATALINA_BASE/lib目录,则创建。
    放log4j和extras中的tomcat-juli-adapters.jar到$CATALINA_BASE/lib
    放tomcat-juli.jar到$CATALINA_BASE/bin/目录
    如果你设置了security manager,你需要编辑$CATALINA_BASE/conf/catalina.policy文件来调整他使用不同的tomcat-juli.jar
  6. 删除$CATALINA_BASE/conf/logging.properties阻止java.util.logging产生零长度的配置文件。
  7. 开启Tomcat

这个log4j配置与Tomcat默认采用的java.util.logging是一样:manager和host-manager应用分隔到不同的日志文件,其余的写入“catalina.out”文件。每天产生一个文件。

你可以更挑剔的设置那个包采用什么配置。Tomcat通过Engine和Host names定义logger。举例:更详细的Catalina localhost日志,加这个到上面的log4j.properties文件中。注意:这有一个众所周知问题是采用log4j XMl配置的命名约定(方框号),因此我们推荐像下面描述的使用properties文件,只到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级别将产生数兆字节的日志且减慢Tomcat的启动速度。这个应该被保守的使用,只有当用来调试Tomcat内部操作才使用。

web应用应该明确的使用他自己的log4j配置。用上面的配置同样有效。你可以放置相似的log4j.properties文件到应用的WEB-INF/classes目录,放log4jx.y.z到WEB-INF/lib。然后指定包的日志级别。这是一个基本的log4j配置,不要求Commons-Logging,你应该查询log4j文档获取更多细节。这个页面有意作为一个入门指南。

4. 附笔

  1. 通过Common classloader暴露log4j库到web应用。看class loading文档获取更多细节。
    因此,web应用和类库使用Apache Commons Logging库有可能自动的选择log4j作为底层的日志实现。
  2. java.util.logging仍然可以使用,web应用可以直接使用他。${catalina.base}/conf/logging.properties文件是仍然被Tomcat启动脚本引用。
    移出${catalina.base}/conf/logging.properties文件,像上面步骤提到的那样,将造成java.util.logging采用JRE默认的配置作为配置,他使用了ConsoleHandler但不产生任何文件。