Tomcat Embedded结合JULI无法分离Web应用Servlet上下文日志与Catalina容器日志
我太懂你这种挫败感了——在独立Tomcat里配置得丝滑的JULI日志分离,换到嵌入式Tomcat就直接“罢工”,Web应用的上下文日志非要往Catalina的日志里凑,单独配置的myapp日志文件就空空地躺在那儿,完全没起到作用。别担心,这不是嵌入式Tomcat的bug,主要是你踩了版本兼容和嵌入式环境默认配置差异这两个坑,咱们一步步来解决:
首先,先把最关键的依赖版本问题搞定
你看你的依赖里,tomcat-embed-core用的是9.0.108,可tomcat-embed-logging-juli居然是9.0.0.M6——这俩版本差了快100个小版本!JULI和Tomcat核心是深度绑定的,旧版本的JULI根本认不出新版本嵌入式Tomcat的容器上下文逻辑,自然没法正确路由日志。
解决办法:把tomcat-embed-logging-juli的版本换成和tomcat-embed-core完全一致的9.0.108,保证依赖版本对齐。
然后,给嵌入式Tomcat显式配置容器名称,对齐日志记录器路径
独立Tomcat默认的引擎名是Catalina、Host名是localhost,虽然嵌入式Tomcat默认也是这个,但显式设置能确保日志记录器的命名空间和你logging.properties里的配置完全匹配,避免因为隐式命名差异导致路由失败。
修改你的Main类代码,添加引擎和Host的名称设置:
public static void main(String[] args) { Tomcat tomcat = new Tomcat(); // 显式设置引擎名称为Catalina,和配置文件里的记录器路径对应 Engine engine = tomcat.getEngine(); engine.setName("Catalina"); // 显式设置Host名称为localhost Host host = tomcat.getHost(); host.setName("localhost"); tomcat.setBaseDir(new File("resource").getAbsolutePath()); tomcat.setPort(8080); tomcat.getConnector(); tomcat.addWebapp("/myapp", new File("/Users/me/TomcatEmbedTest/resource/webapps/myapp").getAbsolutePath()); try { tomcat.start(); // 别忘了加这句,否则Tomcat启动后会直接退出,日志可能来不及写入 tomcat.getServer().await(); } catch (LifecycleException e) { throw new RuntimeException(e); } }
调整logging.properties,阻止日志向上传递到父记录器
你当前的配置已经指定了Web应用的日志处理器,但默认情况下,日志会向上传递到父记录器(比如localhost或Catalina的记录器),导致日志同时出现在Catalina的日志里。咱们加一条配置禁用父记录器继承:
# 阻止/myapp的日志向上传递到父记录器,确保只写入你指定的handler org.apache.catalina.core.ContainerBase.[Catalina].[localhost].[/myapp].useParentHandlers = false
把这条配置加到你现有的org.apache.catalina.core.ContainerBase.[Catalina].[localhost].[/myapp]相关配置下面就行。
最后,验证几个关键细节
- 确保启动参数里的
-Djava.util.logging.config.file路径绝对正确,你可以在代码里加一句System.out.println(System.getProperty("java.util.logging.config.file")),启动后看看输出的路径是不是你实际的配置文件路径。 - 测试的时候一定要访问你的Servlet(比如浏览器访问
http://localhost:8080/myapp/test),因为你的日志语句是在doGet方法里,只有触发请求才会执行。
按照这几步调整完,再启动应用测试,你应该就能看到myapp.xxxx-xx-xx.log里出现你打印的那条日志,Catalina日志里也不会再出现这条Web应用的日志了。
内容来源于stack exchange

