Невозможно разрешить конфигурацию log4j в Android

Вопрос или проблема

Я пытаюсь реализовать log4j в Android, используя зависимости v2.24.1 в gradle:

implementation 'org.apache.logging.log4j:log4j-api:2.24.1'
implementation 'org.apache.logging.log4j:log4j-core:2.24.1'

У меня есть конфигурация log4j2.properties в директории src/main/assets:

# Конфигурация корневого логгера
status = error
name = PropertiesConfig

# Аппендารี
appender.console.type = Console
appender.console.name = Console
appender.console.target = SYSTEM_OUT
appender.console.layout.type = PatternLayout
appender.console.layout.pattern = [%d{yyyy-MM-dd HH:mm:ss.SSS}] %-5p- %m%n

# Уровень корневого логгера и аппендеры
rootLogger.level = INFO
rootLogger.appenderRefs = stdout
rootLogger.appenderRef.stdout.ref = Console

logger.com.example.log4japi.MainActivity.name = com.example.log4japi.MainActivity
logger.com.example.log4japi.MainActivity.level = DEBUG
logger.com.example.log4japi.MainActivity.additivity = false
logger.com.example.log4japi.MainActivity.appenderRefs = stdout
logger.com.example.log4japi.MainActivity.appenderRef.stdout.ref = Console

В моей основной активности я пытаюсь использовать логгер для com.example.log4japi.MainActivity, определенного выше. Активность содержит текстовое поле для отображения текущего уровня журналирования, кнопку для открытия диалогового окна и изменения уровня журналирования, а также дополнительные кнопки для печати журналов на каждом уровне:

package com.example.log4japi;

import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.widget.Button;
import android.widget.TextView;

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 java.util.Arrays;

public class MainActivity extends AppCompatActivity {

    private int logLevelIdx;

    Logger log = LogManager.getLogger(MainActivity.class);

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        //TextView отображающий уровень журналирования
        TextView logLevelTxt = findViewById(R.id.logLevelTxt);
        logLevelTxt.setText(log.getLevel().name());
        
        //Изменение уровня журналирования
        Button setLogLevelBtn = findViewById(R.id.setLogLevelBtn);
        setLogLevelBtn.setOnClickListener(v -> {
            AlertDialog.Builder alertDialog = new AlertDialog.Builder(this);
            alertDialog.setTitle("Установить уровень журналирования");

            String[] logLevels = new String[]{"OFF", "FATAL", "ERROR", "WARN", "INFO", "DEBUG", "TRACE", "ALL"};
            logLevelIdx = Arrays.asList(logLevels).indexOf(log.getLevel().name());

            alertDialog.setSingleChoiceItems(logLevels, logLevelIdx, (dialog, which) -> logLevelIdx = which);
            alertDialog.setPositiveButton("Выбрать", (dialog, which) -> {
                Configurator.setLevel(log.getName(), Level.valueOf(Arrays.asList(logLevels).get(logLevelIdx)));
                logLevelTxt.setText(log.getLevel().name());
                dialog.dismiss();
            });
            alertDialog.setNegativeButton("Отмена", (dialog, which) -> dialog.dismiss());
            alertDialog.create();
            alertDialog.show();
        });
        
        
        //Сообщения журнала
        Button fatalLogBtn = findViewById(R.id.fatalLogBtn);
        fatalLogBtn.setOnClickListener(v -> log.fatal("Текущий уровень журналирования: " + log.getLevel().name()));

        Button errorLogBtn = findViewById(R.id.errorLogBtn);
        errorLogBtn.setOnClickListener(v -> log.error("Текущий уровень журналирования: " + log.getLevel().name()));

        Button warnLogBtn = findViewById(R.id.warnLogBtn);
        warnLogBtn.setOnClickListener(v -> log.warn("Текущий уровень журналирования: " + log.getLevel().name()));

        Button infoLogBtn = findViewById(R.id.infoLogBtn);
        infoLogBtn.setOnClickListener(v -> log.info("Текущий уровень журналирования: " + log.getLevel().name()));

        Button debugLogBtn = findViewById(R.id.debugLogBtn);
        debugLogBtn.setOnClickListener(v -> log.debug("Текущий уровень журналирования: " + log.getLevel().name()));

        Button traceLogBtn = findViewById(R.id.traceLogBtn);
        traceLogBtn.setOnClickListener(v -> log.trace("Текущий уровень журналирования: " + log.getLevel().name()));
    }
}

Почему-то конфигурация не считывается или не инициализируется. Это приводит к тому, что уровень журналирования по умолчанию устанавливается в ERROR для любых логгеров, которые я пытаюсь использовать. Я также не могу изменить уровень этих логгеров с помощью Configurator.setLevel (если не использую корневой логгер).

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

// Вручную считываю log4j2.properties
LoggerContext context = (LoggerContext) LogManager.getContext(false);
try {
    InputStream inputStream = getAssets().open("log4j2.properties");
    ConfigurationSource source = new ConfigurationSource(inputStream);
    context.start(ConfigurationFactory.getInstance().getConfiguration(context, source));
} catch (IOException e) {
    e.printStackTrace();
}

