Файл журнала Log4J остается пустым при программной настройке

Я пытаюсь программно настроить Log4J для записи журналов как на консоль, так и в файл журнала. Хотя вывод консоли выглядит нормально, файл журнала остается пустым (но тем не менее создается). Я использую OpenJDK 22 на Zorin 17.1 Core.

Почему это и как это исправить?

Вот минимальный рабочий пример, который напоминает проблему в моем реальном проекте:

import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.core.Filter;
import org.apache.logging.log4j.core.appender.ConsoleAppender;
import org.apache.logging.log4j.core.config.Configurator;
import org.apache.logging.log4j.core.config.LoggerConfig;
import org.apache.logging.log4j.core.config.builder.api.AppenderComponentBuilder;
import org.apache.logging.log4j.core.config.builder.api.ConfigurationBuilder;
import org.apache.logging.log4j.core.config.builder.api.ConfigurationBuilderFactory;
import org.apache.logging.log4j.core.config.builder.impl.BuiltConfiguration;

public class Main {
    public static void main(String[] args) {
        Level level = Level.WARN;

        ConfigurationBuilder<BuiltConfiguration> builder = ConfigurationBuilderFactory.newConfigurationBuilder();
        builder.setStatusLevel(level);
        builder.setConfigurationName("BuilderTest");

        AppenderComponentBuilder appenderBuilder =
            builder.newAppender("Stdout", "CONSOLE")
                .addAttribute("target", ConsoleAppender.Target.SYSTEM_OUT)
                .add(builder.newLayout("PatternLayout")
                .addAttribute("pattern", "xxxxx %d [%t] %-5level: %msg%n%throwable"))
                .add(builder.newFilter("MarkerFilter", Filter.Result.DENY, Filter.Result.NEUTRAL)
                .addAttribute("marker", "FLOW"));

        builder.add(appenderBuilder);

        appenderBuilder =
            builder.newAppender("File", "File")
            .addAttribute("fileName", "logs/main.log")
            .addAttribute("append", true)
            .addAttribute("locking", false)
            .addAttribute("immediateFlush", true)
            .add(builder.newLayout("PatternLayout")
            .addAttribute("pattern", "xxxxxx %d [%t] %-5level: %msg%n%throwable"));

        builder.add(appenderBuilder);

        builder
            .add(builder.newLogger("org.apache.logging.log4j", level)
            .add(builder.newAppenderRef("Stdout"))
            .addAttribute("additivity", false));

        builder.add(
            builder
                .newRootLogger(level)
                .add(builder.newAppenderRef("Stdout"))
        );

        Configurator.reconfigure(builder.build());
        LoggerConfig loggerConfig = new LoggerConfig(Main.class.getPackageName(), level, false);
        Configurator.setLevel(Main.class.getPackageName(), level);

        LogManager.getRootLogger().error("setLoggingLevel(): Logging level set to %s.".formatted(level));
    }
}

Вывод консоли:

xxxxx 2024-08-30 01:43:22,830 [main] ERROR: setLoggingLevel(): Logging level set to WARN.

Вот мой pom.xml:

<?xml version = "1.0" encoding = "UTF-8"?>
<project xmlns = "http://maven.apache.org/POM/4.0.0"
         xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation = "http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.example.log4j-test</groupId>
    <artifactId>log4j-test</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.source>22</maven.compiler.source>
        <maven.compiler.target>22</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <dependencies>
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
        </dependency>
        <dependency>
            <groupId>commons-logging</groupId>
            <artifactId>commons-logging</artifactId>
            <version>1.3.4</version>
        </dependency>
        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-api</artifactId>
            <version>3.0.0-beta2</version>
        </dependency>
        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-core</artifactId>
            <version>3.0.0-beta2</version>
        </dependency>
    </dependencies>
</project>
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
1
0
52
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Дерево проекта

├── pom.xml
└── src
    └── main
        └── java
            └── com
                └── example
                    └── Main.java

pom.xml

<?xml version = "1.0" encoding = "UTF-8"?>
<project xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance" xmlns = "http://maven.apache.org/POM/4.0.0"
         xsi:schemaLocation = "http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.example.log4j-test</groupId>
    <artifactId>log4j-test</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <!--
        <log4j2.version>2.19.0</log4j2.version>
        -->
        <log4j2.version>3.0.0-beta2</log4j2.version>
    </properties>

    <dependencies>

        <!-- Log4j2 core -->
        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-core</artifactId>
            <version>${log4j2.version}</version>
        </dependency>

        <!-- Log4j2 API -->
        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-api</artifactId>
            <version>${log4j2.version}</version>
        </dependency>

    </dependencies>

