I'm trying to use Log4j2 in an OSGi environment. I've got it to work so far, but while inspecting the logs from the console and from the file, I noticed that some of them were missing, specifically logs that were called from a static method.
The Log class in the example below is just a convenience class to let my colleagues call the logging functionality more easily (in the example for just a String it seems like overkill of course) through a create method. It does nothing more than create an instance of the Log class that has a Logger internally that calls the respective method from the Log4j2 logger.
My question is: Do I just have a simple error in my project or is Log4j2 not able to log to files from static methods?
Here's a code example to make it a bit more clear:
Log log = Log.testLog();
log.info("non static log" );
That's the code I call from a non-static method.
And here's the testLog()-method:
public static Log testLog() {
Log.create( Log.class ).info( "static log" );
return Log.create( Log.class );
}
Results:
Both #info() calls write to the Console Appender, but only the "non static log" message is written to the file.
Here's my log4j2.xml:
<?xml version="1.0" encoding="UTF-8"?>
<Configuration>
<Appenders>
<Console name="Console">
<PatternLayout pattern="!ENTRY %logger{1.} %level %d{DEFAULT} [%t]%n!MESSAGE %msg%n%n"/>
</Console>
<RollingFile name="RollingFile" fileName="${sys:osgi.logfile}.log4j.log"
filePattern="${sys:osgi.logfile}.log4j_bak_%i.log">
<PatternLayout>
<pattern>!ENTRY %logger{1.} %level %d{DEFAULT} [%t]\n!MESSAGE %msg%n%n</pattern>
</PatternLayout>
<Policies>
<SizeBasedTriggeringPolicy size="1 MB"/>
</Policies>
<DefaultRolloverStrategy max="10"
fileIndex="min"/>
</RollingFile>
</Appenders>
<Loggers>
<Root level="TRACE" additivity="false">
<AppenderRef ref="RollingFile"/>
<AppenderRef ref="Console"/>
</Root>
</Loggers>
</Configuration>
Finally found the source of my particular problem, which is OSGi (in this case the Equinox Framework). My application uses the osgi.logfile system property to point to the location where the logs should be saved at.
Unfortunately Equinox not only creates that property, but also changes it at startup to a different location. For Log4j2 I used ${sys:osgi.logfile} to get this system property, but because a few particular plugins started so early, Log4j2 still had the wrong (aka. old) location configured for these plugins (more specifically: their LoggerContext).
What helped me in this case was a simple LoggerContext.reconfigure() on the LoggerContext that still had the old location.
Related
I have a single java class (a device controller) that is being used to create 5 separate processes. Each of the processes is assigned an identifier. I would like each of the processes to write to its own log file based on its assigned identifier. I have all of the appenders and loggers defined in a shared log4j2.xml config file.
Issue: When I start the first device controller, it successfully writes to the correct log file. However, when I start the second device controller, log4j will roll-over all of the loggers in the log4j2.xml config file and will only write to the log file assigned to the new process. All of the log messages for the first process will go to the rolled-over log file, but new messages are no longer written to its newly rolled-over log file.
(OS: Linux, log4j version: 2.8.2)
Below is an abbreviated version of the log4j2.xml config file that I used.
...
<Appenders>
...
<RollingFile name="RollingFile-1" fileName="/logs/EPDU/Device-1.log" filePattern="/logs/EPDU/Device-1_%d{dd-MMM-yyyy::HH:mm:ss}.log">
<PatternLayout>
...
</PatternLayout>
<Policy>
<OnStartUpTriggeringPolicy minSize="1"/>
<SizeBasedTriggeringPolicy size="20 MB"/>
</Policy>
<DefaultRolloverStrategy fileIndex="nomax"/>
</RollingFile>
...
<RollingFile name="RollingFile-5" fileName="/logs/EPDU/Device-5.log" filePattern="/logs/EPDU/Device-5_%d{dd-MMM-yyyy::HH:mm:ss}.log">
<PatternLayout>
...
</PatternLayout>
<Policy>
<OnStartUpTriggeringPolicy minSize="1"/>
<SizeBasedTriggeringPolicy size="20 MB"/>
</Policy>
<DefaultRolloverStrategy fileIndex="nomax"/>
</RollingFile>
</Appenders>
<Loggers>
<Logger name="device-1" level="trace" additivity="false">
<AppenderRef ref="RollingFile-1" level="debug"/>
</Logger>
...
<Logger name="device-5" level="trace" additivity="false">
<AppenderRef ref="RollingFile-5" level="debug"/>
</Logger>
</Loggers>
The Logger variable is initialized and assigned in the main method after the device identifier is determined similar to the code below:
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.LogManager;
public class DeviceController {
private satic Logger deviceLogger;
public DeviceController(Param param1, Param param2){
...
}
...
public static void main(String[] args) {
/**
* Fancy code to find device identifier...
* String loggerName = (results of fancy code is "device-[1..5]");
*/
deviceLogger = LogManager.getLogger(loggerName);
deviceLogger.info("Start logging stuff in device log.");
new DeviceController(param1, param2);
}
...
}
How can I prevent all of the loggers from rolling over, but instead leave the currently running processes/logs alone as the next process and log is started?
Note: I tried to provide a "Goldilocks" amount of detail to explain the problem. Sorry if I provided too much or not enough information.
Could you show a little bit more of your code? I think your issue comes from the fact you have a static logger. So from your above snippet, I believe you overwrite for each new DeviceController the deviceLogger with a new Logger with the next identifier you fetch. I would guess that at the end, all your logs are being appended to your device-5 log file, aren't they?
Side note, I think it's good practice to use the sl4f interface to declare your logger but then assigned the log4j implementation to your logger.
First time trying to use log4j version log4j-1.2.17.jar.
On an existing application the client has log4j in place and there is a log4j.properties file which specifies a light log output. What I want to do is depending on the log level (ERROR & WARN) output a more refined entry.
On the log4j site I came across this but I think it is to be in some .xml file. I need some assistance in understanding how I can put in place the formatting option to alter based on log level.
You don't need to declare separate loggers to achieve this. You can set the logging level on the AppenderRef element.
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN">
<Appenders>
<File name="file" fileName="app.log">
<PatternLayout>
<Pattern>%d %p %c{1.} [%t] %m %ex%n</Pattern>
</PatternLayout>
</File>
<Console name="STDOUT" target="SYSTEM_OUT">
<PatternLayout pattern="%m%n"/>
</Console>
</Appenders>
<Loggers>
<Root level="trace">
<AppenderRef ref="file" level="DEBUG"/>
<AppenderRef ref="STDOUT" level="INFO"/>
</Root>
</Loggers>
</Configuration>
Would I put this xml content into the web.xml file or another file?
a) If another file what file name and where would it go?
How do I get log4j to realize that I need it to use the xml file?
Will the use of the xml ignore the log4j.properties file?
I know it is a lot of questions but there is only me on the project and the client has a production crisis that needs to be figured out today so I don't have time to go off to read and do tutorials with the client calling me every hour. I figured it may help to get this logging more useful. As the logs are right now I have a date and message output to the log but no idea where the entries are created from without doing extensive searches through the code.
You could do this by defining multiple non-additive Loggers so that the first one only logs errors, the next one warnings and the final one infos and debug.
I am using Log4j 2 and I am unsuccessfully trying to change the logging level of jBPM/Drools, having it as a reference. The drools class that keeps logging is ExtensibleXmlParser.
<?xml version="1.0" encoding="UTF-8"?>
<Configuration>
<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="debug">
<AppenderRef ref="Console" />
</Root>
<Logger name="org.drools.core.xml.ExtensibleXmlParser" level="off">
<AppenderRef ref="Console" />
</Logger>
</Loggers>
</Configuration>
If I get it right, ExtensibleXmlParser uses slf4j and Log4j is compatible with sl4j.
Why doesn't this Log4j configuration work? Could someone provide me a working configuration? Should I configure jBPM/Drools logger indendently?
When log4j seems to ignore your tweaks to the log4j.properties/xml file, it most often means you're not fiddling with the right file. It is likely that there is another configuration file in your classpath that gets found earlier and is taken into account.
Search your entire classpath for log4j* pattern and see what comes out (include the contents of .jar files and application server /lib and /ext folders, if any).
If I get it right, ExtensibleXmlParser uses slf4j and Log4j is compatible with sl4j.
"Is compatible" is not equivalent with "is configured to use". SLF4J plugs into appropriate logging framework through the org.slf4j.impl.StaticLoggerBinder class. Search the classpath (best in your IDE) to see what library this class came with. If there is no such class, then SLF4J logs nothing.
I have a JAX-RS 2.0 application running on a Tomcat 7 server, and I'm using log4j2 along with SLF4J to record the server logs to a file.
I can't seem to get any logs to show up properly in my log file when running the server in production, although when I run my integration tests, logs are output correctly.
In production, the logs are merely redirected to the console instead.
My log4j2.xml file is located in the WEB-INF/classes folder, and I've included all the necessary dependencies as well.
My configuration file looks like this:
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="trace">
<Appenders>
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
</Console>
<RollingFile name="file" fileName="log/trace.log" append="true" filePattern="log/trace.%i.log">
<PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %X %logger{36} - %msg%n"/>
<Policies>
<OnStartupTriggeringPolicy/>
<SizeBasedTriggeringPolicy size="10 MB" />
</Policies>
</RollingFile>
</Appenders>
<Loggers>
<Logger name="my.package" level="TRACE" additivity="false">
<AppenderRef ref="file"/>
</Logger>
<Root level="WARN">
<AppenderRef ref="file"/>
</Root>
</Loggers>
</Configuration>
The web.xml needs no configuration (I'm following the documentation found on the log4j2 website).
EDIT
I've tried setting the Root level to TRACE but everything still gets redirected to console. The file log/trace.log itself is created, it's just never written to. I also tried setting immediateFlush=true but that didn't have any impact either.
I noticed you have status logging (log4j internal logging) set to TRACE. This will dump log4j internal initialization messages to the console. It this what you mean?
Otherwise, the config you provide shows there is no logger that has an appender-ref pointing to the ConsoleAppender.
So, if you are also seeing your application logs being output to the console (in addition to log4j's status log messages), I suspect there is another log4j2.xml (or log4j2-test.xml) config file in the classpath somewhere.
Fortunately log4j's status logs should also show the location of the log4j config file, so you can confirm which config file is actually being loaded.
You can switch off status logging by setting <Configuration status="WARN"> after confirming all works correctly.
I figured it out!
Turns out I was using the gretty plug-in with gradle, which contains it's own logging package (the logback library).
It used it's own internal logback.xml which was redirecting to console. I fixed this by overwriting the internal logback.xml with my own (using logback's configuration) and now everything works as expected!
According to here, Log4j2 should work with Tomcat7.0.47. I'm using TomEE Plus 7.0.47.
I have a webapplication deployed with a log4j2.xml in my web-inf/classes folder. This is the config:
<?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>
<File name="File" fileName="${sys:catalina.home}/logs/testapp.log">
<PatternLayout>
<pattern>%d %p %C{1.} [%t] %m%n</pattern>
</PatternLayout>
</File>
</Appenders>
<Loggers>
<Logger name="org.alex" level="TRACE" additivity="false">
<AppenderRef ref="File"/>
</Logger>
<Root level="INFO">
<AppenderRef ref="Console"/>
</Root>
</Loggers>
</Configuration>
I have a logger declared in a class with name org.alex.util.JSON:
private static final Logger LOG = LoggerFactory.getLogger(JSON.class);
I'm using slf4j-api 1.7.5, and have the following libs added to the tomcat lib:
slf4j-api-1.7.5.jar
log4j-api-2.0-rc1.jar
log4j-core-2.0-rc1.jar
log4j-slf4j-impl-2.0-rc1.jar
If I change the Configuration status to TRACE, I can see my configuration file being picked up and configuration happens as expected. Also I can see the MBeans being added.
However, there's not one logging statement ending up in my logfile. I debugged into the log4j2 Logger, and see that the isEnabled(...) method returns false because the logger (com.alex.util.JSON) has the level "ERROR" set, while the configuration set the package org.alex to TRACE.
Further investigation shows it uses a DefaultConfiguration configured for level=ERROR, and only root is configured. I'm thinking of a classloader issue, but I can't seem to figure out what the cause is and how to solve it.
Does anyone know what I'm doing wrong?
This should work on trunk
Btw saw log4j2 has hacks for tomcat and since tomee wraps classloaders not sure they work as expected...
This is very strange. Please raise a ticket for this in the Log4j2 issue tracker so the Log4j team can take a look.
The problem may go away if you put the jar files you mentioned inside WEB-INF/lib instead of in Tomcat's lib folder.
To be comple log4j2 relies on servletcontainerinitializer which are called after ejb and app scanning so ejbs can be loaded too early. Doing the same with a tomcat context listener would make it working better