【问题标题】:How to initialize Loggers correctly?如何正确初始化记录器?
【发布时间】:2016-02-01 12:23:14
【问题描述】:

我有以下问题:我想使用java.util.logging.Logger。不,我找到了不同的资源1,2,3,如何修改记录器的行为。

特别是在2 的问题中,一个(在我看来)根据类名初始化记录器的结构很好。如果需要,这还允许在基于包的级别上修改详细程度以进行调试。

在深入研究问题后,我发现全局记录器和“空”记录器(名称为"")并不相同。另请参见下面的示例。 我刚刚创建了一个记录器foo.Bar,它锚定在空记录器而不是名为foo 的记录器上。 仅当我首先创建记录器bar 时,记录器bar.Baz 才会正确锚定到它。

这使得this question 中的方法主要是无用的,因为不能假设之前创建了父记录器。据我所知,必须解析类名并根据需要创建记录器。

在初始化自己的记录器之前,我必须添加一些static {...} 代码以递归方式初始化记录器,这对吗? 如果多个类为包记录器调用Logger.getLogger(String) 方法,这是否有任何负面影响(导致整体多次调用,例如bar.Bazbar.FooBaz 都获取记录器bar)?

import java.util.Enumeration;
import java.util.logging.LogManager;
import java.util.logging.Logger;
public class TestLogger
{
    public static void main(String[] args)
    {
        // Create the logger directly
        Logger.getLogger("foo.Bar");
        // Create the logger objects step-by-step
        Logger.getLogger("bar");
        Logger.getLogger("bar.Baz");
        // Put the available loggers to output
        Enumeration<String> e = LogManager.getLogManager().getLoggerNames();
        while(e.hasMoreElements())
        {
            String s = e.nextElement();
            Logger l = Logger.getLogger(s);
            String p = (l.getParent() == null ? "none" : "'" + l.getParent().getName() + "'");
            System.out.println("'" + s + "': " + p);
        }
    }
}

程序的输出是

'bar': ''
'global': ''
'foo.bar': ''
'bar.baz': 'bar'
'': none

【问题讨论】:

  • java.utils.Loggers 可能很棘手。虽然我不完全理解这里的实际问题是什么,但(可能)重要的旁注:记录器可以被垃圾收集。当您在main 方法中写入Logger.getLogger("foo").setLevel(x),然后在其他地方获得带有Logger.getLogger("foo") 的记录器时,它可能是一个不同的实例!您在main 中获取的记录器可能已经被垃圾回收,第二次getLogger("foo") 调用将创建一个新实例。

标签: java logging java.util.logging


【解决方案1】:

在每个类中都有Logger.getLogger(String) 的一个负面影响是您将无法模拟它(或通过特殊的记录器)进行测试。

示例:假设您需要测试以下 C 类:

package a.b;
class C {
  private Logger logger;
  private int capacity;
  private int size;
  C(int capacity) {
    this.logger = Logger.getLogger("a.b.C");
    this.capacity = capacity;
    size = 0;
  }
  void add(int item) {
    if (size >= capacity) {
      logger.log("You already reached the capacity: " + capacity);
    }
    //...
  }
}

如果达到容量,则需要添加日志。现在你需要测试它。做一个测试来测试这个非常困难和hacky:

public void testCapacityReachedLogs() {
    C c = new C(2);
    c.add(1);
    c.add(2);
    // verify that c logged the exact string: "You already reached the capacity: 2"
}

但是,如果您有:

package a.b;
class D {
  private Logger logger;
  private int capacity;
  private int size;
  D(Logger logger, int capacity) {
    this.logger = logger;
    this.capacity = capacity;
    size = 0;
  }
  void add(int item) {
    if (size >= capacity) {
      logger.log("You already reached the capacity: " + capacity);
    }
    //...
  }
}

现在你可以模拟 Logger:

public void testCapacityReachedLogs() {
    Logger logger = getMock(Logger.class);
    D d = new D(logger, 2);
    d.add(1);
    d.add(2);
    verify(logger).log("You already reached the capacity: 2");
}

请注意,“mock”相关代码不一定遵循框架的语法,它只是示例。

【讨论】:

  • “模拟”是什么意思?你能解释一下吗?
  • @ChristianWolf 我添加了一个带有“mock”的示例
  • 啊,我明白了。感谢您的解释。
猜你喜欢
  • 1970-01-01
  • 2014-04-03
  • 2022-01-01
  • 2010-11-11
  • 1970-01-01
  • 1970-01-01
  • 2014-11-08
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多