【问题标题】:Log4j2 custom wrapperLog4j2 自定义包装器
【发布时间】:2016-07-12 14:23:10
【问题描述】:

我根据这个主题为 log4j2 记录器制作了一个包装器: How do I add a prefix to log4j messages (at the object level)

这是我有的:

导入 org.apache.log4j.Logger;

public class LogWrapper
{
    private Logger log;
    private String prefix;

    public LogWrapper(Logger log, String prefix) {
        this.log = log;
        this.prefix = prefix;
    }

    public void info(String msg)
    {
        log.error(prefix + "| " + msg);
    }
    public void error(String msg)
    {
        log.error(prefix + "| " + msg);
    }
}

用法:

public class MyClass {
    private final LogWrapper logger;
    public MyClass(String username) {
        logger = new LogWrapper(Logger.getLogger(MyClass.class.getName()), username);
    }
}

问题:

作为输出,我有一个指向 LogWrapper 类的链接

2016-07-12 21:15:17,543 ERROR [pool-3-thread-1] global.LogWrapper (LogWrapper.java:17) - blab bla bla

'LogWrapper.java:17' 它没有指向调用记录器的MyClass 中的行。

如何解决?

【问题讨论】:

  • 什么代码产生了你给我们的输出?
  • logger.info("blab bla bla");在MyClass的方法之一中
  • This link 包含一个简单的实现。

标签: java logging log4j log4j2


【解决方案1】:

Log4j 提供的内置机制在日志输出中放置前缀是 ThreadContext 映射。如何做到这一点:

代码:

// usually at some entry point from where these values won't change 
ThreadContext.put("user.ip", ipAdr);
ThreadContext.put("user.account", userAccount);

配置:

<PatternLayout pattern="%d %p %c{1.} [%t] %X{user.ip} %X{user.account} %m%n"/>

现在将值放入 ThreadContext 后的任何日志记录都将显示所需的前缀。

自定义记录器包装器可用于实现类似的功能,但工作量要大得多。

Log4j 会记住记录器的完全限定类名 (FQCN),并在配置为打印位置时使用它来遍历每个日志事件的堆栈跟踪。 (请注意,使用位置记录很慢,可能会影响应用程序的性能。)

自定义记录器包装器的问题在于它的 FQCN 与实际记录器不同,因此 Log4j 无法找到调用自定义记录器的位置。

解决方案是提供正确的 FQCN。最简单的方法是让 Log4j 为您生成记录器包装器。 Log4j 带有一个 Logger 包装器生成器工具。该工具最初旨在支持自定义日志级别,并在此处记录:https://logging.apache.org/log4j/2.x/manual/customloglevels.html#CustomLoggers

生成的记录器代码将处理 FQCN,您可以将其用作您心目中的进一步增强功能的基础。

【讨论】:

  • 我正在尝试使用 ThreadContext 执行此操作,但 user.account 从未出现在日志字符串中。可能是什么原因?顺便说一句,编译器不接受 `%X{"user.account"}`。只有不带引号才可以 " %X{user.account}"
  • 谢谢,我已经从我的回答中删除了引号。关于没有出现输出,您可以尝试仅使用 %X 吗?这应该显示放在 ThreadContext 中的 所有 键值对。另外,您是否从将 user.account 键值对放入 ThreadContext 的同一线程进行日志记录?
  • 仅使用 %X 进行了尝试。相同的。是的,我正在登录我设置ThreadContext 的同一类。所以必须是同一个线程。
  • 同一个类并不一定意味着同一个线程...您可以在调用logger.info("test message"); 之前立即调用ThreadContext.put("key", "value"); 进行实验吗? (使用一些非空或非空的固定字符串值。)
  • 是的。我正在编辑文件附加程序,但不是 STDOUT :D
【解决方案2】:

实际上,问题在于位置信息不是您想要的。当您像以前那样创建包装器时会发生这种情况。要修复它,Log4j 需要 Logger 类的完全限定类名 (FQCN)。手动创建一个这样的类并不难,但简单的方法是按照http://logging.apache.org/log4j/2.x/manual/customloglevels.html#CustomLoggers的Log4j手册中的说明进行操作

【讨论】:

    猜你喜欢
    • 2019-12-08
    • 2015-05-28
    • 1970-01-01
    • 2015-09-29
    • 1970-01-01
    • 2017-10-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多