以下3篇文章提供了如何使用中间日志记录助手的答案,并且仍然让底层记录器从客户端的方法报告给该日志记录助手(而不是将日志助手方法报告为源):
Java Logging: show the source line number of the caller (not the logging helper method)
Calling log4j's log methods indirectly (from a helper method)
Printing the "source" class in a log statement with a log4j wrapper
但似乎只提供了Log4j 1.2的答案,它提供了现在已经不存在的内容:
Category.log(String callerFQCN, Priority level, Object message, Throwable t).
Logger in the log4J 2.5 API似乎没有明显的等价物。
任何人都可以提供与直接使用Log4J 2.x兼容的答案吗?
答案 0 :(得分:5)
对于Log4j2,答案完全由使用logger包装器提供,如Example Usage of a Generated Logger Wrapper下的Log4j2手册中所述。可以简单地生成(使用那里所示的org.apache.logging.log4j.core.tools.Generate $ ExtendedLogger工具)具有单个STUB级别的记录器包装器,然后调整它以创建模仿logIfEnabled使用的自定义日志记录方法(FQCN,LEVEL,Marker,message,Throwable) - 可能忽略STUB级别并使用常规级别 - 然后根据需要删除或注释掉STUB级别及其方法)。为此,FormattedMessage可能会有所帮助。
示例:
java -cp log4j-core-2.5.jar org.apache.logging.log4j.core.tools.Generate\$ExtendedLogger com.mycomp.ExtLogger STUB=350 > com/mycomp/ExtLogger.java
然后调整生成的类(省略大多数支持方法):
public final class ExtLogger extends ExtendedLoggerWrapper {
...
private final ExtendedLoggerWrapper logger;
private static final String FQCN = ExtLogger.class.getName();
private static final Level STUB = Level.forName("STUB", 350);
//Delete this afterwards if level not used.
private ExtLogger(final Logger logger) {
super((AbstractLogger) logger, logger.getName(), logger.getMessageFactory());
this.logger = this;
}
/**
* Returns a custom Logger with the name of the calling class.
*
* @return The custom Logger for the calling class.
*/
public static ExtLogger create() {
final Logger wrapped = LogManager.getLogger();
return new ExtLogger(wrapped);
}
/**
* Returns a custom Logger using the fully qualified name of the Class as
* the Logger name.
*
* @param loggerName The Class whose name should be used as the Logger name.
* If null it will default to the calling class.
* @return The custom Logger.
*/
public static ExtLogger create(final Class<?> loggerName) {
final Logger wrapped = LogManager.getLogger(loggerName);
return new ExtLogger(wrapped);
}
...
/**
* Logs a message object with the {@code STUB} level.
*
* @param message the message object to log.
*/
public void stub(final String message) {
logger.logIfEnabled(FQCN, STUB, null, message, (Throwable) null);
}
/**
* Example: Adapt with custom formatting.
* Here DEBUG level is used just as an example.
*
* @param name
* @param value
*/
public void echo(final String name, Object value) {
Message m = new FormattedMessage("echo: %s(%s)",name,value);
logger.logIfEnabled(FQCN, Level.DEBUG, null, m, (Throwable) null);
}
...
}
然后在客户端类中,它现在将代表&#34;通过记录器的帮助方法正确地确定了该客户端,在本例中为格式化示例echo(name,value):
public class TestLog4j {
private static final ExtLogger extLogger = ExtLogger.create(TestLog4j.class);
public static void elseWhere() {
extLogger.echo("aVariableName", 4);
}
public static void main(String[] args) {
extLogger.echo("aStringVariableName","from main");
elseWhere();
}
}
Simple PatternLayout:
<PatternLayout pattern=" %-5level [%C{1}::%M(%L)] %logger{36} - %msg%n"/>
输出:
DEBUG [TestLog4j::main(63)] testlogging.TestLog4j - echo: aStringVariableName(from main)
DEBUG [TestLog4j::elseWhere(42)] testlogging.TestLog4j - echo: aVariableName(4)
一旦你对使用fQCN(log4j在堆栈跟踪中搜索)使用logger.logIfEnabled(FQCN,...),你可能希望删除或注释掉存根(.. )如果你不使用额外的等级,方法和STUB等级。
答案 1 :(得分:1)
如果您正在构建新系统,请坚持使用Webel的答案。
如果你有一个现有系统,你正在迁移到log4j2,你应该仍然可以运行generate方法(但我在下面包含一个最小的工作类),你可以添加这个提供旧的1.2 callerFQCN服务方式的函数(有点):
<div class="item">
<figure style="margin: 0px !important" itemprop="associatedMedia" itemscope itemtype="http://schema.org/ImageObject">
<a href="<?php IMAGE 2 OF GALLERY WP; ?>" itemprop="contentUrl" data-size="1800x1200" data-index="0">
<img src="<?php IMAGE 2 OF GALLERY WP; ?>" class="image" itemprop="thumbnail" alt="">
</a>
</figure>
</div>
<div class="item">
<figure style="margin: 0px !important" itemprop="associatedMedia" itemscope itemtype="http://schema.org/ImageObject">
<a href="<?php IMAGE 3 OF GALLERY WP; ?>" itemprop="contentUrl" data-size="1800x1200" data-index="0">
<img src="<?php IMAGE 3 OF GALLERY WP; ?>" class="image" itemprop="thumbnail" alt="">
</a>
</figure>
</div>
and so on.....
然后,从您的现有日志包装类中,您可以执行以下操作:
public void log(Class ignoreClassFQCN, Level level, Marker marker, String msg, Throwable throwable){
logger.logIfEnabled(ignoreClassFQCN.getName(), level, marker, msg, throwable);
}
我碰巧删除了一堆我没有使用的其他生成的函数,因为我打算为一个设计糟糕的(自定义)日志系统做一个简单的垫片。我删除了一堆我不打算使用的create()方法。所以这是一个工人阶级(值得分享的部分):
// inside ThisClass.java, denoting an old logger such as one that used log4j 1.2 with the callerFQCN parameter, or just an old logger that's naive and custom built.
private static final MyLog4j2WrapperClass newLogger = MyLog4j2WrapperClass.create();
public static void debug(String message) {
// basic example
newLogger.log(ThisClass.class, Level.DEBUG, null, message, null);
}
public static void logFailure(String message) {
// example of using a custom log level
newLogger.log(ThisClass.class, MyLog4j2WrapperClass.FAILURE, null, message, null);
}
我应该注意到,我认为这是一个垫片 - 它可以帮助你,但我强烈建议你在垫片到位后继续远离旧的测井系统。这样您就可以进行更多的增量代码更改,而无需立即完成完整的迁移。