slf4j 装饰器正在记录装饰器 FQCN,而不是调用 FQCN

slf4j decorator is logging the decorator FQCN, not the calling FQCN

我从 slf4j Logger class 创建了一个装饰器 class 因为我需要在 info, debug,等方法。我正在使用 log4j12 绑定。

除了记录的 FQCN 外它工作正常:它不是调用 class 的 FQCN,而是装饰器的 FQCN class。

package foo.bar;

import org.slf4j.Logger;

public class MyLogger implements Logger {

private final Logger logger;
private final boolean traceAndExit;

public MyLogger(Logger logger, boolean traceAndExit) {
    this.logger = logger;
    this.traceAndExit = traceAndExit;
} // MyLogger

@Override
public void info(String message) {
    try {
        logger.info(message);
    } catch (Exception e) {
        if (traceAndExit) {
            traceAndExit(e);
        } // if
    } // catch
} // info

...

如果有任何其他 class foo.bar.OtherClass 我这样做:

MyLogger myLogger = new MyLogger(LoggerFactory.getLogger(OtherClass.class), true);
myLogger.info("this is a message");

然后我获取的日志打印foo.bar.MyLogger而不是foo.bar.OtherClass%C转换字符)。

知道如何正确执行此操作吗?我必须打印 FQCN。

不幸的是,您没有提到您使用的是什么日志记录实现。 slf4j 只是一个常见的 API 由各种日志实现共享。

幸运的是,至少 Logback、Log4j 和 Log4j 2 应该以相同的方式解释 %C 格式说明符。

Logback documentation and the Log4j 2 documentation%C 定义为 "the fully-qualified class name of the caller issuing the logging request." 这分别发生在 ch.qos.logback.classic.spi.CallerDataorg.apache.logging.log4j.util.ReflectionUtil 中。基本上,框架会检查堆栈跟踪,直到他们有理由确定已经离开了自己的代码库,然后使用他们在堆栈上遇到的 "next" class 。 在您的情况下,这是 MyLogger class.

避免这种情况的最简单方法是完全放弃 %C 格式说明符。虽然在调试中很有用,但堆栈自省对性能有严重影响,无法干净地处理您的情况。

%c 格式说明符改为插入记录器的名称。如果正确初始化记录器:

// static logger
private static final Logger STATIC_LOG = LoggerFactory.getLogger(OtherClass.class);

// instance logger
private final Logger log = LoggerFactory.getLogger(getClass());

%c 产生预期的输出。这也允许高级日志记录解决方案,例如每个 class 多个记录器,例如审核日志记录。

如果您绝对必须使用 %C 说明符,Logback 提供了一个选项来设置调用者扫描忽略的框架包:

// during application startup
LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();
lc.getFrameworkPackages().add("foo.bar.logging")

请注意,这将有效地禁用整个 foo.bar.logging 包的 %C 输出。 Log4j 2 似乎没有提供类似的配置选项。