简体   繁体   English

如何纯粹以编程方式配置 log4j 2.x?

[英]How to configure log4j 2.x purely programmatically?

How do I configure log4j 2.3 with console appender pure programmatically (no configuration files of any format)?如何以纯编程方式使用console appender程序配置log4j 2.3 (没有任何格式的配置文件)?

Basically I'm looking for 2.x version of this 1.x code .基本上我正在寻找这个1.x 代码的2.x 版本。

In my classes I would then use在我的课程中,我会使用

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

Without any configuration I'm (as expected) facing没有任何配置我(如预期)面临

ERROR StatusLogger No log4j2 configuration file found.错误 StatusLogger 未找到 log4j2 配置文件。 Using default configuration: logging only errors to the console.使用默认配置:仅将错误记录到控制台。

While usage of configuration files seems to be properly documented , I couldn't find a good example of a bare-bone code-only case.虽然配置文件的使用似乎被 正确记录,但我找不到一个很好的例子来说明一个简单的代码案例。

The closest I got is this article that still uses a dummy file.我得到的最接近的是这篇仍然使用虚拟文件的文章。

Here's my best (though completely unsuccessful) shot:这是我最好的(虽然完全不成功)镜头:

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

Have I missed something?我错过了什么吗?

If it's still a RTFM case, please point me into the right direction.如果它仍然是 RTFM 案例,请指出我正确的方向。

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");


    }
}

Not sure if this is what you are looking for. 不确定这是否是您正在寻找的。 This creates a default configuration and adds a console logger. 这将创建默认配置并添加控制台记录器。 However, LogManager.getLogger() does not work and using the LogManager.getContext().getLogger() does not allow for logger hierarchy. 但是,LogManager.getLogger()不起作用并使用LogManager.getContext()。getLogger()不允许记录器层次结构。 Honestly i don't recommend the programmatic approach, Log4j2 is allergic to it. 老实说,我不建议采用程序化方法,Log4j2对它过敏。

Here is a complete example for log4j 2.8 programmatically configuration. 以下是log4j 2.8编程配置的完整示例。 It has 3 appenders: RollingFile, JDBC and SMTP. 它有3个appender:RollingFile,JDBC和SMTP。

There are 1 class and 2 properties config files, one for register the class as a log4j2 configurationFactory, and the other one for set properties like the log file directory. 有1个类和2个属性配置文件,一个用于将类注册为log4j2 configurationFactory,另一个用于设置属性,如日志文件目录。

Class #1: MPLoggingConfiguration 第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);
                }
            }
        }
    }
}

Config file: src/main/resources/log4j2.component.properties 配置文件:src / main / resources / log4j2.component.properties

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

Config file: src/main/resources/log4j2websitester.json 配置文件:src / main / resources / log4j2websitester.json

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

In my case, I set all the properties (accessed in MPLoggingConfiguration via System.getProperty) in other classes, for example: 在我的例子中,我在其他类中设置了所有属性(通过System.getProperty在MPLoggingConfiguration中访问),例如:

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

When you changed some properties and want to reconfigure log4j2, you must make this call: 当您更改某些属性并想要重新配置log4j2时,您必须进行以下调用:

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

Hope this helps 希望这可以帮助

You Can customize your own ConfigurationFactory in log4j. 您可以在log4j中自定义您自己的ConfigurationFactory。 Pls refer to https://logging.apache.org/log4j/2.x/manual/customconfig.html . 请参阅https://logging.apache.org/log4j/2.x/manual/customconfig.html It seems it can meet your need. 它似乎可以满足您的需求。


Sorry for that. 对不起。 Does this way meet your need? 这样可以满足您的需求吗? I just test, and it runs well even though it still outputs the error message you mentioned above. 我只是测试,它运行良好,即使它仍然输出您上面提到的错误消息。

    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");

if you want it for console appender , there is an very easy way if you are using maven, just put these 2 dependencies in your pom.xml and all things will be printed on ur console . 如果你想要它用于控制台appender,有一个非常简单的方法,如果你使用maven,只需将这2个依赖项放在你的pom.xml中,所有的东西都将打印在你的控制台上。 nothing needed ...no log4j.properties file at all. 什么都不需要......根本没有log4j.properties文件。 slf4j extends log4j and has so many rich features. 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>

The documentation recommends the builder api for programmatic configuration.文档建议使用 builder api 进行编程配置。 Using this api, your configureLog4J() method could look something like this:使用此 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());

}

Now, the trick is - and afaik the manual does not state that clearly enough - that this static initialization method as to be called prior to any calls of LogManager.getLogger() .现在,诀窍是 - 并且手册没有足够清楚地说明 -任何LogManager.getLogger()调用之前调用此静态初始化方法。

For a minimal working example, you could use a static initialization block like so对于最小的工作示例,您可以使用像这样的静态初始化块

private static final Logger log;

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

That said, configuring logging in a programmatic way is imho not a good idea for any non trivial project: you would have to recompile, test and ship your code each time you want to temporarily increase log levels on certain loggers to diagnose production problems.也就是说,恕我直言,以编程方式配置日志记录对于任何非平凡项目都不是一个好主意:每次您想临时增加某些记录器的日志级别以诊断生产问题时,您都必须重新编译、测试和发送代码。 Therefore I would strongly recommend against using it.因此,我强烈建议不要使用它。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM