以编程方式创建 log4j 异步记录器

Posted

技术标签:

【中文标题】以编程方式创建 log4j 异步记录器【英文标题】:Creating log4j Async logger programmatically 【发布时间】:2018-06-27 17:55:42 【问题描述】:

我正在使用 Log4J 2.10。

我正在尝试以编程方式创建异步 logger\appender。我需要两件事:

    我应该能够在运行时指定日志文件的文件路径。 我需要在运行时指定模式。

我可以想出下面的代码。但我无法将 RollingFileAppender 添加到 AsyncAppender。网上有使用 AsyncAppender.wrap 的示例。但该 API 似乎不适用于 Log4J 2.10。

你知道我是怎么做到的吗?

void createLog4JLogger(final String logFilePath) 
    
    LoggerContext context = (LoggerContext) LogManager.getContext();
    final Configuration config = context.getConfiguration();

    final PatternLayout patternLayout = PatternLayout.newBuilder().withPattern(CONVERSION_PATTERN).withCharset(Charset.defaultCharset()).build();

    final RollingFileAppender fileAppender = 
            RollingFileAppender.newBuilder().withName(APPENDER_NAME).withLayout(patternLayout).withFileName(logFilePath).build();
    
    AppenderRef ref = AppenderRef.createAppenderRef(APPENDER_NAME, null, null);
    AppenderRef[] refs = new AppenderRef[] ref;
    
    final AsyncAppender asyncAppender = AsyncAppender.newBuilder().setAppenderRefs(refs).setName(APPENDER_NAME).setConfiguration(config).build();
    
    LoggerConfig loggerConfig = LoggerConfig.createLogger(false, Level.INFO, LOGGER_NAME, LOGGER_NAME, refs, null, null, null);
    loggerConfig.addAppender(asyncAppender, null, null);
    
    
    config.addAppender(asyncAppender);
    config.addLogger(LOGGER_NAME, loggerConfig);
    
    
    context.updateLoggers(config);
    
    final Logger logger = LogManager.getContext().getLogger(LOGGER_NAME);
    
    
    logger.info("HELLO_WORLD");
    

【问题讨论】:

【参考方案1】:

您可以使用以下代码在 log4j 2 中创建异步记录器。

final LoggerContext ctx = (LoggerContext) LogManager.getContext(false);
final Configuration config = ctx.getConfiguration();
Layout layout = PatternLayout.newBuilder().withConfiguration(ctx.getConfiguration()).withPattern("%dyyyy-MM-dd HH:mm:ss.SSS [%t] %c1 - test %msg%n").build();
Appender appender = FileAppender.newBuilder().withFileName("logs/test.log").setLayout(layout)
                    .setConfiguration(config).setName("TestApp").build();
AppenderRef ref = AppenderRef.createAppenderRef("TestApp",Level.INFO, null);

config.addAppender(appender);
appender.start();
AppenderRef[] refs = new AppenderRef[] ref;
LoggerConfig loggerConfig= AsyncLoggerConfig.createLogger(true, Level.INFO, "test","test", refs, null, config, null);
loggerConfig.addAppender(appender, Level.INFO, null);
config.addLogger("test", loggerConfig);
loggerConfig.start();

【讨论】:

【参考方案2】:

我需要使用没有配置文件的多线程 log4j 记录器。所以我最终将来自多个来源的代码(答案中的引用)放在一起。它已经工作了几年(抱歉延迟回复)。也许对其他人有用:

创建记录器的类:

class MyCustomLogger 
private static Logger createLog4JLogger(final String logFilePath, final String logLevel) 

    try 
        final Level level = (null != logLevel && 0 == logLevel.toLowerCase().compareTo(DEBUG_MODE_STRING)) ? Level.DEBUG : Level.INFO;

        ConfigurationFactory.setConfigurationFactory(new LogCustomConfigurationFactory(logFilePath, level)); // This must be called before any other calls to Log4j

        dumpStringToSysOut("created configuration factory");

        Logger logger = LogManager.getLogger();

        dumpStringToSysOut("logger is " + ((null == logger) ? "null" : "not null"));

        return logger;
     catch(Exception e) 
        e.printStackTrace();
    

    return null;

