问题
How do I configure log4j 2.3
with console appender pure programmatically (no configuration files of any format)?
Basically I'm looking for 2.x version of this 1.x code.
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. 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.
回答1:
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. Honestly i don't recommend the programmatic approach, Log4j2 is allergic to it.
回答2:
Here is a complete example for log4j 2.8 programmatically configuration. It has 3 appenders: RollingFile, JDBC and 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.
Class #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
log4j.configurationFactory=com.websitester.config.MPLoggingConfiguration$MPConfigurationFactory
log4j.configurationFile=log4j2websitester.json
Config file: 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.setProperty("log4jjdbcjndiName", "weblogic-monitor");
When you changed some properties and want to reconfigure log4j2, you must make this call:
final LoggerContext ctx = (LoggerContext) LogManager.getContext(false);
ctx.reconfigure();
Hope this helps
回答3:
You Can customize your own ConfigurationFactory in log4j. Pls refer to 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");
回答4:
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 . nothing needed ...no log4j.properties file at all. slf4j extends log4j and has so many rich features.
<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>
回答5:
The documentation recommends the builder api for programmatic configuration. Using this api, your configureLog4J()
method could look something like this:
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()
.
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.
来源:https://stackoverflow.com/questions/30881990/how-to-configure-log4j-2-x-purely-programmatically