记录日志时为该类动态创建日志文件,并仅在log4j中登录该文件 [英] While logging log create log file dynamically for that class and log into that file only in log4j
问题描述
我在我的项目中使用log4j进行日志记录。我有一个包,它包含50多个java类。从这些日志记录日志时,如果日志语句来自A类,它应该进入A.log文件等等其他类。 我想在运行时执行此操作。不希望在log4j.xml中为所有类编写appender。在运行时,它应该能够识别该日志来自A类,因此它将其记录到A.log文件中。我希望通过在已经实现的java文件中进行最小化或无变化来实现此目的。我可以通过仅在该包的log4j.xml文件中进行更改来实现。 System.setProperty(logfilename,className)对我没用。任何帮助赞赏。
在此之前我觉得我应该指出这似乎是一种非常不寻常的日志记录策略 。通常,您希望查看特定用户与程序交互期间发生的事情的整体视图,而不是必须引用数十个尝试跟踪逻辑流程的日志文件。例如,如果用户通过调用A类来运行您的程序,然后A类使用B类,则您必须查看2个日志才能跟踪用户体验。想象一下,必须为复杂的用户交互执行此操作,这些交互流入更多类,并且还想象当执行从A到B到A到B到C到B到A时的跟踪是多么困难。就在这个小例子中你必须查看A的日志并以某种方式认识到执行将转到B类然后查看B的日志,依此类推。
所有的如上所述,如果您仍然想要走这条路线,那么我不相信您可以通过仅配置更改来实现您想要的功能,但除了配置更改之外,还可以使用最少的代码。
如果你看一下
所有这些只是一个概念验证所以你需要修改它以满足你的需要。希望它能说明你实现目标的一般方式。
I'm using log4j in my project for logging. I have one package and it contains 50+ java classes. While logging the logs from these if log statement comes from class A it should go in A.log file and etc for other classes. I want to do it at runtime. Don't want to write appenders in log4j.xml for all classes. At runtime it should be able to identify that log comes from class A so it log it into A.log file. I want achieve this by doing minimal or no changes in java file as its already implemented. Can I achieve by doing changes only in log4j.xml file of that package. System.setProperty("logfilename","className") is not useful for me. Any help appreciated.
Before anything else I feel that I should point out this seems like a very unusual logging strategy. Normally you would want to see a holistic view of what happened during a particular user's interaction with your program rather than having to refer to dozens of log files trying to trace through the flow of the logic. For example if a user runs your program by invoking class A and then class A uses Class B you already have to look at 2 logs in order to follow the user experience. Imagine having to do this for a complex user interaction that flows into many more classes and also imagine how difficult it would be to trace when the execution goes from A to B to A to B to C to B to A. Just in this small example you would have to look at the log for A and somehow recognize that execution is going to class B then look at the log for B and so on.
With all of the above said, if you still want to go this route then I don't believe you can achieve what you want with only a configuration change but it is possible with minimal code in addition to a configuration change.
If you take a look at the log4j2 manual in the section regarding Extending Log4j2 Lookups you'll see an example there of how to implement a lookup. You can create your own lookup for the logger name as follows:
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;
}
}
Now, use the Routing Appender to dynamically create appenders as needed based on the logger name at runtime by configuring it similar to the following example:
<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>
Below are two sample classes that generate some logging.
First the main class:
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();
}
}
Second class:
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");
}
}
Below is the configuration file (log4j2.xml) I used to test with. Note that I used console appender at first to verify the new lookup was working and decided to leave it in as it may be helpful to those reading this answer.
<?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>
Running SomeClass
generates two log files called "example.AnotherClass.txt" and "example.SomeClass.txt" in a directory named "logs". The logs in the first file were generated by AnotherClass
and those in the second file were generated by SomeClass
All of this is just a proof of concept so you will need to modify it to fit your needs. Hopefully it illustrates the general way you could achieve what you want.
这篇关于记录日志时为该类动态创建日志文件,并仅在log4j中登录该文件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!