Tomcat 的内部日志使用 JULI 组件,这是一个 Apache Commons 日志的重命名的打包分支,默认被硬编码,使用 java.util.logging 架构。这能保证 Tomcat 内部日志与 Web 应用的日志保持独立,即使 Web 应用使用的是 Apache Commons Logging。
假如想用另外的日志框架来替换 Tomcat 的内部日志系统,那么就必须采用一种能够保持完整的 Commons 日志机制的 JULI 实现,用它来替换通过硬编码使用 java.util.logging 的 JULI 实现。通常这种替代实现都是以额外组件的形式出现的。利用 Log4j 框架用于 Tomcat 内部日志的配置如下文所示。
在 Apache Tomcat 上运行的 Web 应用可以使用:
各个应用可以使用不同的日志框架,详情参见类加载器。java.util.logging 则是例外。如果日志库直接或间接地用到了这一 API,那么 Web 应用就能共享使用它的元素,因为该 API 是由系统类加载器所加载的。
Apache Tomcat 本身已经实现了 java.util.logging API 的几个关键元素。这种实现就是 JULI。其中的关键组件是一个自定义的 LogManager 实现,它能分辨运行在 Tomcat 上的不同 Web 应用(以及它们所用的不同的类加载器),还能针对每一应用进行私有的日志配置。另外,当 Web 应用没能从内存中加载时,Tomcat 会给予它相应通知,从而清除相应的引用类,防止内存泄露。
在启动 Java 时,通过提供特定的系统属性,可以启用 java.util.logging 实现。Apache Tomcat 启动脚本可以实现这个操作,但如果使用不同工具来运行 Tomcat(比如 jsvc,或者从某个 IDE 中运行 Tomcat),就必须自己来启用实现。
关于 java.util.logging 实现的详细情况可以查阅 JDK 文档,具体位于 java.util.logging 包的相关 javadoc 页面中。
关于 Tomcat JULI 的详细介绍见下文。
Tomcat 内部日志能够处理对 javax.servlet.ServletContext.log(...) 的调用,从而写入日志消息。这种消息都被记录到一种特定类别中,命名方式如下:
org.apache.catalina.core.ContainerBase.[${engine}].[${host}].[${context}]
这种日志是依照 Tomcat 日志配置而执行的,无法在 Web 应用中重写。
Servlets logging API 的问世要先于 Java 所提供的 java.util.logging API,所以,它无法提供太多的选项,比如无法用它来控制日志级别。然而需要注意的是,在 Tomcat 实现中, 对 ServletContext.log(String) 和 GenericServlet.log(String) 的调用都被记录在 INFO 级别。对 ServletContext.log(String, Throwable) 或 GenericServlet.log(String, Throwable) 的调用都被记录在 ERROR 级别。
在 UNIX 系统下运行 Tomcat 时,控制台输出经常会重定向到 catalina.out 的文件中。通过一个环境变量,可以配置该文件(参见启动脚本)。
写入 System.err/out 的任何内容都会被 catalina.out 文件所捕获。这些内容可能包括:
在 Windows 上以服务形式运行时,控制台输出也会被捕获及重定向,但文件名有所不同。
Tomcat 默认的日志配置会将同样的消息写入控制台和一个日志文件中。这一特点非常有利于使用 Tomcat 进行开发,但往往并不适用于生产环境。
老的应用可能还在使用 System.out 或 System.err,可以通过在 Context 元素上设置 swallowOutput 属性来调整。如该属性设为 true,那么在请求阶段对 System.out/err 的调用就会被拦截,它们的输出也会通过 javax.servlet.ServletContext.log(...) 调用反馈给日志系统。
注意:swallowOutput 虽然是一个小技巧,但还是有局限性的:它需要直接调用 System.out/err,并且要在请求处理周期内完成。而且,它可能还并不适用于应用所创建的其他线程。不能将其用于拦截本身写入系统流的日志框架(它们可能早先已经启动,并且在重定向发生前就已经获取了对流的直接引用)。
Access 日志功能相近,但还是有所不同。它是一个 Valve,使用自包含的逻辑来编写日志文件。访问日志的基本需求是以较低开销处理大型连续数据流,所以只能使用 Commomns Logging 来处理自身的调试消息。这种实现方法避免了额外的开销,并且可能具有较复杂的配置。请参考 Valves 文档了解更多配置详情,其中包含了各种报告格式。