но это приводит к следующему стек-трассировке:

E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.example.log4japi, PID: 10971
    java.lang.RuntimeException: Не удалось запустить активность ComponentInfo{com.example.log4japi/com.example.log4japi.MainActivity}: java.lang.UnsupportedOperationException: Этот парсер не поддерживает спецификацию "Unknown" версия "0.0"
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3449)
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3601)
        at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:85)
        at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
        at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2066)
        at android.os.Handler.dispatchMessage(Handler.java:106)
        at android.os.Looper.loop(Looper.java:223)
        at android.app.ActivityThread.main(ActivityThread.java:7656)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947)
     Caused by: java.lang.UnsupportedOperationException: Этот парсер не поддерживает спецификацию "Unknown" версия "0.0"
        at javax.xml.parsers.DocumentBuilderFactory.setXIncludeAware(DocumentBuilderFactory.java:475)
        at org.apache.logging.log4j.core.config.xml.XmlConfiguration.enableXInclude(XmlConfiguration.java:226)
        at org.apache.logging.log4j.core.config.xml.XmlConfiguration.newDocumentBuilder(XmlConfiguration.java:186)
        at org.apache.logging.log4j.core.config.xml.XmlConfiguration.<init>(XmlConfiguration.java:87)
        at org.apache.logging.log4j.core.config.xml.XmlConfigurationFactory.getConfiguration(XmlConfigurationFactory.java:46)
        at org.apache.logging.log4j.core.config.ConfigurationFactory$Factory.getConfiguration(ConfigurationFactory.java:565)
        at com.example.log4japi.MainActivity.onCreate(MainActivity.java:40)
        at android.app.Activity.performCreate(Activity.java:8000)
        at android.app.Activity.performCreate(Activity.java:7984)
        at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1309)
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3422)
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3601) 
        at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:85) 
        at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135) 
        at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95) 
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2066) 
        at android.os.Handler.dispatchMessage(Handler.java:106) 
        at android.os.Looper.loop(Looper.java:223) 
        at android.app.ActivityThread.main(ActivityThread.java:7656) 
        at java.lang.reflect.Method.invoke(Native Method) 
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592) 
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947) 

Как мне решить проблемы с чтением конфигурации?

Ответ или решение

Ваша проблема с конфигурацией Log4j в Android может быть вызвана несколькими факторами. Рассмотрим основные шаги, которые помогут вам успешно инициализировать конфигурацию Log4j.

Шаг 1: Проверьте расположение файла конфигурации

Убедитесь, что файл log4j2.properties находится в директории src/main/assets. Это важно, так как при загрузке ресурсов Android getAssets() будет искать файл именно в этой папке.

Шаг 2: Используйте правильный способ загрузки конфигурации

К сожалению, прямой способ использования ConfigurationSource через getAssets() может не обеспечивать успешную загрузку файла конфигурации. Вместо этого вы можете использовать Configurator.initialize() непосредственно с ConfigurationSource, как показано ниже:

import org.apache.logging.log4j.core.config.Configurator;
import org.apache.logging.log4j.core.config.ConfigurationSource;

// ...

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    try {
        InputStream inputStream = getAssets().open("log4j2.properties");
        ConfigurationSource source = new ConfigurationSource(inputStream);
        Configurator.initialize(null, source);
    } catch (IOException e) {
        e.printStackTrace();
    }

    // ... остальной код
}

Шаг 3: Убедитесь, что вы импортируете нужные зависимости

Кроме log4j-api и log4j-core, вам могут понадобиться и другие зависимости, чтобы обеспечить полную функциональность Log4j:

implementation 'org.apache.logging.log4j:log4j-slf4j-impl:2.24.1' // При необходимости
implementation 'org.apache.logging.log4j:log4j-api:2.24.1'
implementation 'org.apache.logging.log4j:log4j-core:2.24.1'

Шаг 4: Проверьте конфигурацию файлов и их формат

Убедитесь, что ваш файл log4j2.properties имеет правильный синтаксис. Например, у вас ошибка в секции appender:

# Измените на
rootLogger.appenderRefs = console
rootLogger.appenderRef.console.ref = Console

И для logger:

logger.com.example.log4japi.MainActivity.additivity = false
logger.com.example.log4japi.MainActivity.appenderRefs = console
logger.com.example.log4japi.MainActivity.appenderRef.console.ref = Console

Шаг 5: Минимизация возможностей конфликтов

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

Шаг 6: Ошибка с XML Parser

Ошибка, о которой вы говорите, связанная с не поддерживаемой операцией парсинга, может возникать, если библиотека Log4j пытается использовать XML-конфигурацию вместо свойств. Убедитесь, что вы действительно используете именно properties файл и что другие XML конфигурации не загружаются.

Заключение

Следуя вышеописанным шагам, вы сможете решить проблему с конфигурацией Log4j в вашем Android-приложении. Если после выполнения всех шагов проблема сохраняется, сообщите о возникающих ошибках, чтобы можно было провести дальнейшую диагностику.

Оцените материал
Добавить комментарий

Капча загружается...