Как настроить log4j 2.x чисто программно?

Как настроить log4j 2.3 с помощью console appender чисто программно (без файлов конфигурации любого формата)?

В основном я ищу версию 2.x этого код 1.x.

В своих классах я бы использовал

private static final Logger logger = LogManager.getLogger();
// 
    // some method
       logger.debug(someString);

Без какой-либо конфигурации я (как и ожидалось) сталкиваюсь

ОШИБКА StatusLogger Не найден файл конфигурации log4j2. Использование конфигурации по умолчанию: запись в консоль только ошибок.

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

Самое близкое, что я получил, это эта статья, в которой по-прежнему используется фиктивный файл.

Вот мой лучший (хотя и совершенно неудачный) снимок:

private static void configureLog4J() {
    PatternLayout layout = PatternLayout.createDefaultLayout();
    ConsoleAppender appender = ConsoleAppender.createDefaultAppenderForLayout(layout);
    LoggerConfig loggerConfig = new LoggerConfig();
    loggerConfig.addAppender(appender, DEBUG, null);
}

Я что-то пропустил?

Если это все еще дело RTFM, пожалуйста, укажите мне правильное направление.


person PM 77-1    schedule 17.06.2015    source источник
comment
log4j2 напрямую, без всяких slf4j?   -  person Sotirios Delimanolis    schedule 17.06.2015
comment
@SotiriosDelimanolis - Да, это было намерением.   -  person PM 77-1    schedule 17.06.2015
comment
Чистая программная конфигурация также отсутствовала в журнале до недавнего времени. См. stackoverflow.com/questions/22335441/. . В этом сообщении SO есть ссылка на log4j2, которую я никогда не мог заставить log4j2 загружаться с помощью моего кода инициализации, но последний журнал позволит вам контролировать процесс инициализации.   -  person Adam Gent    schedule 18.06.2015


Ответы (5)


package com;

import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.core.Appender;
import org.apache.logging.log4j.core.LoggerContext;
import org.apache.logging.log4j.core.appender.ConsoleAppender;
import org.apache.logging.log4j.core.config.AppenderRef;
import org.apache.logging.log4j.core.config.Configuration;
import org.apache.logging.log4j.core.config.LoggerConfig;
import org.apache.logging.log4j.core.layout.PatternLayout;

import java.nio.charset.Charset;

public class MyLoggerTest  {

    public static void main(String[] args){
        LoggerContext context= (LoggerContext) LogManager.getContext();
        Configuration config= context.getConfiguration();

        PatternLayout layout= PatternLayout.createLayout("%m%n", null, null, Charset.defaultCharset(),false,false,null,null);
        Appender appender=ConsoleAppender.createAppender(layout, null, null, "CONSOLE_APPENDER", null, null);
        appender.start();
        AppenderRef ref= AppenderRef.createAppenderRef("CONSOLE_APPENDER",null,null);
        AppenderRef[] refs = new AppenderRef[] {ref};
        LoggerConfig loggerConfig= LoggerConfig.createLogger("false", Level.INFO,"CONSOLE_LOGGER","com",refs,null,null,null);
        loggerConfig.addAppender(appender,null,null);

        config.addAppender(appender);
        config.addLogger("com", loggerConfig);
        context.updateLoggers(config);

        Logger logger=LogManager.getContext().getLogger("com");
        logger.info("HELLO_WORLD");


    }
}

Не уверен, что это то, что вы ищете. Это создает конфигурацию по умолчанию и добавляет средство ведения журнала консоли. Однако LogManager.getLogger() не работает, а использование LogManager.getContext().getLogger() не позволяет использовать иерархию регистратора. Честно говоря, я не рекомендую программный подход, у Log4j2 на него аллергия.

person alan7678    schedule 22.06.2015

Вот полный пример программной конфигурации log4j 2.8. Он имеет 3 приложения: RollingFile, JDBC и SMTP.

Существует 1 файл конфигурации класса и 2 свойства, один для регистрации класса в качестве log4j2 configurationFactory, а другой для установки свойств, таких как каталог файла журнала.

Класс № 1: MPLoggingConfiguration

package com.websitester.config;

import java.io.Serializable;
import java.nio.charset.Charset;
import java.util.zip.Deflater;

import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.core.Appender;
import org.apache.logging.log4j.core.Layout;
import org.apache.logging.log4j.core.LoggerContext;
import org.apache.logging.log4j.core.appender.RollingFileAppender;
import org.apache.logging.log4j.core.appender.SmtpAppender;
import org.apache.logging.log4j.core.appender.db.ColumnMapping;
import org.apache.logging.log4j.core.appender.db.jdbc.ColumnConfig;
import org.apache.logging.log4j.core.appender.db.jdbc.ConnectionSource;
import org.apache.logging.log4j.core.appender.db.jdbc.DataSourceConnectionSource;
import org.apache.logging.log4j.core.appender.db.jdbc.JdbcAppender;
import org.apache.logging.log4j.core.appender.rolling.CompositeTriggeringPolicy;
import org.apache.logging.log4j.core.appender.rolling.DefaultRolloverStrategy;
import org.apache.logging.log4j.core.appender.rolling.OnStartupTriggeringPolicy;
import org.apache.logging.log4j.core.appender.rolling.SizeBasedTriggeringPolicy;
import org.apache.logging.log4j.core.appender.rolling.TriggeringPolicy;
import org.apache.logging.log4j.core.config.AppenderRef;
import org.apache.logging.log4j.core.config.Configuration;
import org.apache.logging.log4j.core.config.ConfigurationFactory;
import org.apache.logging.log4j.core.config.ConfigurationSource;
import org.apache.logging.log4j.core.config.DefaultConfiguration;
import org.apache.logging.log4j.core.config.LoggerConfig;
import org.apache.logging.log4j.core.config.Order;
import org.apache.logging.log4j.core.config.Property;
import org.apache.logging.log4j.core.config.plugins.Plugin;
import org.apache.logging.log4j.core.layout.HtmlLayout;
import org.apache.logging.log4j.core.layout.PatternLayout;

public class MPLoggingConfiguration {

    public static final String WEBSITESTER_LOGGER_NAME = "com.websitester";
    public static final String FILE_PATTERN_LAYOUT = "%n[%d{yyyy-MM-dd HH:mm:ss}] [%-5p] [%l]%n\t%m%n%n";
    public static final String LOG_FILE_NAME = "awmonitor.log";
    public static final String LOG_FILE_NAME_PATTERN = "awmonitor-%i.log";  

    /**
     * Just to make JVM visit this class to initialize the static parts.
     */
    public static void configure() {
    }

    @Plugin(category = ConfigurationFactory.CATEGORY, name = "MPConfigurationFactory")
    @Order(15)
    public static class MPConfigurationFactory  extends ConfigurationFactory {
        public static final String[] SUFFIXES = new String[] {".json", "*"};

        @Override
        protected String[] getSupportedTypes() {
            return SUFFIXES;
        }

        @Override
        public Configuration getConfiguration(LoggerContext arg0, ConfigurationSource arg1) {
            return new Log4j2Configuration(arg1);
        }
    }

    private static class Log4j2Configuration extends DefaultConfiguration {

        public Log4j2Configuration(ConfigurationSource source) {
            super.doConfigure();
            setName("mp-log4j2");

            String logFilePath = "/log/weblogic/wl-moniport/";

            // LOGGERS
            //      com.websitester
            AppenderRef[] refs = new AppenderRef[] {};
            Property[] properties = new Property[] {};
            LoggerConfig websitesterLoggerConfig = LoggerConfig.createLogger(true, Level.INFO, WEBSITESTER_LOGGER_NAME, "true", refs, properties, this, null);
            addLogger(WEBSITESTER_LOGGER_NAME, websitesterLoggerConfig);


            // APPENDERS
            final Charset charset = Charset.forName("UTF-8");

            //      MP ROLLING FILE
            TriggeringPolicy mpFileCompositePolicy = CompositeTriggeringPolicy.createPolicy(
                    SizeBasedTriggeringPolicy.createPolicy("3 M"),
                    OnStartupTriggeringPolicy.createPolicy(1));
            final DefaultRolloverStrategy mpFileRolloverStrategy = DefaultRolloverStrategy.createStrategy("9", "1", "max", Deflater.NO_COMPRESSION + "", null, true, this);
            Layout<? extends Serializable> mpFileLayout = PatternLayout.newBuilder()
                    .withPattern(FILE_PATTERN_LAYOUT)
                    .withPatternSelector(null)
                    .withConfiguration(this)
                    .withRegexReplacement(null)
                    .withCharset(charset)
                    .withAlwaysWriteExceptions(isShutdownHookEnabled)
                    .withNoConsoleNoAnsi(isShutdownHookEnabled)
                    .withHeader(null)
                    .withFooter(null)
                    .build();
            Appender mpFileAppender = RollingFileAppender.newBuilder()
                    .withAdvertise(Boolean.parseBoolean(null))
                    .withAdvertiseUri(null)
                    .withAppend(true)
                    .withBufferedIo(true)
                    .withBufferSize(8192)
                    .setConfiguration(this)
                    .withFileName(logFilePath + LOG_FILE_NAME)
                    .withFilePattern(logFilePath + LOG_FILE_NAME_PATTERN)
                    .withFilter(null)
                    .withIgnoreExceptions(true)
                    .withImmediateFlush(true)
                    .withLayout(mpFileLayout)
                    .withCreateOnDemand(false)
                    .withLocking(false)
                    .withName("error_file_web")
                    .withPolicy(mpFileCompositePolicy)
                    .withStrategy(mpFileRolloverStrategy)
                    .build();
            mpFileAppender.start();
            addAppender(mpFileAppender);
            getLogger(WEBSITESTER_LOGGER_NAME).addAppender(mpFileAppender, Level.DEBUG, null);


            // JDBC
            if (System.getProperty("log4jjdbcjndiName") != null){
                ColumnConfig[] columnConfigs = new ColumnConfig[] {
                        ColumnConfig.newBuilder()
                        .setConfiguration(this)
                        .setName("DATED")
                        .setPattern(null)
                        .setLiteral(null)
                        .setEventTimestamp(true)
                        .setUnicode(false)
                        .setClob(false)
                        .build(),
                        ColumnConfig.newBuilder()
                        .setConfiguration(this)
                        .setName("LOGGER")
                        .setPattern("%logger")
                        .setLiteral(null)
                        .setEventTimestamp(false)
                        .setUnicode(false)
                        .setClob(false)
                        .build(),
                        ColumnConfig.newBuilder()
                        .setConfiguration(this)
                        .setName("LOG_LEVEL")
                        .setPattern("%level")
                        .setLiteral(null)
                        .setEventTimestamp(false)
                        .setUnicode(false)
                        .setClob(false)
                        .build(),
                        ColumnConfig.newBuilder()
                        .setConfiguration(this)
                        .setName("MESSAGE")
                        .setPattern("%message")
                        .setLiteral(null)
                        .setEventTimestamp(false)
                        .setUnicode(false)
                        .setClob(false)
                        .build(),
                        ColumnConfig.newBuilder()
                        .setConfiguration(this)
                        .setName("NODE")
                        .setPattern("" + System.getProperty("log4jmpserverid"))
                        .setLiteral(null)
                        .setEventTimestamp(false)
                        .setUnicode(false)
                        .setClob(false)
                        .build()
                };
                ConnectionSource dataSourceConnectionSource = DataSourceConnectionSource.createConnectionSource(System.getProperty("log4jjdbcjndiName"));
                if (dataSourceConnectionSource != null){
                    Appender jdbcAppender = JdbcAppender.newBuilder()
                            .setBufferSize(0)
                            .setColumnConfigs(columnConfigs)
                            .setColumnMappings(new ColumnMapping[]{})
                            .setConnectionSource(dataSourceConnectionSource)
                            .setTableName("MTDTLOGS")
                            .withName("databaseAppender")
                            .withIgnoreExceptions(true)
                            .withFilter(null)
                            .build();
                    jdbcAppender.start();
                    addAppender(jdbcAppender);
                    getLogger(WEBSITESTER_LOGGER_NAME).addAppender(jdbcAppender, Level.WARN, null);
                }
            };

            // SMTP
            if (System.getProperty("log4jemailSubject") != null){
                if (System.getProperty("log4jemailLevel").equalsIgnoreCase("error")) {
                    Layout<? extends Serializable> mpHtmlLayout = HtmlLayout.createLayout(false, "Monitor de Portales", null, null, "x-small", null);

                    Appender smtpAppender = SmtpAppender.createAppender(
                            this,
                            "SMTP",
                            System.getProperty("log4jemailTo"), 
                            System.getProperty("log4jemailcc"), 
                            System.getProperty("log4jemailbcc"), 
                            System.getProperty("log4jemailFrom"), 
                            System.getProperty("log4jemailreplyTo"), 
                            System.getProperty("log4jemailSubject"), 
                            System.getProperty("log4jemailProtocol"), 
                            System.getProperty("log4jemailHost"), 
                            System.getProperty("log4jemailPort"), 
                            System.getProperty("log4jemailUserName"), 
                            System.getProperty("log4jemailPassword"), 
                            "false", 
                            "50", 
                            mpHtmlLayout, 
                            null, 
                            "true");
                    smtpAppender.start();
                    addAppender(smtpAppender);
                    getLogger(WEBSITESTER_LOGGER_NAME).addAppender(smtpAppender, Level.ERROR, null);
                }
            }
        }
    }
}

Файл конфигурации: src/main/resources/log4j2.component.properties

log4j.configurationFactory=com.websitester.config.MPLoggingConfiguration$MPConfigurationFactory
log4j.configurationFile=log4j2websitester.json

Файл конфигурации: src/main/resources/log4j2websitester.json

{"logFilePath" : "/log/weblogic/wl-moniport/"}

В моем случае я задал все свойства (доступные в MPLoggingConfiguration через System.getProperty) в других классах, например:

System.setProperty("log4jjdbcjndiName", "weblogic-monitor");

Когда вы изменили некоторые свойства и хотите перенастроить log4j2, вы должны сделать этот вызов:

final LoggerContext ctx = (LoggerContext) LogManager.getContext(false);
ctx.reconfigure();

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

person Carlos Cuesta    schedule 08.02.2017
comment
ОШИБКА StatusLogger Не найден файл конфигурации log4j2. Использование конфигурации по умолчанию: запись в консоль только ошибок. Установите системное свойство «log4j2.debug», чтобы отобразить журнал внутренней инициализации Log4j2… не удалось правильно получить конфигурацию. пожалуйста помоги - person this_is_om_vm; 07.08.2018
comment
Я редактирую ответ, изменяя первый файл конфигурации, включая свойство configurationFile и включая содержимое нового файла конфигурации. - person Carlos Cuesta; 07.08.2018
comment
это больше не работает с API 2.11.x - вам нужно использовать ConfigurationBuilder baeldung.com/log4j2 -программная-конфигурация - person madduci; 16.01.2019
comment
Кажется, что источник подключения по-прежнему зависит от файла конфигурации. Не могу найти способ полностью настроить JdbcAppender программно. - person Galya; 06.03.2019

Вы можете настроить свою собственную ConfigurationFactory в log4j. Пожалуйста, обратитесь к https://logging.apache.org/log4j/2.x/manual/customconfig.html. Кажется, это может удовлетворить ваши потребности.


Простите за это. Соответствует ли этот способ вашим потребностям? Я просто тестирую, и он работает хорошо, хотя все еще выводит сообщение об ошибке, о котором вы упоминали выше.

    LoggerContext ctx = (LoggerContext) LogManager.getContext(false);
    final Configuration config = ctx.getConfiguration();
    Layout<? extends Serializable> layout = PatternLayout.createLayout(PatternLayout.SIMPLE_CONVERSION_PATTERN, config, null,
        null,true, true,null,null);

    Appender appender = FileAppender.createAppender("/tmp/log4jtest.txt", "false", "false", "File", "true",
        "false", "false", "4000", layout, null, "false", null, config);
    appender.start();
    config.addAppender(appender);
    AppenderRef ref = AppenderRef.createAppenderRef("File", null, null);
    AppenderRef[] refs = new AppenderRef[] {ref};
    LoggerConfig loggerConfig = LoggerConfig.createLogger("false", Level.INFO, "org.apache.logging.log4j",
        "true", refs, null, config, null );
    loggerConfig.addAppender(appender, null, null);
    config.addLogger("simpleTestLogger", loggerConfig);
    ctx.updateLoggers();


    Logger l = ctx.getLogger("simpleTestLogger");
    l.info("message of info level shoud be output properly");
    l.error("error message");
person Yiping Huang    schedule 17.06.2015
comment
Я полагаю, что вы неправильно поняли мой вопрос. Я спрашивал, как создать простую конфигурацию с нуля, которая не зависит от наличия каких-либо файлов конфигурации. - person PM 77-1; 17.06.2015
comment
Мне нужно настроить ConsoleAppender таким образом, чтобы не возникало проблем при использовании LogManager.getLogger() в моем основном коде. - person PM 77-1; 24.06.2015
comment
Первое приведение к LoggerContext кажется излишним, поскольку этот метод уже возвращает его. Но в LoggerContext также нет метода getConfiguration(). - person Trejkaz; 29.07.2016
comment
@Trejkaz В log4j2 есть два определения LoggerContext: одно — интерфейс, а другое — класс. Приведение необходимо, чтобы попасть в класс, у которого есть метод getConfiguration(). - person Mike; 17.11.2016

если вы хотите это для консольного приложения, есть очень простой способ, если вы используете maven, просто поместите эти 2 зависимости в свой pom.xml, и все будет напечатано на вашей консоли. ничего не нужно... вообще нет файла log4j.properties. slf4j расширяет log4j и имеет так много богатых возможностей.

          <dependency>
                 <groupId>org.slf4j</groupId>
                 <artifactId>slf4j-api</artifactId>
                 <version>1.7.5</version>
                 <scope>compile</scope>
          </dependency>

          <dependency>
                 <groupId>org.slf4j</groupId>
                 <artifactId>slf4j-simple</artifactId>
                 <version>1.7.5</version>
          </dependency>
person Bhupi    schedule 24.06.2015
comment
Добавление других зависимостей, таких как slf4j, приводит к дополнительным затратам на обслуживание в долгосрочной перспективе проекта. - person Rohit Gaikwad; 24.01.2021

В документации рекомендуется API-интерфейс компоновщика для программной настройки. Используя этот API, ваш метод configureLog4J() может выглядеть примерно так:

public static void configureLog4J() {
  ConfigurationBuilder<BuiltConfiguration> builder =
      ConfigurationBuilderFactory.newConfigurationBuilder();

  // configure a console appender
  builder.add(
      builder.newAppender("stdout", "Console")
          .add(
              builder.newLayout(PatternLayout.class.getSimpleName())
                  .addAttribute(
                      "pattern",
                      "%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"
                  )
          )
  );

  // configure the root logger
  builder.add(
      builder.newRootLogger(Level.INFO)
          .add(builder.newAppenderRef("stdout"))
  );

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

}

Хитрость заключается в том, - и, на самом деле, в руководстве это не указано достаточно ясно - что этот статический метод инициализации должен вызываться до любых вызовов LogManager.getLogger().

Для минимального рабочего примера вы можете использовать статический блок инициализации, например

private static final Logger log;

static {
  configureLog4J();
  log = LogManager.getLogger(MyAwesomeClass.class);
}

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

person f0xdx    schedule 19.09.2019