Log4j2 динамически регистрирует, что не создается во время выполнения - PullRequest
0 голосов
/ 14 сентября 2018
Файл

log4j2.xml динамически создается во время выполнения с помощью Java-программы.

<?xml version="1.0" encoding="UTF-8"?>
    <Configuration status="error">
        <Appenders>
            <RollingRandomAccessFile
                name="Application" immediateFlush="false"
                fileName="logs/FixGatewayLogs/Application.log"
                append="true"
                filePattern="logs/FixGatewayLogs/Application-%d{dd-MM-yyyy}-%i.log.gz">
                <PatternLayout>
                    <Pattern>%d %-5p [%t] (%F:%L) - %m%n</Pattern>
                </PatternLayout>
                <Policies>
                    <SizeBasedTriggeringPolicy size="100 MB" />
                </Policies>
                <DefaultRolloverStrategy fileIndex="max"
                    max="20" />
            </RollingRandomAccessFile>
            <RollingRandomAccessFile name="FirstUser"
                immediateFlush="false"
                fileName="logs/FixAcceptorLogs/FirstUser.log"
                append="true"
                filePattern="logs/FixAcceptorLogs/FirstUser-%d{dd-MM-yyyy}-%i.log.gz">
                <PatternLayout>
                    <Pattern>%d %F - %m%n</Pattern>
                </PatternLayout>
                <Policies>
                    <SizeBasedTriggeringPolicy size="100 MB" />
                </Policies>
                <DefaultRolloverStrategy fileIndex="max"
                    max="20" />
            </RollingRandomAccessFile>
            <RollingRandomAccessFile name="SecondUser"
                immediateFlush="false"
                fileName="logs/FixAcceptorLogs/SecondUser.log"
                append="true"
                filePattern="logs/FixAcceptorLogs/SecondUser-%d{dd-MM-yyyy}-%i.log.gz">
                <PatternLayout>
                    <Pattern>%d %F - %m%n</Pattern>
                </PatternLayout>
                <Policies>
                    <SizeBasedTriggeringPolicy size="100 MB" />
                </Policies>
                <DefaultRolloverStrategy fileIndex="max"
                    max="20" />
            </RollingRandomAccessFile>
        </Appenders>
        <Loggers>
            <AsyncLogger name="Application" level="debug"
                includeLocation="false" additivity="false">
                <AppenderRef ref="Application" />
            </AsyncLogger>
            <AsyncLogger name="FirstUser" level="debug"
                includeLocation="false" additivity="false">
                <AppenderRef ref="FirstUser" />
            </AsyncLogger>
            <AsyncLogger name="SecondUser" level="debug"
                includeLocation="false" additivity="false">
                <AppenderRef ref="SecondUser" />
            </AsyncLogger>
        </Loggers>
    </Configuration>

Основной класс

public class CreateLog4jApplication {

        static GenerateLog4j generateLog4j = new GenerateLog4j();

        public static void main(String[] args) {
            try {
                createLog4jFile();
                //System.setProperty("log4j.configurationFile","./src/main/resources/log4j2.xml");
            }
            catch(Exception e){
                System.out.println("CreateLog4jApplication Main Exception : " + e);
            }
         }

        public static void createLog4jFile() {
            try{
                // Create instance of OPTopicListener
                System.out.println("run() of CreateLog4jApplication");

                List<String> initiatorList = new ArrayList<String>();
                initiatorList.add("First");

                generateLog4j.generateLog4j2XMLFile(initiatorList);

                //((org.apache.logging.log4j.core.LoggerContext) LogManager.getContext(true)).reconfigure();

                Logger logger = LoggerFactory.getLogger("First");

                logger.info("Enter First File");

                System.out.println("After Logger add First file");

                Thread.sleep(5000);

                initiatorList.add("Second");

                generateLog4j.generateLog4j2XMLFile(initiatorList);

                //((org.apache.logging.log4j.core.LoggerContext) LogManager.getContext(true)).reconfigure();

                Logger logger1 = LoggerFactory.getLogger("Second");

                logger1.info("Enter Second File");

                System.out.println("After Logger add Second file");

                // This prevents program exit
                CountDownLatch  shutdownLatch = new CountDownLatch(1);
                shutdownLatch.await();
            }
            catch(Exception e){
                System.out.println("run() of CreateLog4jApplication Exception : " + e);
            }       
        }

    }

