调试 Tomcat 源码过程中,控制台日志打印的都是 INFO 级别的日志,于是就想修改下日志级别,打印 Digester 类的 DEBUG 级别的日志,便于观察 Digester 类解析 server.xml 的流程,顺便跟踪了一下 Tomcat 使用日志的流程,整理如下。
Java提供了原生态的日志工具包 java.util.logging,功能虽然没有 log4j 强大,但是够用了,我想这也是 Tomcat 使用原生日志的原因吧。Java 默认的日志配置文件路径是 Java 安装路径下的 \jre\lib\logging.properties。
使用过程中可以设置系统变量来改变路径,使用方法很简单,示例如下
public class MyClass { public static void main(String[] args) { System.setProperty("java.util.logging.config.file", "D:\\A2017Study\\TomcateStudy\\catalina-home\\conf\\logging.properties"); Logger log = Logger.getLogger("Javasoft"); log.info("aaa"); } }从类图上,不难看出,这里使用了工厂模式、单例模式、观察者模式(即监听器)。
LogManager 类负责生成 Logger 实例,区分用户 Logger 和系统 Logger,默认新建的 Logger其 isSystemLog 标识为false,存储在 userContext 中。
LoggerContext 维护了一个 HashTable,保存创建的Logger对象。
分析上述示例的 main 方法,得到整个调用的时序图如下:
logging.properties 文件的作用就是定义 Logger 的 Handler 和 level,这个文件是在 LogManager 的构造方法中调用的,源码如下:
public static LogManager getLogManager() { if (manager != null) { manager.readPrimordialConfiguration(); } return manager; } public void readConfiguration() throws IOException, SecurityException { checkPermission(); String cname = System.getProperty("java.util.logging.config.class"); if (cname != null) { try { Class clz = ClassLoader.getSystemClassLoader().loadClass(cname); clz.newInstance(); return; } String fname = System.getProperty("java.util.logging.config.file"); if (fname == null) { fname = System.getProperty("java.home"); if (fname == null) { throw new Error("Can't find java.home ??"); } File f = new File(fname, "lib"); f = new File(f, "logging.properties"); fname = f.getCanonicalPath(); } …… }readConfiguration() 值得关注的是两个配置(其他代码省略了,只保留重要代码)。
LogManager 类通过它们来控制配置文件的初始化,类注释如下:
In addition, the LogManager uses two optional system properties that allow more control over reading the initial configuration: “java.util.logging.config.class” “java.util.logging.config.file”
所以我们可以通过 -Djava.util.logging.config.file 配置这两个变量来控制最终的配置文件,如果指定了class类,我们就需要在自定义类的构造函数中完成配置文件的初始化过程,当然直接指定file配置显得更简单一些。
主要关注的是日志的 level 和 handler 属性,文章开头的问题,通过修改 Java 安装目录下默认的 logging.properties 文件,修改全局控制台的日志等级为java.util.logging.ConsoleHandler.level=FINE,就能打印出 Tomcat 启动过程中的所有日志了。