以编程方式创建 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 异步记录器的主要内容,如果未能解决你的问题,请参考以下文章
MAXIMO API 7.6.1 POST 以编程方式创建服务请求创建空记录,但在 POSTMAN 中同样有效