简体   繁体   English

在记录日志时,为该类动态创建日志文件,并仅在log4j中登录该文件

[英]While logging log create log file dynamically for that class and log into that file only in log4j

I'm using log4j in my project for logging. 我在项目中使用log4j进行日志记录。 I have one package and it contains 50+ java classes. 我有一个包,它包含50多个Java类。 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. 在记录来自这些日志的日志时,如果log语句来自类A,则对于其他类,它应该放入A.log文件等。 I want to do it at runtime. 我想在运行时这样做。 Don't want to write appenders in log4j.xml for all classes. 不想为所有类在log4j.xml中编写附加程序。 At runtime it should be able to identify that log comes from class A so it log it into A.log file. 在运行时,它应该能够标识该日志来自类A,因此将其记录到A.log文件中。 I want achieve this by doing minimal or no changes in java file as its already implemented. 我想通过在Java文件中进行最少的更改或不更改来实现此效果,因为它已经实现了。 Can I achieve by doing changes only in log4j.xml file of that package. 我可以仅通过对该软件包的log4j.xml文件进行更改来实现吗? System.setProperty("logfilename","className") is not useful for me. System.setProperty(“ logfilename”,“ className”)对我没有用。 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. 例如,如果用户通过调用A类来运行您的程序,然后A类使用B类,则您已经必须查看2条日志才能遵循用户体验。 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. 试想一下,如果要为流入更多类的复杂的用户交互操作执行此操作,还可以想象执行从A到B到A到B到C到B到A时执行跟踪的难度。您将不得不查看A的日志,并以某种方式认识到执行将转到类B,然后查看B的日志,依此类推。

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. 如果您在有关扩展Log4j2查找的部分中阅读log4j2手册则会在其中看到有关如何实现查找的示例。 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. 以下是我用来测试的配置文件(log4j2.xml)。 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". 运行SomeClass在名为“ logs”的目录中生成两个日志文件,分别称为“ example.AnotherClass.txt”和“ example.SomeClass.txt”。 The logs in the first file were generated by AnotherClass and those in the second file were generated by SomeClass 第一个文件中的日志由AnotherClass生成,第二个文件中的日志由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. 希望它能说明您实现所需目标的一般方法。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM