Как да конфигурирам 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
Чистата програмна конфигурация също липсваше от logback доскоро. Вижте stackoverflow.com/questions/22335441/. . Има връзка към log4j2 в този SO пост, че никога не бих могъл да накарам log4j2 да стартира, използвайки моя код за стартиране, но най-новият logback ще ви позволи да контролирате процеса на стартиране.   -  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: MPLogging Configuration

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
това вече не работи с 2.11.x API - трябва да използвате ConfigurationBuilder baedung.com/log4j2 -programmatic-config - 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 Има две дефиниции на LoggerContext в log4j2: едната е интерфейс, а другата е клас. Кастът е необходим, за да влезете в класа, който има метод getConfiguration(). - person Mike; 17.11.2016

ако го искате за конзолен appender, има много лесен начин, ако използвате 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());

}

Сега, номерът е - и afaik ръководството не посочва това достатъчно ясно - че този метод за статична инициализация трябва да бъде извикан преди на всяко извикване на LogManager.getLogger().

За минимален работен пример можете да използвате блок за статична инициализация като този

private static final Logger log;

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

Въпреки това конфигурирането на регистриране по програмен начин имхо не е добра идея за всеки нетривиален проект: ще трябва да прекомпилирате, тествате и изпращате кода си всеки път, когато искате временно да увеличите нивата на регистриране на определени регистратори, за да диагностицирате производствени проблеми. Затова силно препоръчвам да не го използвате.

person f0xdx    schedule 19.09.2019