我在我的项目中使用log4j进行日志记录。我有一个包,它包含50多个java类。从这些日志记录日志时,如果日志语句来自A类,则它应该放在A.log文件中,等等用于其他类。 我想在运行时执行此操作。不想在log4j.xml中为所有类编写appender。在运行时,它应该能够识别该日志来自A类,因此它将其记录到A.log文件中。我希望通过在已经实现的java文件中进行最小化或无变化来实现此目的。我可以通过仅在该包的log4j.xml文件中进行更改来实现。 System.setProperty(" logfilename"," className")对我没用。任何帮助赞赏。
答案 0 :(得分:0)
在此之前,我觉得我应该指出这似乎是一种非常不寻常的日志记录策略。通常,您希望看到特定用户与您的程序交互过程中发生的事情的整体视图,而不是必须引用几十个尝试跟踪逻辑流程的日志文件。例如,如果用户通过调用A类来运行您的程序,然后A类使用B类,则您必须查看2个日志才能跟踪用户体验。想象一下,必须为复杂的用户交互执行此操作,这些交互流入更多类,并且还想象当执行从A到B到A到B到C到B到A时的跟踪是多么困难。就在这个小例子中你必须查看A的日志,并以某种方式认识到执行将转到B类,然后查看B的日志,依此类推。
如上所述,如果您仍然想要走这条路线,那么我不相信您可以通过仅配置更改来实现您想要的功能,但是可以使用最少的代码除了配置更改。
如果您查看有关log4j2 manual的部分中的Extending Log4j2 Lookups,您会看到有关如何实施查找的示例。您可以按如下方式为记录器名称创建自己的查找:
package example;
import org.apache.logging.log4j.core.LogEvent;
import org.apache.logging.log4j.core.config.plugins.Plugin;
import org.apache.logging.log4j.core.lookup.StrLookup;
@Plugin(name = "logger", category = "Lookup")
public class LoggerLookup implements StrLookup{
/**
* Lookup the value for the key.
* @param key the key to be looked up, may be null
* @return The value for the key.
*/
public String lookup(String key) {
return null;
}
/**
* Lookup the value for the key using the data in the LogEvent.
* @param event The current LogEvent.
* @param key the key to be looked up, may be null
* @return The value associated with the key.
*/
public String lookup(LogEvent event, String key) {
if("name".equals(key)){
return event.getLoggerName();
}
return null;
}
}
现在,使用Routing Appender根据需要在运行时根据记录器名称动态创建appender,方法与以下示例类似:
<Routing name="MyRoutingAppender">
<Routes pattern="$${logger:name}">
<Route>
<File
fileName="logs/${logger:name}.txt"
name="appender-${logger:name}">
<PatternLayout>
<Pattern>%d{HH:mm:ss.SSS} [%t] %-5level ${logger:name} - %msg%n</Pattern>
</PatternLayout>
</File>
</Route>
</Routes>
</Routing>
以下是两个生成一些日志记录的示例类。
首先是主要课程:
package example;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public class SomeClass {
private static final Logger log = LogManager.getLogger();
public static void main(String[] args){
log.info("Here's some info!");
log.error("Some erorr happened!");
AnotherClass ac = new AnotherClass();
ac.logSomething();
}
}
第二课:
package example;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public class AnotherClass {
private static final Logger log = LogManager.getLogger();
public void logSomething(){
log.info("This is yet another info message");
}
}
下面是我用来测试的配置文件(log4j2.xml)。请注意,我首先使用了控制台appender来验证新的查找是否正常工作,并决定将其保留,因为它可能对阅读此答案的人有所帮助。
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN">
<Appenders>
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level ${logger:name} - %msg%n" />
</Console>
<Routing name="MyRoutingAppender">
<Routes pattern="$${logger:name}">
<Route>
<File
fileName="logs/${logger:name}.txt"
name="appender-${logger:name}">
<PatternLayout>
<Pattern>%d{HH:mm:ss.SSS} [%t] %-5level ${logger:name} - %msg%n</Pattern>
</PatternLayout>
</File>
</Route>
</Routes>
</Routing>
</Appenders>
<Loggers>
<Root level="debug">
<AppenderRef ref="Console" level="info" />
<AppenderRef ref="MyRoutingAppender" level="info" />
</Root>
</Loggers>
</Configuration>
运行SomeClass
会在名为“logs”的目录中生成两个名为“example.AnotherClass.txt”和“example.SomeClass.txt”的日志文件。第一个文件中的日志由AnotherClass
生成,第二个文件中的日志由SomeClass
生成
所有这些只是概念验证,因此您需要对其进行修改以满足您的需求。希望它能说明你实现目标的一般方式。