</project>

Main.java

package com.example;

import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.core.config.Configurator;
import org.apache.logging.log4j.core.config.builder.api.*;
import org.apache.logging.log4j.core.config.builder.impl.BuiltConfiguration;

public class Main {

    //private static final Logger logger = LogManager.getLogger(Main.class);
    //private static final Logger appLoggerInstance = LogManager.getLogger("com.example");
    
    public static void main(String[] args) {
    

    
        // Create a ConfigurationBuilder instance
        ConfigurationBuilder<BuiltConfiguration> builder = ConfigurationBuilderFactory.newConfigurationBuilder();
        builder.setStatusLevel(Level.WARN);
    
        // Create a pattern layout
        
        String pattern1 = "XXXX %d [%t] %-5level: %msg%n%throwable";
        String pattern2 = "%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n";
        
        LayoutComponentBuilder layout = builder.newLayout("PatternLayout")
                .addAttribute("pattern", pattern1 );

        // Create Console Appender
        AppenderComponentBuilder consoleAppender = builder.newAppender("Stdout", "Console")
                .addAttribute("target", "SYSTEM_OUT")
                .add(layout);

        // Create File Appender
        AppenderComponentBuilder fileAppender = builder.newAppender("File", "File")
                .addAttribute("fileName", "logs/main.log")
                .addAttribute("append", true)
                .addAttribute("locking", false)
                .addAttribute("immediateFlush", true)                
                .add(layout);

        // Add appenders to the configuration
        builder.add(consoleAppender);
        builder.add(fileAppender);

        // Root Logger configuration
        RootLoggerComponentBuilder rootLogger = builder.newRootLogger("info");
        rootLogger.add(builder.newAppenderRef("Stdout"));
        rootLogger.add(builder.newAppenderRef("File"));
        builder.add(rootLogger);

        // Application-specific Logger configuration
        LoggerComponentBuilder appLogger = builder.newLogger("com.example", "debug")
                .add(builder.newAppenderRef("Stdout"))
                .add(builder.newAppenderRef("File"))
                .addAttribute("additivity", false);

        // Add logger to the configuration
        builder.add(appLogger);

        // Apply the configuration
        Configurator.initialize(builder.build());

        // Test logging
        Logger logger = LogManager.getLogger(Main.class);
        logger.info("This is an info message from the root logger.");
        logger.debug( "This is a debug message from the root logger.");
        logger.error( "This is an error message from the root logger.");
        
        Logger appLoggerInstance = LogManager.getLogger("com.example");
        appLoggerInstance.debug("ZZZ This is a debug message from com.example logger.");
        
        LogManager.getRootLogger().error("setLoggingLevel(): Logging level set to %s.".formatted(Level.WARN));
    }
}

log4j2.xml

Программа не использует log4j2.xml, но наш программный код может использовать log4j2.xml в качестве базового преобразования преобразования.

<?xml version = "1.0" encoding = "UTF-8"?>
<Configuration status = "WARN">
    <Appenders>
        <!-- Console Appender Configuration -->
        <Console name = "Stdout" target = "SYSTEM_OUT">
            <PatternLayout pattern = "%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n"/>
        </Console>

        <!-- File Appender Configuration -->
        <File name = "File" fileName = "logs/app-log4j-xml.log" append = "true">
            <PatternLayout pattern = "%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n"/>
        </File>
    </Appenders>

    <Loggers>
        <!-- Root Logger Configuration -->
        <Root level = "info">
            <AppenderRef ref = "Stdout"/>
            <AppenderRef ref = "File"/>
        </Root>

        <!-- Application Specific Logger Configuration -->
        <Logger name = "com.example" level = "debug" additivity = "false">
            <AppenderRef ref = "Stdout"/>
            <AppenderRef ref = "File"/>
        </Logger>
    </Loggers>
</Configuration>

Стройте и запускайте

mvn clean package

mvn dependency:copy-dependencies -DoutputDirectory=target/libs

java -cp "target/libs/*:target/log4j-test-1.0-SNAPSHOT.jar" com.example.Main

Результат:

XXXX 2024-08-30 09:20:01,980 [main] INFO : This is an info message from the root logger.
XXXX 2024-08-30 09:20:02,002 [main] DEBUG: This is a debug message from the root logger.
XXXX 2024-08-30 09:20:02,002 [main] ERROR: This is an error message from the root logger.
XXXX 2024-08-30 09:20:02,003 [main] DEBUG: ZZZ This is a debug message from com.example logger.
XXXX 2024-08-30 09:20:02,003 [main] ERROR: setLoggingLevel(): Logging level set to WARN.

