在Tomcat JULI中,“针对特定设施的"记录器是否成为每个Web应用程序记录器的根目录? [英] In Tomcat JULI, do the 'facility specific' loggers become per-webapp logger roots?
问题描述
我可以期待"Hi!"的日志条目吗?将被发送到${catalina.base}/logs/webapp.log
?
Tomcat配置
{$CATALINA_BASE}/conf/logger.properties
# DECLARE HANDLERS
handlers = 3webapp.org.apache.juli.FileHandler
# CONFIGURE HANDLERS
3webapp.org.apache.juli.FileHandler.level = ALL
3webapp.org.apache.juli.FileHandler.directory = ${catalina.base}/logs
3webapp.org.apache.juli.FileHandler.prefix = webapp
3webapp.org.apache.juli.FileHandler.rotatable = false
# Webapp-local 'ROOT' logger?? The Apache-provided logger.properties
# calls these 'Facility specific'
org.apache.catalina.core.ContainerBase.[Catalina].[localhost].[/webapp].level = ALL
org.apache.catalina.core.ContainerBase.[Catalina].[localhost].[/webapp].handlers = 3webapp.org.apache.juli.FileHandler
Webapp级日志记录配置
部署到/webapp
的WAR的 WEB-INF/classes/logger.properties
au.com.mydomain.level = ALL
通过代码使用
WAR中的代码已部署到/webapp
package au.com.mydomain.foo;
import java.util.logging.Logger;
import java.util.logging.Level;
public class Bar {
...
Logger.getLogger(Bar.class.getName()).log(Level.INFO, "Hi!");
...
}
答案为否"
如在调试器中确认的那样,如果Web应用程序执行以下操作:
import java.util.logging.Logger;
...
Logger foo = Logger.getLogger("foo");
然后foo
的直接父级是org.apache.juli.ClassLoaderLogManager$RootLogger
,它是由Catalina设置的JVM范围内的记录器,并且是{$CATALINA_BASE}/conf/logger.properties
中定义的所有其他记录器的最终祖先.
但一切并没有丢失
有可能获得对每个Web应用程序"记录器的引用:
String prefix = "org.apache.catalina.core.ContainerBase.[Catalina].[localhost].[/webapp]";
Logger hmm = Logger.getLogger(prefix);
这意味着我们可以将每个Web应用程序记录器作为父记录器来获取记录器:
Logger.getLogger(prefix + "." + MyClass.class.getName())
骇人听闻的骇客
但是,当然,所有现有代码都执行Logger.getLogger()而不指定前缀.
如果您执行以下操作(在类似ServletContextListener#contextInitialized(ServletContextEvent)
的位置,则可以:
// eg "org.apache.catalina.core.ContainerBase.[Catalina].[localhost].[/webapp]"
String tomcatHack = sce.getServletContext().getInitParameter("tomcatHack");
if (tomcatHack != null) {
Logger ctxLog = Logger.getLogger("webappLogger");
Logger appLog = Logger.getLogger("au.com.mydomain");
appLog.setParent(ctxLog);
}
现在将后续日志记录到:
Logger.getLogger("au.com.mydomain.foo").log(Level.INFO, "Ha!");
...将出现在log.log
中.
作为一个令人讨厌的副作用,如果您有两个在同一容器中运行此技巧的Web应用程序(例如,/prod和/test)运行,则它们将覆盖父级应用程序.
作为潜在的令人讨厌的副作用,我们的记录器根目录现在在JVM范围的记录器层次结构中的两个点处都是孩子",这可能使某人在某个地方,某个时候感到不安.
Can I expect that a log entry for "Hi!" will be emitted to ${catalina.base}/logs/webapp.log
?
Tomcat Config
{$CATALINA_BASE}/conf/logger.properties
# DECLARE HANDLERS
handlers = 3webapp.org.apache.juli.FileHandler
# CONFIGURE HANDLERS
3webapp.org.apache.juli.FileHandler.level = ALL
3webapp.org.apache.juli.FileHandler.directory = ${catalina.base}/logs
3webapp.org.apache.juli.FileHandler.prefix = webapp
3webapp.org.apache.juli.FileHandler.rotatable = false
# Webapp-local 'ROOT' logger?? The Apache-provided logger.properties
# calls these 'Facility specific'
org.apache.catalina.core.ContainerBase.[Catalina].[localhost].[/webapp].level = ALL
org.apache.catalina.core.ContainerBase.[Catalina].[localhost].[/webapp].handlers = 3webapp.org.apache.juli.FileHandler
Webapp-level Logging Config
WEB-INF/classes/logger.properties
of WAR deployed to /webapp
au.com.mydomain.level = ALL
Usage from Code
Code in WAR deployed to /webapp
package au.com.mydomain.foo;
import java.util.logging.Logger;
import java.util.logging.Level;
public class Bar {
...
Logger.getLogger(Bar.class.getName()).log(Level.INFO, "Hi!");
...
}
The answer is "NO"
As confirmed in a debugger, if a web-application does:
import java.util.logging.Logger;
...
Logger foo = Logger.getLogger("foo");
Then foo
's immediate parent is the org.apache.juli.ClassLoaderLogManager$RootLogger
which is the JVM-wide logger which is gets set up by Catalina, and is the ultimate ancestor of all other loggers defined in {$CATALINA_BASE}/conf/logger.properties
.
But all is not lost
It's possible to gain a reference to the 'per-webapp' logger:
String prefix = "org.apache.catalina.core.ContainerBase.[Catalina].[localhost].[/webapp]";
Logger hmm = Logger.getLogger(prefix);
which means we can get a logger with the per-webapp logger as a parent:
Logger.getLogger(prefix + "." + MyClass.class.getName())
A horrible, horrible hack
But of course, all the existing code does Logger.getLogger() without specifying a prefix.
If you do the following (in somewhere like ServletContextListener#contextInitialized(ServletContextEvent)
, you can:
// eg "org.apache.catalina.core.ContainerBase.[Catalina].[localhost].[/webapp]"
String tomcatHack = sce.getServletContext().getInitParameter("tomcatHack");
if (tomcatHack != null) {
Logger ctxLog = Logger.getLogger("webappLogger");
Logger appLog = Logger.getLogger("au.com.mydomain");
appLog.setParent(ctxLog);
}
And now subsequent logs to:
Logger.getLogger("au.com.mydomain.foo").log(Level.INFO, "Ha!");
... will turn up in log.log
.
As a nasty side-effect, if you've got two web-apps that pull of this trick running in the same container (eg, /prod and /test) then they will overwrite the parent.
As a potentially nasty side-effect, our logger root is now a 'child' at two points in the JVM-wide hierarchy of loggers, and that may upset someone, somewhere, sometime.
这篇关于在Tomcat JULI中,“针对特定设施的"记录器是否成为每个Web应用程序记录器的根目录?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!