Migration from log4j 1.x to log4j2 - java

Hi I came across some code which is using log4j. I want to move to log4j2.
From http://logging.apache.org/log4j/2.x/manual/migration.html I came to that log4j-1.2-api.jar can be used. I have following question :
In code I have a custom appender (as given in that link I should not use internals of class Appender) is that mean I can't use log4j-1.2-api.jar ?
I also want to use asyn logging feature of log4j2 . How do I do that using log4j-1.2-api.jar.

Your custom appender may no longer work. Log4j2 has a lot of functionality, and depending on what your custom appender did, it could be that this functionality already exists in log4j2. You can ask on one of the mailing lists and if it is a function that could be useful for many users it may be added to log4j2.
To use the async loggers, you can either make all loggers async with a system property (http://logging.apache.org/log4j/2.x/manual/async.html#AllAsync) or mix synchronous and async loggers with configuration (http://logging.apache.org/log4j/2.x/manual/async.html#MixedSync-Async). Both should work when you drop in the log4j-1.2-api jar (in addition to the log4j-api and log4j-core jars, these two jars are always needed).

There is a migration guide. I used it successfully.
http://logging.apache.org/log4j/2.x/manual/migration.html
In log4j2 everything is cofigured using a XML file (or more XML files, e. g. for your test directory). The file should be named log4j2.xml.

Related

log4j2 changing configuration during runtime - already supported or custom class needed?

I'm new to logging and wanted to use slf4j with log4j2 in a project of mine.
The configuration is using a json file.
I know that you can create a configuration during runtime with a ConfigurationFactory or use a file that will be checked if it has changed every time a log statement is made and a given time (or none) has passed.
My question is regarding the json file. Will i have to write my own class to change that file using a json parser or will slf4j/log4j2 change the file for me somehow? If so how?
I was reading through the documentation and googled, but didn't find the answer.
I hope you can help me out. :)
First write you code against the slf4j API. It's mostly a bunch of interfaces, and you don't want to "pollute" your code with non-slf4j API if you're using the slf4j logging interface.
Then you want to package / run with log4j-slf4j-impl-2.0.jar which adapts the slf4j API to the log4j2 API. Then you can configure your log4j2 system like you would if you never used slf4j.
Do not use the log4j-to-slf4j-2.0.jar, as that is intended to make code written to log to log4j loggers put their logging on the slf4j API, and if slf4j then implements that with a slf4j logger, your logging events will be passed between slf4j and log4j in an endless loop.
---- Editing post to address question, as it would be too much to put in a comment ----
slf4j is a logging suite with three main kinds of components.
A set of "input adapters" that take one logging system and pipe it into the slf4j API.
An slf4j API that doesn't make any assumptions about how logging is implemented.
A set of "output adapters" that take the slf4j API calls and cram them into some "other" logging system.
The input adapters typically have names like "logsystem-to-slf4j-version.jar", and should be used when you want to migrate to slf4j but haven't rewritten your code to stop using the "old" logging interface.
The output adapters typically have names like "logsystem-slf4j-impl-version.jar" and only one should be provided to slf4j at runtime.
Because slf4j is unaware of which logging adapter it might use to actually process the log messages, it is unaware of the configuration capabilities of that logging system.
Even worse, while logging typically has a semi-similar interface for the submission of log messages, they have vastly different interfaces for configuring the handling of such messages.
In short, if slf4j only adapts the handling of log messages, not the handling of configuration (which is vastly different between say System.out.println(...) and log4j)
This means that at best, you can filter your log messages at the slf4j API layer; but, there is no guarantee that they will be presented; because the underlying logging implementation may be configured to filter even more messages, or may be replaced with a "no logging at all" implementation.
Within some bounds it is possible to have log4j2 react on runtime values: With properties (which can grab entries from System config or ThreadContext), it's simple enough to inject some dynamism.

Embedded Jetty and Complex Logging