Сопоставление log4j2.xml с кодом

Статус конфигурации

<Configuration status = "WARN">

builder.setStatusLevel(Level.WARN);

ШаблонМакет

<PatternLayout pattern = "%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n"/>

// Create a pattern layout

String pattern1 = "XXXX %d [%t] %-5level: %msg%n%throwable";
String pattern2 = "%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n";

LayoutComponentBuilder layout = builder.newLayout("PatternLayout")
        .addAttribute("pattern", pattern1 );

Консольное приложение

<!-- Console Appender Configuration -->
<Console name = "Stdout" target = "SYSTEM_OUT">
    <PatternLayout pattern = "%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n"/>
</Console>

// Create Console Appender
AppenderComponentBuilder consoleAppender = builder.newAppender("Stdout", "Console")
        .addAttribute("target", "SYSTEM_OUT")
        .add(layout);

Консольное приложение

Код несовместим с XML. Настройте код так, чтобы он соответствовал программе, описанной в проблеме.

<!-- File Appender Configuration -->
<File name = "File" fileName = "logs/app-log4j-xml.log" append = "true">
    <PatternLayout pattern = "%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n"/>
</File>

// Create File Appender
AppenderComponentBuilder fileAppender = builder.newAppender("File", "File")
        .addAttribute("fileName", "logs/main.log")
        .addAttribute("append", true)
        .addAttribute("locking", false)
        .addAttribute("immediateFlush", true)                
        .add(layout);

Добавить приложения

// Add appenders to the configuration
builder.add(consoleAppender);
builder.add(fileAppender);

Корневой регистратор

<!-- Root Logger Configuration -->
<Root level = "info">
    <AppenderRef ref = "Stdout"/>
    <AppenderRef ref = "File"/>
</Root>

// Root Logger configuration
RootLoggerComponentBuilder rootLogger = builder.newRootLogger("info");
rootLogger.add(builder.newAppenderRef("Stdout"));
rootLogger.add(builder.newAppenderRef("File"));
builder.add(rootLogger);

Регистратор приложений

<!-- Application Specific Logger Configuration -->
<Logger name = "com.example" level = "debug" additivity = "false">
    <AppenderRef ref = "Stdout"/>
    <AppenderRef ref = "File"/>
</Logger>

// Application-specific Logger configuration
LoggerComponentBuilder appLogger = builder.newLogger("com.example", "debug")
        .add(builder.newAppenderRef("Stdout"))
        .add(builder.newAppenderRef("File"))
        .addAttribute("additivity", false);
        
// Add logger to the configuration
builder.add(appLogger);

Хороший ответ, хотя, вероятно, было бы полезно краткое изложение. То, что ОП забыл добавить в свой код, это элементы AppenderRef для приложения «Файл».

Piotr P. Karwasz 30.08.2024 08:32

(1) Main.java — это полноценная программа, которая уже содержит AppenderRef и File Appender. (2) В разделе Console Appender вы можете обнаружить, что Appenders уже содержит сопоставление File Appender.

life888888 30.08.2024 08:48

Код, в котором нет всех AppenderRef, — это код, о котором идет речь, а не ваш. Возможно, было бы полезно это отметить. Вот почему Pixelcode ничего не видит в своих файлах журналов.

Piotr P. Karwasz 30.08.2024 09:23

Вы правы, спасибо, что отметили это.

life888888 30.08.2024 09:29

Большое спасибо! Log4J действительно кажется слишком сложным для правильной настройки:/

Pixelcode 30.08.2024 15:03

Другие вопросы по теме

Похожие вопросы

Почему JPA все еще работает с классом записи как с сущностью?
Приложение Spring Framework возвращает только ошибки 404
Spring: получение ошибки грамматики неправильного sql для именованного параметра – удаление параметра устраняет ошибку
Есть ли в Visual Studio Code сочетания клавиш, которые переключают детали предложения и всплывающие окна режима объяснения в предложениях?
Вывод консоли IntelliJ IDEA неправильно отображает символы вертикальной табуляции (U + 000B)
Ошибка создания bean-компонента с именем «entityManagerFactory», определенным в ресурсе пути к классу: невозможно построить Hibernate SessionFactory;
Как использовать внешние файлы конфигурации для обеспечения специфичных для среды конфигураций в приложении Spring Boot?
Как использовать общие файлы миграции для mysql и h2
Отключение клиента администратора Kafka Streams
Укажите дополнительную версию Java в maven-compiler-plugin