我根据以下主题为log4j2记录器做了一个包装:
如何在log4j消息中添加前缀(在对象级别)
这是我有的:
导入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的方法之一中
实际上,问题在于位置信息不是您想要的。当您完成包装后,就会发生这种情况。要修复它,Log4j需要Logger类的完全限定的类名(FQCN)。手动创建执行该操作的类并不难,但是简单的方法是遵循Log4j手册中的说明,该手册位于http://logging.apache.org/log4j/2.x/manual/customloglevels.html #CustomLoggers
已投票。非常关键。
Log4j提供的用于在日志输出中添加前缀的内置机制是ThreadContext映射。这个怎么做:
码:
// usually at some entry point from where these values won't change
ThreadContext.put("user.ip", ipAdr);
ThreadContext.put("user.account", userAccount);
组态:
现在,将值放入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");进行实验吗? (使用一些不为空或为空的固定字符串值。)
是的可以。现在-im logging [pool-2-thread-1]线程,因此它在各处显示相同的线程。
ThreadContext.put("user", username); logger.info("log after thread context");尝试过此操作-相同,上下文没有记录
猜测还必须提到ThreadPoolExecutor执行的应用程序中的所有线程
非常奇怪...请尝试ThreadContext.put("user","FIXEDVALUE"); logger.info("original value is{}", ThreadContext.get("user"));这将帮助我们确定该值在哪里消失。
logger.info("original value is:"+ ThreadContext.get("user"));正在记录" FIXEDVALUE",但未将其添加到附加程序2016-07-13 13:56:54,091 INFO [pool-2-thread-1] MyClass (MyClass.java:36) - original value is: FIXEDVALUE中,这是模式:d{yyy-MM-dd HH:mm:ss} [%t] %X{user} %-5level %logger{36} - %msg%n
啊哈!那不能是正确的布局模式:输出在线程名称之前显示INFO级别,并显示位置信息(类+行号),但是该模式首先显示线程名称,而%logger{36}则不显示位置信息。您是否更新了错误的配置文件?
那么正确的顺序是什么?如果我毕竟那样,但是在消息之前-同样的优势-从上下文中没有任何价值。 %d{yyy-MM-dd HH:mm:ss} [%t] %-5level %logger{36} %X{user} - %msg%n
不,那不是我的意思。任何命令都可以,但是显示的布局模式无法产生显示的输出,因此我认为您可能正在修改错误的log4j2.xml配置文件...您确定Log4j在布局中使用的包含%X的配置文件?
嗯是的好像我编辑错了。好瞎
谜团已揭开?! (伙计,为此我应受很多赞扬... :-D)
是的,它确实。我正在编辑文件追加器,但未编辑STDOUT:D