自定义配置工厂:

      import java.io.File;
  import java.net.URI;

  import org.apache.logging.log4j.Level;
  import org.apache.logging.log4j.core.LoggerContext;
  import org.apache.logging.log4j.core.appender.ConsoleAppender;
  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.Order;
  import org.apache.logging.log4j.core.config.builder.api.AppenderComponentBuilder;
  import org.apache.logging.log4j.core.config.builder.api.ComponentBuilder;
  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.api.LayoutComponentBuilder;
  import org.apache.logging.log4j.core.config.builder.api.RootLoggerComponentBuilder;
  import org.apache.logging.log4j.core.config.builder.impl.BuiltConfiguration;
  import org.apache.logging.log4j.core.config.plugins.Plugin;

  @Plugin(name = "LogCustomConfigurationFactory", category = ConfigurationFactory.CATEGORY)
  @Order(50)
  public class LogCustomConfigurationFactory extends ConfigurationFactory 

     private final String _logFilePath;
     private final Level _level;

     public LogCustomConfigurationFactory(final String logFilePath, final Level level) 
        _logFilePath = logFilePath;
        _level = level;
     

     public LogCustomConfigurationFactory() 
        _logFilePath = System.getenv("TEMP") + File.separator + "my.log";
        _level = Level.INFO;
     


    //https://github.com/LMAX-Exchange/disruptor/releases   
    private static Configuration createConfiguration(final String name, ConfigurationBuilder<BuiltConfiguration> builder, final String logFilePath, final Level level) 
      builder.setConfigurationName(name);

      //https://***.com/questions/34904304/how-to-properly-create-a-rollingfileappender-with-appendercomponentbuilder-in-lo
      //ConfigurationBuilder< BuiltConfiguration > builder =
      //        ConfigurationBuilderFactory.newConfigurationBuilder();

      builder.setStatusLevel(Level.ERROR);
      builder.setConfigurationName("RollingBuilder");
      // create the console appender
      AppenderComponentBuilder appenderBuilder = builder.newAppender("Stdout", "CONSOLE").addAttribute("target",
              ConsoleAppender.Target.SYSTEM_OUT);
      appenderBuilder.add(builder.newLayout("PatternLayout").
              addAttribute("pattern", "%d [%t] %-5level: %msg%n%throwable"));
      builder.add( appenderBuilder );

      LayoutComponentBuilder layoutBuilder = builder.newLayout("PatternLayout")
              .addAttribute("pattern", "[%ddd-MM-yyyy HH:mm:ss] [%t] [%p] %m%n");
      ComponentBuilder triggeringPolicy = builder.newComponent("Policies")
              .addComponent(builder.newComponent("CronTriggeringPolicy").addAttribute("schedule", "0 0 0 * * ?"))
              .addComponent(builder.newComponent("SizeBasedTriggeringPolicy").addAttribute("size", "100M"));
      appenderBuilder = builder.newAppender("rolling", "RollingFile")
              .addAttribute("fileName", logFilePath)
              .addAttribute("filePattern", "C:\\Temp\\rolling-%dMM-dd-yy.log.gz")
              .add(layoutBuilder)
              .addComponent(triggeringPolicy)

              ;
      builder.add(appenderBuilder);

      // create the new logger
      //builder.add( builder.newLogger( "Logger", Level.DEBUG )
      //        .add( builder.newAppenderRef( "rolling" ) )
      //        .addAttribute( "additivity", false ) );

      //builder.add( builder.newRootLogger( Level.DEBUG )

      builder.add( builder.newAsyncRootLogger( level )
              .add( builder.newAppenderRef( "rolling" ) ) );
      return builder.build();
      //Configurator.initialize(builder.build());    


      //https://***.com/questions/43145250/how-to-configure-log4j-2-to-asynchonous-mode-programmatically?noredirect=1&lq=1
      /*
      AppenderComponentBuilder appenderBuilder = builder.newAppender("Stdout", "CONSOLE").
          addAttribute("target", ConsoleAppender.Target.SYSTEM_OUT);
      appenderBuilder.add(builder.newLayout("PatternLayout").
          //addAttribute("pattern", "[%ddd-MM-yyyy HH:mm:ss] [%t] [%p] [%c] - %m%n %level: %msg%n"));
           addAttribute("pattern", "[%ddd-MM-yyyy HH:mm:ss] [%t] [%p] [%c] - %m%n"));

      builder.add(appenderBuilder);

      RootLoggerComponentBuilder rootLoggerBuilder = builder.newAsyncRootLogger(Level.DEBUG); // use newAsyncRootLogger instead of newRootLogger 
      rootLoggerBuilder.add(builder.newAppenderRef("Stdout"));

      builder.add(rootLoggerBuilder);
      return builder.build();*/
    

    @Override
    public Configuration getConfiguration(final LoggerContext loggerContext, final ConfigurationSource source) 
      return getConfiguration(loggerContext, source.toString(), null);
    

    @Override
    public Configuration getConfiguration(final LoggerContext loggerContext, final String name, final URI configLocation) 
      ConfigurationBuilder<BuiltConfiguration> builder = newConfigurationBuilder();
      return createConfiguration(name, builder, _logFilePath, _level);
    

    @Override
    protected String[] getSupportedTypes() 
      return new String[]"*";
    
  

【讨论】:

以上是关于以编程方式创建 log4j 异步记录器的主要内容,如果未能解决你的问题,请参考以下文章

log4j 1.2 - 异步记录器内存使用限制设置

如何以编程方式记录 PerformanceCounter

MAXIMO API 7.6.1 POST 以编程方式创建服务请求创建空记录,但在 POSTMAN 中同样有效

Log4j 2.0 - 日志文件中没有出现日志 - 使用 log4j2.xml 在同一类中尝试多个记录器

优雅记录log4j日志

以编程方式访问浏览器历史记录