Jetty 9 is used for the embedded server and everything works well. One thing that remains is the logging issue.
Prior to that mvn:jetty-run brings his own logging setup with it and logs to the console. That is good for development. In the production environment we need something more special.
Currently on start-up the SLF4J complains about, that there is no binding available, so we can chose freely.
That is what we want to archive:
We need to log to the console if we are starting in a non-production environment.
In the production environment the logging should be done in a single log-file but on a daily rotation with the naming schema: logs/logname-date.log (e.g. logs/application-20130926.log)
We distinguish between the production and non-production mode using a command line argument '-production'.
Since the jetty server is embedded I would love to have a solution which we can fully configure the logger without the need to manage xml or properties-files taking the logging configuration aspect out of the deployment process.
So what options do we have and how can we do this in the best possible way?
Update: It seems that logback is the way to go. It has support for the logfile rotation and also makes it possible to use a console output. The difficult question remaining is how to do this programatically and without additional files.
You have hundreds of configuration options here.
You will need to know a few things about your application before you can pick an appropriate configuration here.
How are logging events emitted from your code? the jetty server? and all 3rd party libraries?
Then you want to answer, what logging framework do you want to handle output (to disk, and to console) portions of the logging architecture?
This is documented at Jetty:
http://www.eclipse.org/jetty/documentation/current/example-logging-logback-centralized.html
Yes, that documentation isn't for embedded mode, but it is still relevant.
Your required logging jar files:
The basic api jar:
slf4j-api.jar (required, no matter what you choose below)
The log capturing jars:
(pick [0..n] jars here)
log4j-over-slf4j.jar (slf4j handling of log4j events)
jul-to-slf4j.jar (slf4j handling of java.util.logging events)
jcl-over-slf4j.jar (slf4j handling of jakarta commons-logging events)
The log output jars:
Pick only 1 of the following output jars:
slf4j-simple.jar (this is a super simple logging implementation, not suitable for production)
logback-classic.jar (slf4j's own output logging framework)
also requires logback-core.jar
slf4j-log4j12.jar (route slf4j events to log4j for processing)
also requires log4j.jar
do not use if using log4j-over-slf4j.jar from above
slf4j-jdk14.jar (route slf4j events to java.util.logging for processing)
do not use if using jul-to-slf4j.jar from above
slf4j-nop.jar (route slf4j events to nowhere, silently discard them)
slf4j-jcl.jar (route slf4j events to jakarta commons-logging)
also requires commons-logging.jar and your choice of commons-logging implementation.
do not use if using jcl-over-slf4j.jar from above
Configure it all:
Be sure you read the slf4j manual on each of these jars, as there is sometimes some extra setup details you might need to know about.
For your described situation, the most appropriate output jars would be logback-classic.jar or slf4j-log4j12.jar. As for configuring the output, you would need to rely on the documentation that those libraries provide.
Logback Documentation
Log4j Wiki
So finally here is the complete picture.
After all the logging configuration in a programmatic way is just described here: http://logback.qos.ch/manual/configuration.html#joranDirectly
I use the logback API just as stated by Joakim. Once you learn how to program it programmatically using the JoranConfigurator object everything is quite easy. Play with it and you get the picture.
I managed to accomplished all tasks at hand.
Thanks for the help Joakim. I was missing the JoranConfigurator thingy. Thanks!
Update:
I used a StringReader and embedded the xml configuration file directly in the Logging configuration class. This way I dont have to manage additional files and logging works as expected.

Difference between Logger.getLogger(className) and LogFactory.getLog(className )?

I know its a package difference
1) org.apache.log4j.Logger logger = Logger.getLogger(clazz);
2) org.apache.commons.logging.Log log = LogFactory.getLog(clazz);
The first one uses loggers via log4j and the second one uses commons.logging. We have a huge project where in some classes loggers are configured using log4j and in some cases its commons.logging.
I did find a log4j property file though.Is there a similar property file for commons.logging ? Where do I configure for commons-logging ?. I am unable to see the logs generated by commons-logging.
Any help is appreciated.
Yes, commons-logging is a facade API that was suppose to abstract you from underlying logging framework (in practice there was a choice between log4j and java.util.logging) so that you could switch from one to another without touching the code - just by switching libraries available on the CLASSPATH.
Unfortunately due to some design mistakes it had issues with complex class-loading environments, like application servers. Currently it is effectively superseded by slf4j.
In your case I would recommend sticking with one API - either Log4J or commons-logging, even though commons-logging will (most likely) delegate to log4J. You can also migrate to using SLF4J and install bridging APIs, but this is slightly more advanced.

Baffled by Java Logging Systems with Spring and Hibernate

