我有新鲜的tomcat安装。
为了改善日志记录,我编辑conf/logging.properties。
conf/logging.properties
我换线
java.util.logging.ConsoleHandler.level = FINE
至
java.util.logging.ConsoleHandler.level = FINER
并追加行
org.apache.catalina.level = FINER
然后我启动服务器,如果我失败来验证http://localhost:8080/manager/与用户名MyUsername和MyPassword我看到这样的输出:
http://localhost:8080/manager/
MyUsername
MyPassword
FINE [http-bio-443-exec-2] org.apache.catalina.authenticator.AuthenticatorBase.invoke Security checking request GET /manager/html FINE [http-bio-443-exec-2] org.apache.catalina.loader.WebappClassLoaderBase.loadClass loadClass(org.apache.catalina.manager.HTMLManagerServlet, false) FINE [http-bio-443-exec-2] org.apache.catalina.loader.WebappClassLoaderBase.loadClass Delegating to parent classloader1 java.net.URLClassLoader@1218025c FINE [http-bio-443-exec-2] org.apache.catalina.loader.WebappClassLoaderBase.loadClass Loading class from parent FINE [http-bio-443-exec-2] org.apache.catalina.realm.RealmBase.findSecurityConstraints Checking constraint 'SecurityConstraint[Status interface]' against GET /html --> false FINE [http-bio-443-exec-2] org.apache.catalina.realm.RealmBase.findSecurityConstraints Checking constraint 'SecurityConstraint[JMX Proxy interface]' against GET /html --> false FINE [http-bio-443-exec-2] org.apache.catalina.realm.RealmBase.findSecurityConstraints Checking constraint 'SecurityConstraint[Text Manager interface (for scripts)]' against GET /html --> false FINE [http-bio-443-exec-2] org.apache.catalina.realm.RealmBase.findSecurityConstraints Checking constraint 'SecurityConstraint[HTML Manager interface (for humans)]' against GET /html --> true FINE [http-bio-443-exec-2] org.apache.catalina.realm.RealmBase.findSecurityConstraints Checking constraint 'SecurityConstraint[Status interface]' against GET /html --> false FINE [http-bio-443-exec-2] org.apache.catalina.realm.RealmBase.findSecurityConstraints Checking constraint 'SecurityConstraint[JMX Proxy interface]' against GET /html --> false FINE [http-bio-443-exec-2] org.apache.catalina.realm.RealmBase.findSecurityConstraints Checking constraint 'SecurityConstraint[Text Manager interface (for scripts)]' against GET /html --> false FINE [http-bio-443-exec-2] org.apache.catalina.realm.RealmBase.findSecurityConstraints Checking constraint 'SecurityConstraint[HTML Manager interface (for humans)]' against GET /html --> true FINE [http-bio-443-exec-2] org.apache.catalina.authenticator.AuthenticatorBase.invoke Calling hasUserDataPermission() FINE [http-bio-443-exec-2] org.apache.catalina.realm.RealmBase.hasUserDataPermission User data constraint has no restrictions FINE [http-bio-443-exec-2] org.apache.catalina.authenticator.AuthenticatorBase.invoke Calling authenticate() FINER [http-bio-443-exec-2] org.apache.catalina.realm.RealmBase.authenticate Username MyUsername NOT successfully authenticated FINE [http-bio-443-exec-2] org.apache.catalina.authenticator.AuthenticatorBase.invoke Failed authenticate() test FINE [http-bio-443-exec-2] org.apache.catalina.core.StandardHostValve.custom Processing ErrorPage[errorCode=401, location=/WEB-INF/jsp/401.jsp] FINER [http-bio-443-exec-2] org.apache.catalina.core.StandardWrapper.allocate Returning non-STM instance FINE [http-bio-443-exec-2] org.apache.catalina.core.ApplicationDispatcher.doForward Disabling the response for futher output FINE [ContainerBackgroundProcessor[StandardEngine[Catalina]]] org.apache.catalina.session.ManagerBase.processExpires Start expire sessions StandardManager at 1525428004090 sessioncount 0 FINE [ContainerBackgroundProcessor[StandardEngine[Catalina]]] org.apache.catalina.session.ManagerBase.processExpires End expire sessions StandardManager processingTime 4 expired sessions: 0
现在,我修改 步骤2 并将程序包添加realm到定义中。现在,步骤2改为添加以下行:
realm
org.apache.catalina.realm.level = FINER
为什么FINER-Loggings消失了?我的意思是,org.apache.catalina.realm更具体吧?
org.apache.catalina.realm
如果我正确理解,您最终将获得如下所示的日志记录属性:
java.util.logging.ConsoleHandler.level = FINER org.apache.catalina.realm.level = FINER
在Java记录概述部分1.1规定:
应用程序在Logger对象上进行日志记录调用。记录器以分层的名称空间组织,子记录器可以从名称空间的父级继承一些记录属性。
读取记录器名称时,父记录器位于圆点的左侧。所以,org.apache.catalina是的父org.apache.catalina.realm和org.apache.catalina.core。
org.apache.catalina
org.apache.catalina.core
执行代码必须要求记录器才能存在。 仅在属性文件中添加行不会创建记录器。 如果这样做的话,他们无论如何都会被垃圾收集。这意味着您拥有一个记录器树A <- B <- C。您要为此设置B所有B子级的级别,以便A.B.level在属性文件中添加行。然而,在运行时所要求的记录器A和C
A <- B <- C
B
A.B.level
A
C
因此,您所需要的"" <- A <- A.B.C就是期望"" <- A <- A.B <- A.B.C
"" <- A <- A.B.C
"" <- A <- A.B <- A.B.C
综上所述,我认为您的记录器在运行时如下所示:
"" <- org.apache.catalina <- org.apache.catalina.realm.RealmBase而且还没有Tomcat代码创建名为的实际记录器org.apache.catalina.realm。
"" <- org.apache.catalina <- org.apache.catalina.realm.RealmBase
您可以通过将JConsole连接到运行中的JVM并检查MBean选项卡并列出记录器名称来进行验证。在Tomcat上,这将不起作用,因为返回的记录器取决于调用的类加载器。
要解决此问题,您可以使用config选项来要求并保持记录器在内存中。您只需将其安装在系统类路径上的自定义代码上。
否则,您必须在属性文件中指定所有已知的子记录器名称,这些名称可能很冗长。
第一个想法:如果我们看一下CSS的特殊性,我们知道.mydiv {color:red}不如div.mydiv {color:green}那样具体,那么div.mydiv包含红色文本吗?继承是指(如果未指定)什么是反继承。
与CSS不同,JUL具有运行时记录器树和属性文件。当执行代码需要记录器时,将动态调整运行时记录器树。仅当代码需要记录器时才使用这些属性。除非通过代码创建记录器,否则在属性文件中指定记录器名称并不重要。这可以更改记录器的父级,从而更改级别。试一下:
package so; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.util.Properties; import java.util.logging.Level; import java.util.logging.LogManager; import java.util.logging.Logger; public class TheMissingParent { private static final Logger[] LAZY_ONE; static { LAZY_ONE = new Logger[] { Logger.getLogger("org.apache.catalina"), Logger.getLogger("org.apache.catalina.realm.RealmBase") }; } private static volatile Logger[] LAZY_TWO; public static void main(String[] args) { loadProperties(); printAncestors(LAZY_ONE); findlLongLostParents(); System.out.println("===="); printAncestors(LAZY_ONE); } private static void loadProperties() { Properties props = new Properties(); props.put("org.apache.catalina.realm.level", "FINER"); try(ByteArrayOutputStream out = new ByteArrayOutputStream()) { props.store(out, ""); LogManager.getLogManager().readConfiguration(new ByteArrayInputStream(out.toByteArray())); } catch (IOException ioe) { throw new AssertionError(ioe); } } private static void findlLongLostParents() { LAZY_TWO = new Logger[] {Logger.getLogger("org.apache.catalina.realm") }; } private static void printAncestors(Logger[] loggers) { // System.out.println(loggers.toString()); for (Logger l : loggers) { printAncestors(l); System.out.println(); } } private static void printAncestors(Logger l) { if (l != null) { printAncestors(l.getParent()); System.out.print("<-"); String name = l.getName(); if (name != null && name.isEmpty()) { System.out.append("\"\""); } else { System.out.append(name); } for(Logger p = l; p != null; p = p.getParent()) { Level lvl = p.getLevel(); if (lvl != null) { System.out.append('{').append(lvl.getName()).append('}'); break; } } } } }
这将输出:
<-""{INFO}<-org.apache.catalina{INFO} <-""{INFO}<-org.apache.catalina{INFO}<-org.apache.catalina.realm.RealmBase{INFO} ==== <-""{INFO}<-org.apache.catalina{INFO} <-""{INFO}<-org.apache.catalina{INFO}<-org.apache.catalina.realm{FINER}<-org.apache.catalina.realm.RealmBase{FINER}
这是核心问题。如果Tomcat(或某些自定义代码)从不要求org.apache.catalina.realm记录器,则属性文件中的行就是无效代码。
其次,如果您这样说,那么没有人将org.apache.catalina或org.apache或org nor指定为``级别INFO’‘,那么INFO的价值从何而来?
该行为在LoggerManager类级别docs中进行了描述:
如果这两个属性均未定义,则如上所述,LogManager将从JRE目录中的属性文件“ lib / logging.properties”中读取其初始配置。
名为空字符串的根记录器""是所有记录器的父级。始终创建根记录器。
""