Tomcat 使用自带JULI输出log的方法
前言
在开发serverlet的过程中,输出自己代码的log来调试和追踪问题是不可避免的。大家知道在tomcat安装目录${catalina.base}中的有logs文件夹,下面存放的都是catalina log,localhost log等。怎么才能让自己的webapp也输出log文件到log文件夹下呢,网上有很多使用log4j的帖子,使用log4J之后从配置文件到使用方法全部替换掉tomcat原生的JULI。由于了解不够深刻,我担心自定义配置会漏掉一些有用的信息,所以还是想用tomcat自带的JULI,可网上关于怎么使用JULI定制自己log的文章很少。
最后通过翻阅官方文档了解到JULI是tomcat继承自java自带的logger类,并加以扩展的功能。于是又结合java的logger使用方法,自己总结出一个可用的方法,亲测可用。
这里贴上tomcat logging系统的官方文档,有时官方的说明已经详细到足够我们解决自己的问题。
http://tomcat.apache.org/tomcat-9.0-doc/logging.html
还需要说明的一点是,在tomcat以前版本的logging章节中有log4j的介绍,在tomcat最新9.0版本中除去了log4j的介绍,是不是在引导我们使用自带的JULI呢?当然如果你想使用log4j来定制log,那应该可以搜到很多帖子。
正文
最开始我添加了一些常用的system.out.print来打印log,这可以在运行调试时输出到idea环境下面,但是在发布到tomcat的webapp后打印到哪里呢?通过翻阅帖子在${catalina.base}/logs目录下tomcat9-stdout.2018-10-08.log中。而这个stdout文件的配置是在${catalina.base}/bin/service.bat中定义的(这是在windows环境下)。
"%EXECUTABLE%" //IS//%SERVICE_NAME% ^
--Description "Apache Tomcat 9.0.12 Server - https://tomcat.apache.org/" ^
--DisplayName "%DISPLAYNAME%" ^
--Install "%EXECUTABLE%" ^
--LogPath "%CATALINA_BASE%\logs" ^
--StdOutput auto ^
--StdError auto ^
而且在tomcat运行程序中好像可以自定义路径和文件,但是我还没有尝试过。
而在linux环境下,利用java中的系统输出则会打印在${catalina.base}/logs/catalina.out文件中,它的配置是在${catalina.base}/bin/catalina.sh中的CATALINA_OUT变量。
但我们想要的并不是默认输出路径,而是将log输出到固定的webapp.log文件下,这就要用到log4j和JULI了。下面介绍的方法会使用到JULI,详细的说明可以上文给出的官方文档。
1. 下载juli的jar包
tomcat官网很坑,并没有给出juli jar包的下载。想下载最新版本的juli包,必须通过maven或gradle,那就需要配置maven环境,并创建一个maven项目。
maven的配置看这个帖子:https://www.cnblogs.com/phpdragon/p/7216626.html
之后就在maven库上下载最新的juli包。
2. 创建logging.properties配置文件
java.util.logger类的使用就是通过配置文件来的,JULI继承了logger类,所以也可以通过配置文件进行管理。tomcat原生的log文件,例如catalina.out,localhost.log,host-manager.log就是在配置文件${catalina.base}/conf/logging.properties中的。可以通过网友的帖子,或者官方文档了解一下。
我们直接在web项目的/web/WEB-INF目录下创建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
org.apache.catalina.core.ContainerBase.[Catalina].[localhost].[/${classloader.webappName}].[com.washcar.interlayer.IlServer].handlers = org.apac\
/ he.juli.FileHandler
定义比较直观,里面包含log输出的路径是logs,文件名prefix就是当前的webappName,handlers比较重要。它将具体的文件和logger连接起来,以供下面我们要将的ClassLoaderLogManager来寻找和使用。
3. 编写代码
代码使用了官方文档中juli包里的重要的类ClassLoaderLogManager,它用来根据不同的tag寻找对应的logger,而logger和handler是多对一的关系。我使用ClassLoaderLogManager.getLogger("catalina")获取的logger就将log打印在catalina.out目录下,如果getlogger("localhost")获取的logger就将log打印在localhost文件下,使用host-manager获取的logger就会打印在对应的文件下。
我们要做的就是获取到我们自己的serverlet对应的logger,具体代码如下:
LogManager classLoaderLogManager = ClassLoaderLogManager.getLogManager();
Enumeration e = classLoaderLogManager.getLoggerNames();
while(e.hasMoreElements()) {
String value = (String) e.nextElement();
System.out.println("logger-tag: "+value);
if (value.contains(serverletName)) {
myLoggerName = value;
break;
}
}//调用nextElement方法获得元素 System.out.print(value);
其中的serverletName就是我们自定义的serverlet的name,找到之后直接用info就可以将log输出在${catalina.base}/logs/webappname.2018-10-08.log文件中。
至此我们就完成了JULI的使用。
总结
虽然功能是很小,但对于初接触tomcat webapp开发的人来说,仍然需要摸索一番,而网上大量的文章都是用了log4j这种方法,很少明确的给出JULI用法。
现在的方法,对于我还有几点不是很清楚,在此记录以便补齐:
1、对于logging.properties中的handler和formatt还需要进一步研究,要进一步弄清它的用法。
2、[com.washcar.interlayer.IlServer]这个是写死的内容,有没有利用变量来获取呢?使用classloader的变量行不行?
3、这个log打印是在发布之后打在文件中的,在idea环境中打印不太方便,能否做成调试时就在idea下打印,发布后就在文件中打印,通过环境变量来控制,而不是硬编码。