【问题标题】:java.util.logging can't share the logger between two classesjava.util.logging 不能在两个类之间共享记录器
【发布时间】:2016-11-21 08:44:59
【问题描述】:

我正在尝试将日志从两个类(在包 com.project.callcontrol 中)重定向到同一个文件。 这就是我在两个类中启动记录器的方式 私有静态最终 Logger logger =

private static Logger log = Logger.getLogger(CCPurgeEvent.class.getName());

private static Logger log = Logger.getLogger(PurgeDeadCalls.class.getName());

这就是我试图为两个类共享同一个文件的方式,java.util.logging 配置

com.project.callcontrol.PurgeDeadCalls.useParentHandlers = false
com.project.callcontrol.PurgeDeadCalls.handlers = com.project.logging.CcPurgeLogger

com.project.callcontrol.CCPurgeEvent.useParentHandlers = false
com.project.callcontrol.CCPurgeEvent.handlers = com.project.logging.CcPurgeLogger

com.project.logging.CcPurgeLogger.pattern=/var/log/voxcallcontrol-batches/cc_purge%u.log
com.project.logging.CcPurgeLogger.formatter = java.util.logging.SimpleFormatter
com.project.logging.CcPurgeLogger.level = FINEST
com.project.logging.CcPurgeLogger.limit=100000000
com.project.logging.CcPurgeLogger.count=10

请注意,CCPurgeLogger 什么都不做,只是创建父类 FileHandler 的方法(甚至不知道为什么会在那里) 我的问题是我无法从日志文件中的两个类中获取日志,我只能从一个类中获取日志,具体取决于配置文件中的配置顺序。 例如,如果我将 CCPurgeEvent 配置移到 PurgeDeadCalls 配置之上,它适用于 CCPurgeEvent 而不是 PurgeDeadCalls,当我切换顺序时会发生相反的情况。 我似乎无法理解我错过了什么,任何指向这个方向的指针都会非常有帮助。

P.S:我不能改变我的日志框架,我知道log4j和其他框架提供了更多的选择,但是在目前的工作范围内,我只需要使用java.util.logging。

【问题讨论】:

    标签: java java.util.logging


    【解决方案1】:

    如果您希望为两个记录器共享一个日志文件,那么您必须在一个公共父记录器上安装处理程序,并且您的代码必须获取该父记录器并将其固定在内存中。第一个共同的父母是com.project.callcontrol

    com.project.callcontrol.handlers = com.project.logging.CcPurgeLogger
    com.project.callcontrol.PurgeDeadCalls.useParentHandlers = true
    com.project.callcontrol.CCPurgeEvent.useParentHandlers = true
    
    com.project.logging.CcPurgeLogger.pattern=/var/log/voxcallcontrol-batches/cc_purge%u.log
    com.project.logging.CcPurgeLogger.formatter = java.util.logging.SimpleFormatter
    com.project.logging.CcPurgeLogger.level = FINEST
    com.project.logging.CcPurgeLogger.limit=100000000
    com.project.logging.CcPurgeLogger.count=10
    

    如果您想使用现有配置,则必须将 com.project.logging.CcPurgeLogger 处理程序的实现更改为:

    public class CcPurgeLogger extends Handler {
    
        private static volatile Handler common;
        private static long count;
    
    
        private static void create() throws IOException {
            synchronized (CcPurgeLogger.class) {
                if (common == null) {
                   common = new FileHandler(); 
                }
                count++;
            }
        }
    
        public CcPurgeLogger() throws IOException {
            create();
        }
    
        @Override
        public boolean isLoggable(LogRecord record) {
            String name = record.getLoggerName();
            return ("com.project.callcontrol.PurgeDeadCalls".equals(name)
                    || "com.project.callcontrol.CCPurgeEvent".equals(name))
                    && common.isLoggable(record);
        }
    
        @Override
        public void publish(LogRecord record) {
            common.publish(record);
        }
    
        @Override
        public void flush() {
            common.flush();
        }
    
        @Override
        public void close() throws SecurityException {
            synchronized (CcPurgeLogger.class) {
                if (common != null) {
                    if (count == 1L) {
                        common.close();
                        common = null;
                    }
                    --count;
                }
            }
        }
    }
    

    您能否分享一个在配置文件中定义新子系统记录器的示例?

    让我们根据子系统的作用(purge)而不是它是什么(一些类名)来命名子系统。

    com.project.callcontrol.PURGE.handlers = com.project.logging.CcPurgeLogger
    com.project.callcontrol.PURGE.useParentHandlers = true
    
    
    com.project.logging.CcPurgeLogger.pattern=/var/log/voxcallcontrol-batches/cc_purge%u.log
    com.project.logging.CcPurgeLogger.formatter = java.util.logging.SimpleFormatter
    com.project.logging.CcPurgeLogger.level = FINEST
    com.project.logging.CcPurgeLogger.limit=100000000
    com.project.logging.CcPurgeLogger.count=10
    

    然后在 'PurgeDeadCalls' 类和 'CCPurgeEvent' 类中通过执行以下操作获取子系统记录器。

    private static Logger log = Logger.getLogger("com.project.callcontrol.PURGE");
    

    【讨论】:

    • 嗨@jmerherns,在您提出的配置解决方案中,来自“com.project.callcontrol”包中其他类的日志也将开始记录到同一个文件,这是不需要的。我只是将这两个类的所有日志放在一个日志文件中。我可以做的另一件事是将“记录器”从 PurgeDeadcalls 传递给 CCPurgeEvent,因为 CCPurgeEvent 仅用于 PurgeDeadCalls。我想知道如果我使用'log4j'是否会遇到同样的问题
    • @Nitesh 您已经创建了一个自定义处理程序,因此您不妨创建一个自定义过滤器来检查记录器名称并安装它。或者只是覆盖自定义处理程序的isLoggable 方法来进行过滤。如果您只想坚持配置,那么您必须为您不想看到的所有记录器关闭 .useParentHandlers
    • 谢谢,但我真的很茫然,不明白为什么对两个类使用同一个记录器这么复杂。我不想修改自定义记录器 CCPurgeLogger,并且此包中的所有其他类都写入根记录器,因此不可能为所有类禁用“useParentLogger”,并且有 50 个类,不要想修改所有这些。没有别的选择,用log4j会不会更容易解决??
    • 不要用类名来命名你的记录器。按子系统命名它们,并让两个类获取完全相同的命名子系统记录器。
    • 我还是很好奇如果我使用 log4j 实现起来会不会更简单
    猜你喜欢
    • 2010-12-13
    • 2012-10-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多