Класс GenerateLog4j

public class GenerateLog4j {
public void generateLog4j2XMLFile(List<String> initiatorList) {
    try {
        System.out.println("InitiatorList : " + initiatorList + " " + initiatorList.size());

        File       fileForDelete    = new File("src/main/resources/log4j2.xml");
        fileForDelete.delete();

        File       fileForWrite     = new File("src/main/resources/log4j2.xml");
        FileWriter fileWriterObject = new FileWriter(fileForWrite, true);


        fileWriterObject.write("<?xml version=" + "\"1.0\"" + " " + "encoding=" + "\"UTF-8\"" + "?>" + System.getProperty("line.separator"));
        fileWriterObject.write("<Configuration status="+ "\""+ "error" +"\"" +">" + System.getProperty("line.separator"));
        fileWriterObject.write("<Appenders>" + System.getProperty("line.separator"));

        fileWriterObject.close();

        String beginString       = "FIX.4.4";
        String tradesAcceptorID  = "FIX_44_ACCEPTOR_TR";


        // Iterate through the List and create entry for each Appender in XML file 
        for(int fileIndex = 0; fileIndex < (initiatorList.size() + 1); fileIndex++) {
            String appName     = null;
            String filePath    = null;
            String filePattern = null;
            String pattern     = null;
            String logLevel    = null;

            if(fileIndex == 0) { // FixGateway.log
                appName  = "OrderProcessorApplication";
                filePath = "logs/FixGatewayLogs/" + appName + ".log";
                filePattern = "logs/FixGatewayLogs/" + appName +"-%d{dd-MM-yyyy}-%i.log.gz";
                pattern  = "%d %-5p [%t] (%F:%L) - %m%n";
                logLevel = "trace";

                writeAppenderToLog4j2XMLFile(appName, filePath, filePattern, pattern, logLevel);
            }
            else { //Initiator
                // Create entry for Trades Session in XML file
                //appName = initiatorList.get(fileIndex - 1) + "_TR";
                appName = initiatorList.get(fileIndex-1);
                //filePath = "logs/FixAcceptorLogs/" + beginString + "-" + tradesAcceptorID + "-" + appName + ".log";
                filePath = "logs/FixAcceptorLogs/" + appName + ".log";
                filePattern = "logs/FixAcceptorLogs/" + appName +"-%d{dd-MM-yyyy}-%i.log.gz";
                pattern  = "%d %F - %m%n";
                logLevel = "trace";

                writeAppenderToLog4j2XMLFile(appName, filePath, filePattern, pattern, logLevel);
            }
        }


        File       fileForWriteOne     = new File("src/main/resources/log4j2.xml");
        FileWriter fileWriterObjectOne = new FileWriter(fileForWriteOne, true);

        fileWriterObjectOne.write("</Appenders>" + System.getProperty("line.separator"));
        fileWriterObjectOne.write("<Loggers>" + System.getProperty("line.separator"));

        fileWriterObjectOne.close();


        // Iterate through the List and create entry for each Logger in XML file
        for(int fileIndex = 0; fileIndex < (initiatorList.size() + 1); fileIndex++) {
            String appName  = null;
            String logLevel = null;

            if(fileIndex == 0) { // OrderProcessorApplication.log
                appName  = "OrderProcessorApplication";
                logLevel = "trace";

                writeLoggerToLog4j2XMLFile(appName, logLevel);
            }
            else { // Initiator
                // Create entry for Trades Session in XML file
                appName = initiatorList.get(fileIndex-1);
                logLevel = "trace";

                writeLoggerToLog4j2XMLFile(appName, logLevel);      
            }
        }

        File       fileForWriteTwo     = new File("src/main/resources/log4j2.xml");
        FileWriter fileWriterObjectTwo = new FileWriter(fileForWriteTwo, true);

        fileWriterObjectTwo.write("</Loggers>"+ System.getProperty("line.separator"));
        fileWriterObjectTwo.write("</Configuration>"+ System.getProperty("line.separator"));

        // Close file handle
        fileWriterObjectTwo.close();

        System.out.println("generateLog4j2XMLFile Completed.");
     }
    catch(Exception e) {
        System.out.println("Exception In generateLog4j2XMLFile: " + e);
    }
}

public void writeLoggerToLog4j2XMLFile(String appName, String logLevel) {
    try {
        File       fileForWrite  = new File("src/main/resources/log4j2.xml");
        FileWriter fileWriterObject = new FileWriter(fileForWrite, true);

        fileWriterObject.write("<AsyncLogger name="+"\""+ appName +  "\"" +" " +"level="+"\"" + logLevel + "\""+" "+"includeLocation="+"\"true\""+" "+ "additivity="+"\"false\""+">"+ System.getProperty("line.separator"));
        fileWriterObject.write("<AppenderRef ref="+"\"" + appName +"\"" + "/>" + System.getProperty("line.separator"));
        fileWriterObject.write("</AsyncLogger>"+ System.getProperty("line.separator"));

        fileWriterObject.close();
    }
    catch(Exception e) {
        System.out.println("Exception In writeLoggerToLog4j2XMLFile : " + e);
    }
}

public void writeAppenderToLog4j2XMLFile(
        String appName, String filePath, String filePattern, String pattern, String logLevel) { 
        try {
            File       fileForWrite  = new File("src/main/resources/log4j2.xml");
            FileWriter fileWriterObject = new FileWriter(fileForWrite, true);

            String fileRollOverSize = "100 MB";
            String maxNumberOfFiles = "20";  

            fileWriterObject.write("<RollingRandomAccessFile name=" + "\"" + appName + "\"" + " immediateFlush=" + "\""  + "false" + "\"" + " fileName=" + "\""+ filePath +"\""+" "+ "append=" + "\"true\"" +" "+ "filePattern=" + "\"" + filePattern + "\">"+ System.getProperty("line.separator"));
            fileWriterObject.write("<PatternLayout>" + System.getProperty("line.separator"));
            fileWriterObject.write("<Pattern>" + pattern + "</Pattern>" + System.getProperty("line.separator"));
            fileWriterObject.write("</PatternLayout>" + System.getProperty("line.separator"));

            fileWriterObject.write("<Policies>" + System.getProperty("line.separator"));
            fileWriterObject.write("<SizeBasedTriggeringPolicy size="+"\"" + fileRollOverSize + "\""+ "/>" + System.getProperty("line.separator"));
            fileWriterObject.write("</Policies>" + System.getProperty("line.separator"));
            fileWriterObject.write("<DefaultRolloverStrategy fileIndex="+"\"max\""+" "+"max="+"\"" + maxNumberOfFiles + "\""+"/>"+ System.getProperty("line.separator"));
            fileWriterObject.write("</RollingRandomAccessFile>" + System.getProperty("line.separator"));

            fileWriterObject.close();
        }
        catch(Exception e) {
            System.out.println("Exception In writeAppenderToLog4j2XMLFile: " + e);
        }
    }

}

