Log4j is finding my config, because as soon as I delete it I get an error message saying it couldn't find one, however it's properties are not reflected when logging.
log4j2.properties:
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="TRACE">
<Appenders>
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout pattern="%d{HH:mm:ss} [%t] %-5level %logger{36} - %msg%n"/>
</Console>
</Appenders>
<Loggers>
<Root level="info">
<AppenderRef ref="Console"/>
</Root>
</Loggers>
</Configuration>
Test.java:
public class Test {
private static Logger logger = LogManager.getLogger(Test.class);
public static void main(String[] args) throws Exception {
logger.info("test");
logger.fatal(logger.getLevel());
}
}
Output:
20:19:31.848 [main] FATAL io.rj93.sarcasm.examples.CnnSentenceClassificationExample - ERROR
As you can see, the logger is returning the level to be ERROR when it is set to INFO, and the time format is including the milliseconds even though it has been removed.
The config file is taken from the log4j website, with only minor changes (the two mentioned, and status="TRACE")
I am using version 2.8.1.
You use a log4j2.properties file with a XML configuration inside it.
It is not consistent.
The log4J initialization doesn't recognize the format used as a properties format. So it uses the default log4J configuration that specifies ERROR level for the root logger.
Simply rename log4j2.properties to log4j2.xml and it should be fine.
Related
I'm using notepad++ to preview log files from running java application with log4j logging mechanism. NP++ has a feature where file is automatically reloaded when focus is switched to it, which I find very convenient. Problem here is that new lines are not displayed automatically, even though they are added to file. I can see that if I reload file manually or open it from another text editor. It looks like file is being locked because I cannot delete it until app is closed. I tried executing the same app in Linux but there file is not locked. I can live with manually refreshing file, but I'm concerned if I did something wrong here. Setting locking to false doesn't seem to help here.
I'm using log4j v2.9.1 and running app from wincmd with:
java -jar log.jar
This is log4jconfig.xml:
<?xml version="1.0" encoding="UTF-8"?>
<Configuration name="ConfigName">
<Appenders>
<File locking="false" immediateFlush="true" bufferedIO="false" name="LogFile" fileName="C:\path\to\test.log">
<PatternLayout>
<Pattern>%d{YYYY-MM-dd HH:mm:ss.SSS} %5level: %m%n</Pattern>
</PatternLayout>
</File>
<Async name="Async">
<AppenderRef ref="LogFile"/>
</Async>
</Appenders>
<Loggers>
<Root level="info">
<AppenderRef ref="Async"/>
</Root>
</Loggers>
</Configuration>
Java code:
public class Main {
static {
System.setProperty("log4j.configurationFile", "C:\\path\\to\\log4jconfig.xml");
}
private static final Logger LOGGER = LoggerFactory.getLogger(Main.class);
public static void main(String[] args) {
LOGGER.info("Testing...");
System.in.read();
}
}
Does anyone see a problem here?
Yes, I've read all the related questions. I am using log4j2 (tried both version 2.4 and updating to latest, version 2.6.2).
I have a small utility program for customers. I'm keen to keep exposed configurations at minimum. But for problematic cases, I'd also want to add a -debug flag to enable debug logs at runtime.
Here is my code to enable debug logging
private static void enableDebugLogs(){
LoggerContext ctx = (LoggerContext) LogManager.getContext();
LoggerConfig log = ctx.getConfiguration().getRootLogger();
System.out.println(log.getLevel()); // INFO
log.setLevel(Level.DEBUG);
System.out.println(log.getLevel()); // DEBUG
ctx.updateLoggers();
System.out.println(ctx.getRootLogger().getLevel()); // DEBUG, hey it works, right?
}
But it does not actually work with any of these cases:
enableDebugLogs();
logger.debug("Debug mode on"); // static, already made logger. Level did not change
LogManager.getLogger(Main.class).debug("Debug"); // Nope, not printing
Logger root = LogManager.getRootLogger();
root.info("Level: " + root.getLevel()); // Level: INFO, should be DEBUG
The utility program is finished usually in less than 30 seconds, so the change should be instant. Here is the log4j2.xml
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN">
<Appenders>
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout pattern="%d{HH:mm:ss.SSS} %-5level - %msg%n"/>
</Console>
<RollingFile name="File" fileName="program_name.log" filePattern="program_name-archived.log">
<PatternLayout>
<Pattern>%d{HH:mm:ss.SSS} %-5level - %msg%n</Pattern>
</PatternLayout>
<Policies>
<SizeBasedTriggeringPolicy size="10 KB" />
</Policies>
<DefaultRolloverStrategy min="1" max="1"/>
</RollingFile>
</Appenders>
<Loggers>
<Root level="info">
<AppenderRef ref="Console"/>
<AppenderRef ref="File"/>
</Root>
</Loggers>
</Configuration>
Is the problem with usings AppenderRefs? Can I somehow tell the Appenders to update logging level from Root logger?
Found the real issue. Had to use:
LoggerContext ctx = (LoggerContext) LogManager.getContext(false);
instead of
LoggerContext ctx = (LoggerContext) LogManager.getContext();
API stating the difference being "returns the LoggerContext" and "returns the current LoggerContext". And I clearly missed this bit of information for the version without boolean parameter:
"WARNING - The LoggerContext returned by this method may not be the LoggerContext used to create a Logger for the calling class."
You can change switch the logging configuration between two or multiple log4j2.xml files.
For example, create two log4j2.xml files with different configurations. log4j2.xml & log4j2-debug.xml and pass it to below code.
ConfigurationFactory configFactory = XmlConfigurationFactory.getInstance();
ConfigurationFactory.setConfigurationFactory(configFactory);
LoggerContext ctx = (LoggerContext) LogManager.getContext(false);
ClassLoader classloader = Thread.currentThread().getContextClassLoader();
InputStream inputStream = classloader.getResourceAsStream(logFileName);
ConfigurationSource configurationSource = new ConfigurationSource(inputStream);
ctx.start(configFactory.getConfiguration(ctx, configurationSource));
To reconfigure log4j2 after it's initialization, the documentation give you two ways :
Using the config file, you can enable the automatic reconfiguration (it's the preferred way) so that modifying the file after initialization will be reflected on your runtime : http://logging.apache.org/log4j/2.x/manual/configuration.html#AutomaticReconfiguration
Using ConfigurationBuilder you can reconfigure log4j programatically (I think it's what you are looking for), see the "Reconfigure Log4j Using ConfigurationBuilder with the Configurator" paragraph of this page : http://logging.apache.org/log4j/2.x/manual/customconfig.html
In addition to the above, to debug log4j initialization, set <Configuration status="trace" in the beginning of the configuration file. Log4j2's internal status logs will print to the console. This may help troubleshooting.
Here is a little known fact.
If you set your ROOT_LOGGER level in your log4j2.xml or equivalent properties to say DEBUG, then setting the level dynamically to something lower did not work for me; in other words, setting dynamically had no effect.
ONLY when I change the setting in log4j2.xml to TRACE and then using the below to change the log level did it work for me:
Level level = Level.valueOf(this.consoleLogLevel.toUpperCase());
//Dynamically set the log level for ALL loggers
LoggerContext ctx = (LoggerContext) LogManager.getContext(false);
Configuration config = ctx.getConfiguration();
LoggerConfig loggerConfig = config.getLoggerConfig(LogManager.ROOT_LOGGER_NAME);
loggerConfig.setLevel(level);
ctx.updateLoggers();
And here is my simple configuration file:
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN">
<Appenders>
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
</Console>
</Appenders>
<Loggers>
<Root level="TRACE">
<AppenderRef level="TRACE" ref="Console" />
</Root>
</Loggers>
</Configuration>
And here is a TestNG test you can refactor to verify the above:
#Test
public void givenCut_whenLoggingWithERRORLevel_LoggingOutputIsAtERRORLevelAndHigherOnly() {
try {
lcaProperties.setLogLevel(Level.ERROR.name());
GlobalLogger globalLogger = GlobalLogger.builder().lcaServiceProperties(lcaProperties).build();
assertNotNull(globalLogger.getConsoleLogger());
assertNotNull(globalLogger.getFunctionalDbLogger());
assertEquals(globalLogger.getConsoleLogger().getLevel(), Level.ERROR);
assertEquals(log.getLevel(), Level.ERROR);
System.out.println("log.getLogLevel() = " + log.getLevel());
System.out.println("globalLogger.getConsoleLogger().getLevel() = " + globalLogger.getConsoleLogger().getLevel());
log.fatal("logLevel::"+log.getLevel()+"::log.fatal");
log.error("logLevel::"+log.getLevel()+"::log.error");
log.warn("logLevel::"+log.getLevel()+"::log.warn");
log.info("logLevel::"+log.getLevel()+"::log.info");
log.debug("logLevel::"+log.getLevel()+"::log.debug");
log.trace("logLevel::"+log.getLevel()+"::log.trace");
globalLogger.getConsoleLogger().fatal("logLevel::"+globalLogger.getConsoleLogger().getLevel()+"::globalLogger.getConsoleLogger().fatal");
globalLogger.getConsoleLogger().error("logLevel::"+globalLogger.getConsoleLogger().getLevel()+"::globalLogger.getConsoleLogger().debug");
globalLogger.getConsoleLogger().warn("logLevel::"+globalLogger.getConsoleLogger().getLevel()+"::globalLogger.getConsoleLogger().debug");
globalLogger.getConsoleLogger().info("logLevel::"+globalLogger.getConsoleLogger().getLevel()+"::globalLogger.getConsoleLogger().debug");
globalLogger.getConsoleLogger().debug("logLevel::"+globalLogger.getConsoleLogger().getLevel()+"::globalLogger.getConsoleLogger().debug");
globalLogger.getConsoleLogger().trace("logLevel::"+globalLogger.getConsoleLogger().getLevel()+"globalLogger.getConsoleLogger()::log.trace");
} catch (Exception e) {
fail();
log.error(e);
}
}
I am trying to use log4j2 with disruptor in a java application. I have the following jar files in my classpath:
log4j-api-2.0-rc2.jar
log4j-core-2.0-rc2.jar
disruptor-3.2.0.jar
In my Java class, I a doing the following to test:
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.LogManager;
public class LoggerTest {
private static final Logger Logger = LogManager.getLogger(LoggerTest.class.getName());
public static void main(String[] args) {
Logger.info("testing log4j2 with disruptor");
}
My log4j2.xml file is as follows:
<?xml version="1.0" encoding="UTF-8"?>
<!-- Don't forget to set system property
-DLog4jContextSelector=org.apache.logging.log4j.core.async.AsyncLoggerContextSelector
to make all loggers asynchronous. -->
<configuration status="INFO">
<appenders>
<!-- Async Loggers will auto-flush in batches, so switch off immediateFlush. -->
<FastFile name="RandomAccessFile" fileName="logs/test.log" immediateFlush="false" append="false">
<PatternLayout>
<pattern>%d %p %c{1.} [%t] %m %ex%n</pattern>
</PatternLayout>
</FastFile>
</appenders>
<loggers>
<root level="info" includeLocation="true">
<appender-ref ref="RandomAccessFile"/>
</root>
</loggers>
</configuration>
When I run the application, I get the following error (with no log output):
2014-07-10 14:45:32,930 ERROR Error processing element FastFile: CLASS_NOT_FOUND
2014-07-10 14:45:32,973 ERROR Unable to locate appender RandomAccessFile for logger
In beta9, the <FastFile> appender was renamed to <RandomAccessFile>. If you rename this element in your configuration it should work.
I cannot get Log4j 2 to log to the console. Nothing is showing up when running with gradle.
log4j2.xml in the projects root directory:
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="ALL">
<Appenders>
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
</Console>
</Appenders>
<Loggers>
<Root level="all">
<AppenderRef ref="Console"/>
</Root>
</Loggers>
</Configuration>
Usage in my classes:
public class ABCHandler {
private final Logger logger = LogManager.getLogger();
public ABC(String serialPortName) {
logger.info("Opening serial port {}", serialPortName);
}
}
Loading your file and configurations on my machine works.
This was the class I used:
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public class Test
{
private final Logger logger = LogManager.getLogger(Test.class);
public Test(String serialPortName) {
System.out.println(logger.isInfoEnabled());
logger.entry();
logger.info("info! {}", serialPortName);
logger.error("error! {}", serialPortName);
logger.debug("debug! {}", serialPortName);
}
public static void main(String args[])
{
Test h1 = new Test("1001");
}
}
This is the log4j2.xml:
<ThresholdFilter level="all"/>
<Appenders>
<Console name="STDOUT" target="SYSTEM_OUT">
<PatternLayout pattern="%d %-5p method: [%t] %C{2} (%F:%L) - %m%n"/>
</Console>
</Appenders>
<Loggers>
<Root level="all">
<AppenderRef ref="STDOUT"/>
</Root>
</Loggers>
and finally, this is the output:
true
2014-05-29 12:19:15,266 TRACE method: [main] Test (Test.java:10) - entry
2014-05-29 12:19:15,268 INFO method: [main] Test (Test.java:11) - info! 1001
2014-05-29 12:19:15,269 ERROR method: [main] Test (Test.java:12) - error! 1001
2014-05-29 12:19:15,269 DEBUG method: [main] Test (Test.java:13) - debug! 1001
One common error when using Log4j2 is placing the log4j2.xml in a file that is not in the classpath.
To diagnose if that is the problem, change the line
logger.info("Opening serial port {}", serialPortName);
to
logger.error("Opening serial port {}", serialPortName);
If you see any output it is because log4j can't load your file. This is because the default log level when the file is not found is ERROR, not DEBUG.
The location of the log4j2.xml on my project (Maven) is in src/main/resources, which I know it is in my classpath.
My problems were:
I was using a log4j.properties file. Once renamed to log4j2.properties the main and test classpaths picked it up
I had to add logging to standard output to build.gradle
test {
testLogging.showStandardStreams = true
}
note: when I added sourcesets according to here it still didn't find the log4j.properties file only renaming it worked!
Below is the log4j2.xml file that I have created. I have configured async_file.log for Asynchronous Logging and regular_file.log for regular and synchronous logging. The problem is that the log files get created, but the size of the files is zero and with no logs. All logs are coming to server.log file (JBOSS) and not to the 2 files that I had got configured for (async_file.log and regular_file.log).
Please let me know why the logs are NOT going to the log files that I have configured. Please help me with this or give me some direction or hint.
I am calling the two different loggers in the same class file by name DCLASS as shown below:
private static final transient Logger LOG = Logger.getLogger(DCLASS.class);
private static final transient Logger ASYNC_LOG = Logger.getLogger("ASYNC");
I have included the following jars in the Class Path:
1. log4j-api-2.0-beta8.jar
2. log4j-core-2.0-beta8.jar
3. disruptor-3.0.0.beta1.jar
My log4j2.xml is as below:
<?xml version="1.0" encoding="UTF-8"?>
<configuration status="INFO">
<appenders>
<!-- Async Loggers will auto-flush in batches, so switch off immediateFlush. -->
<FastFile name="AsyncFastFile" fileName="../standalone/log/async_file.log"
immediateFlush="false" append="true">
<PatternLayout>
<pattern>%d %p %class{1.} [%t] %location %m %ex%n</pattern>
</PatternLayout>
</FastFile>
<FastFile name="FastFile" fileName="../standalone/log/regular_file.log"
immediateFlush="true" append="true">
<PatternLayout>
<pattern>%d %p %class{1.} [%t] %location %m %ex%n</pattern>
</PatternLayout>
</FastFile>
</appenders>
<loggers>
<!-- pattern layout actually uses location, so we need to include it -->
<asyncLogger name="ASYNC" level="trace" includeLocation="true">
<appender-ref ref="AsyncFastFile"/>
</asyncLogger>
<root level="info" includeLocation="true">
<appender-ref ref="FastFile"/>
</root>
</loggers>
</configuration>
The reason why the logs were not coming to the log files is because, I was using 'Logger' instead of 'LogManager'.
In the code, I had
private static final transient Logger ASYNC_LOG = Logger.getLogger("ASYNC");
The code should have been
private static final transient Logger ASYNC_LOG = Logmanager.getLogger("ASYNC");
When it is 'logger', then the compiler is looking into 'Log4j API' and when it is 'LogManager' it is looking into 'Log4j2 API'. Since I have configured everything to use Log4j2, by changing logger to LogManager, the logs started coming to the log files as expected.