在Tomcat JULI中,“针对特定设施的"记录器是否成为每个Web应用程序记录器的根目录? [英] In Tomcat JULI, do the 'facility specific' loggers become per-webapp logger roots?

查看:104
本文介绍了在Tomcat JULI中,“针对特定设施的"记录器是否成为每个Web应用程序记录器的根目录?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我可以期待"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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