Зависимости Maven

<!-- https://mvnrepository.com/artifact/com.lmax/disruptor -->
        <dependency>
            <groupId>com.lmax</groupId>
            <artifactId>disruptor</artifactId>
            <version>3.3.0</version>
        </dependency>


        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-api</artifactId>
            <version>2.8.2</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/org.slf4j/slf4j-api -->
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>1.7.25</version>
        </dependency>

        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-slf4j-impl</artifactId>
            <version>2.8.2</version>
        </dependency> 

        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-core</artifactId>
            <version>2.8.2</version>
         </dependency>

Когда один пользователь добавляется в XML-файл с помощью кода, создается файл журнала, но когда второй пользователь добавляется динамически с помощью кода, файл журнала не создается.

ПРИМЕЧАНИЕ. В журналах находятся две разные папки. Один для FixGateway, другой для FixAcceptor.

Я пытался найти проблему в Google и других блогах, но не удалось устранить эту ошибку.

Ответы [ 2 ]

0 голосов
/ 21 сентября 2018

Не уверен, что вы там делаете, особенно с

File fileForDelete = new File("src/main/resources/log4j2.xml");

В любом случае, вы можете использовать org.apache.logging.log4j.core.LoggerContext.setConfigLocation(URI), чтобы заменить текущую конфигурацию новой:

((LoggerContext) LogManager.getContext(false)).setConfigLocation(newUri);

IЯ предполагаю, что ваш код, кажется, работает в первый раз, потому что вы заменяете xml-файл до инициализации log4j2 - если вы запишете какое-либо сообщение перед вызовом createLog4jFile(), держу пари, оно перестанет обманывать вас, заставляя поверить, что оно работает.