WHen deploying my Spring / Hibernate application, I get the following warning related to logging:
log4j:WARN No appenders could be found for logger (org.springframework.web.context.ContextLoader).
log4j:WARN Please initialize the log4j system properly.
Surprising to me was the lack of information from a Google / SO search. The only thing relevant was this SO post Problem with Commons Logging / Log4j setup in spring webapp with tomcat 6
However, this is even beyond me. Can somebody clarify the logging systems in play here, or point me to a RECENT resource on the matter (there are some ancient google search results that don't really apply). Specifically, the issues I'm wrestling with are:
The distinction among commons-logging, log4j, slf4j and JCL. My understanding is that slf4j is a wrapper, while commons-logging and log4j are actual implementations. I don't know where JCL fits in.
How to configure logging for Spring. What does in the web.xml file, do i need a log4j.properties file or a log4j.xml file? Where does it go, in WEB-INF? Does anything go in my applicationContext.xml file? (sorry but I need to start from zero here).
I am using Hibernate in my project and including via Maven. It seems that Hibernate uses slf4j-simple. I have seen warnings saying that I can't have slf4j-simple and slf4j-log4j both on the classpath. I have not included slf4j-log4j as a dependency, but Hibernate must be including it. How do i solve this problem? Can I force Hibernate to use log4j instead?
Any help would be greatly appreciated. Thanks.
edit:
Thanks for all the answers so far. I am giving these suggestions a try. What about spring web-app specifically? I've seen examples of listeners and parameters and whatnot put into the web.xml file. Is this also required?
commons-logging and SLF4J are both API wrappers around other logging implementations. SLF4J is the more modern of the two, and rather more capable. Log4j is a logging implementation, and pretty much the defacto standard. JUL (short for java.util.logging) is the (generally awful) logging implementation that comes with the JRE. Another log implementation is logback, which is slowly gaining traction, but not at all widespread yet.
log4j.properties and log4j.xml are different ways of configuring log4j, both are equally valid. Which one you use is up to you, although some application servers dictate one or the other. Read the log4j manual to find out how to configure this.
If Hibernate uses SLF4J as its API, that's the choice of the Hibernate developers. However, you can choose which logging implementation SLF4J will delegate to. Again, read the slf4j manual to find out how to select your chosen implementation.
Yes, it's all rather confusing. Given an open choice, SLF4J and Logback is the most capable combination, but you usually don't get an open choice. Different frameworks (like Hibernate and Spring) will potentially use different logging APIs, usually commons-logging or SLF4J, but you can get all those APIs to eventually log to the same underlying implementation (usually log4j).
The distinction among commons-logging, log4j, slf4j and JCL. My understanding is that slf4j is a wrapper, while commons-logging and log4j are actual implementations. I don't know where JCL fits in.
Jakarta Commons Logging (JCL) and Simple Logging Facade for Java SLF4J are both abstractions for various logging frameworks e.g. java.util.logging, log4j and logback, allowing the end user to plug in the desired logging framework at deployment time. Commons Logging is known to suffers from class loader problems which is what SLF4J tries to solve (SLF4J is known to be a cleaner library).
Having that said, the fact is that Spring uses Jakarta Commons Logging API (see Logging Dependencies in Spring): Spring is compiled against JCL and Spring makes JCL Log objects available for classes that extend Spring. The is actually the only mandatory external dependency in Spring. This choice has been made because many other frameworks where also using it (e.g. Struts). The idea was to avoid having to have multiple facade libraries on the class path when building applications ("A" for Spring, "B" for Struts, etc). It is however possible to replace JCL by SLF4J if you want to (SFL4J provides bindings to logging frameworks but also a "JCL to SLF4J" bridge). See the mentioned post Logging Dependencies in Spring for all the details.
How to configure logging for Spring. What does in the web.xml file, do i need a log4j.properties file or a log4j.xml file? Where does it go, in WEB-INF? Does anything go in my applicationContext.xml file? (sorry but I need to start from zero here).
To log, you have 1. to decide which implementation you want to use (java.util.logging, log4j or logback), 2. to put the chosen one on the classpath if required (java.util.logging is in Java SE so it doesn't require extra libraries) and 3. to configure it (by putting a config file on the classpath). If you choose to use log4j, just add its jar and a log4j.properties or a more fancy (but more verbose) log4j.xml (this is just another format for the configuration) to the classpath.
I am using Hibernate in my project and including via Maven. It seems that Hibernate uses slf4j-simple. I have seen warnings saying that I can't have slf4j-simple and slf4j-log4j both on the classpath. I have not included slf4j-log4j as a dependency, but Hibernate must be including it. How do i solve this problem? Can I force Hibernate to use log4j instead?
Hibernate utilizes Simple Logging Facade for Java (SLF4J) and, indeed, you can't have several bindings (e.g. slf4j-simple.jar and slf4j-logj12.jar) on the classpath at the same time. Here, you are very likely getting slf4j-simple.jar transitively from another dependency. To solve this problem, run mvn dependency:tree to figure out from where it's coming from and exclude it if required.
And by the way, in your case, I would configure Spring to use SLF4J as Hibernate is using it. Follow the steps in the link mentioned in the first paragraph for that. And I would use logback as logging framework (which the successor of log4j), this is where things happen now.
You need a log4j.properties file in your classpath. Here is a minimal properties file I happened to have created yesterday:
log4j.logger.BillReview=INFO,BillReviewLog
log4j.appender.BillReviewLog=org.apache.log4j.RollingFileAppender
log4j.appender.BillReviewLog.File=BillReview.log
log4j.appender.BillReviewLog.Append=true
log4j.appender.BillReviewLog.MaxFileSize=5000KB
log4j.appender.BillReviewLog.MaxBackupIndex=5
log4j.appender.BillReviewLog.layout=org.apache.log4j.PatternLayout
log4j.appender.BillReviewLog.layout.ConversionPattern=%c %p %-10.10X{server} %-4.4X{user} %d{ISO8601} %m%n
Put that into a log4j.properties file, change all the references to 'BillReview' to something more like your project and that'll log to a file and stop those messages.
Your questions about which logging framework are largely personal choice. Log4j is the old standard and it works fine, Commons logging and slf4j are newer APIs and allow some more complicated use cases.
I'll let some more experienced Gurus than I answer the first bullet.
Answering your second bullet...
You can use either a log4j.properties or log4j.xml file (it doesn't matter which). Whatever you choose you should add it to your classpath (typically it should go in the same directory as your source code). If you are using Spring, a nice way to break your src directory up into logical portions is by using the following directory structure...
src/main/java -- put main source here
src/main/resources -- put resources used by you main source here
src/test/java -- put test source here (for tests)
src/test/resources -- put resources for tests here
You would therefore put your log4j.properties in the src/test/resources directory.
Answering your third bullet...
You can exclude a dependency within a dependency in you pom.xml file by doing the following...
<dependency>
<groupId>org.apache.xbean</groupId>
<artifactId>xbean-spring</artifactId>
<version>${xbean.version}</version>
<exclusions>
<exclusion>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
I had problems in the same area while running my tests. I eventually noticed that junit was bringing in slf4j-nop as a dependency, in addition to the slf4j-log4j12 that I wanted. Once I excluded slf4j-nop, it started working.

Log4j Properties in a Custom Place

I'm using Apache Commons Logging and SLF4J with log4j, but I also want to use the log4j.properties in a custom place like conf/log4.properties. Here is the problem:
If i use
PropertyConfigurator.configure("conf/log4j.properties");
then my app is tied to log4j and defeats the purpose of having ACL and SLF4J.
What is the best way to configure it without the app ever knowing what the logging implementation is?
I think the easiest thing to do is specify the location of the file using the log4j.configuration system property. Adopting the example in the Log4J manual:
java -Dlog4j.configuration=conf/log4j.properties -classpath ...
I believe that Log4J will find a file named "log4j.properties" anywhere on the classpath, but may be hallucinating. Worth trying, however.
As you state, by invoking PropertiesConfigurator, you are tying your application to log4j. However, the extend of this tie is quite limited. You could very easily remove the line invoking PropertiesConfigurator and recompile your code. After that is done, assuming you are using the SLF4J API for logging, you could repalce log4j with another logging framework, say logback-classic or j.u.l. just by replacing jar files. Thus, SLF4J still serves its purpose to a large extend. I would not throw the baby out with the bath water.
You can specify config file location with VM argument
-Dlog4j.configuration="file:/C:/workspace3/local/log4j.properties"

Categories