Программная конфигурация может подойти для вашего варианта использования лучше, чем ... хак, который вы используете в настоящее время - см. https://logging.apache.org/log4j/2.x/manual/customconfig.html для некоторых указателей.

PS: если у вас есть log4j-slf4j-imp в качестве зависимости вам не понадобится slf4j-api (она будет считаться транзитивной зависимостью log4j-slf4j-imp)

0 голосов
/ 19 сентября 2018

Я думаю, что ты делаешь себе сложнее, чем нужно.Log4j2 предоставляет RoutingAppender , который можно использовать для динамической записи в отдельные файлы журнала без изменения вашего файла конфигурации вообще.

Я создал простой пример, используя некоторые из вашихКонфигурация для иллюстрации того, как вы можете делать то, что вы хотите, без программного изменения файла конфигурации.

Вот класс, содержащий метод main, который мы будем использовать для запуска log4j2:

package pkg;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.ThreadContext;

public class Log4j2DiffFilePerUserMain {
    private static final Logger LOG = LogManager.getLogger();
    private static final Logger USER_LOG = LogManager.getLogger("Users");

    public static void main(String[] args){

        ThreadContext.put("userId", "user1");
        LOG.info("Now generating user1 log entry");
        USER_LOG.info("This should appear in user1 log file");

        ThreadContext.put("userId", "user2");
        LOG.info("Now generating user2 log entry");
        USER_LOG.info("This should appear in user2 log file");
    }
}

Обратите внимание, как main вызывает ThreadContext.put дважды.Это имитирует выполнение кода разными пользователями.Также обратите внимание, что есть два регистратора - один для «Приложения» и один для «Пользователей».Основываясь на вашей конфигурации, я полагаю, что вы хотели оставить это отдельно.

Вот конфигурация log4j2.xml:

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN">
    <Appenders>
        <RollingRandomAccessFile
            name="Application" immediateFlush="false"
            fileName="logs/FixGatewayLogs/Application.log"
            append="true"
            filePattern="logs/FixGatewayLogs/Application-%d{dd-MM-yyyy}-%i.log.gz">
            <PatternLayout>
                <Pattern>%d %-5p [%t] (%F:%L) - %m%n</Pattern>
            </PatternLayout>
            <Policies>
                <SizeBasedTriggeringPolicy size="100 MB" />
            </Policies>
            <DefaultRolloverStrategy fileIndex="max"
                max="20" />
        </RollingRandomAccessFile>
        <Routing name="UsersAppender">
            <Routes pattern="$${ctx:userId}">
                <Route>
                    <RollingRandomAccessFile name="user-${ctx:userId}"
                        immediateFlush="false"
                        fileName="logs/FixAcceptorLogs/${ctx:userId}.log"
                        append="true"
                        filePattern="logs/FixAcceptorLogs/${ctx:userId}-%d{dd-MM-yyyy}-%i.log.gz">
                        <PatternLayout>
                            <Pattern>%d %F - %m%n</Pattern>
                        </PatternLayout>
                        <Policies>
                            <SizeBasedTriggeringPolicy size="100 MB" />
                        </Policies>
                        <DefaultRolloverStrategy fileIndex="max"
                            max="20" />
                    </RollingRandomAccessFile>
                </Route>
            </Routes>
        </Routing>
    </Appenders>
    <Loggers>
        <Root level="info">
            <AppenderRef ref="Application" />
        </Root>
        <Logger name="Users" level="debug"
            includeLocation="false" additivity="false">
            <AppenderRef ref="UsersAppender" />
        </Logger>
    </Loggers>
</Configuration>

Как вы можете видеть, я использовал RoutingAppender очень похожекак это было использовано на странице log4j2 FAQ .Он использует переменную контекста userId, чтобы динамически решить, в какой журнал отправлять сообщения.

При выполнении вышеуказанного кода и конфигурации создаются 3 файла в 2 папках:

enter image description here

Файл user1.log содержит: 2018-09-18 20:12:42,482 - This should appear in user1 log file

Файл user2.log содержит: 2018-09-18 20:12:42,485 - This should appear in user2 log file

Наконец, журнал приложения содержит:

2018-09-18 20:12:42,480 INFO  [main] (Log4j2DiffFilePerUserMain.java:14) - Now generating user1 log entry
2018-09-18 20:12:42,485 INFO  [main] (Log4j2DiffFilePerUserMain.java:19) - Now generating user2 log entry

Надеюсь, это поможет вам.

...