Using slf4j logger in a simple mvc Spring web project - java

I am learning spring web mvc project from online resources, i came across this logger slf4j, and i want to use it in my application.
I don't have any idea on how to add this. what i am thinking is i should remove commons-logging.jar from lib folder, and add another jar file to lib folder, but then i don't know which jar file i should add as there are many jar files present in slf4j.zip that i have downloaded from its official site.
I have searched and read few posts/articles about integrating slf4j but they all were related to maven, and i don't have maven, i simply started working with adding spring framework jars to dynamic web project.
Please tell me how and what files i should add in lib folder for logging purpose. or how to configure the slf4j logger.
thanx folks!!

The official source of information on logging in Spring is the Spring Reference.
If you want to use SLF4J, this document suggests using the following Maven dependencies:
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>4.0.6.RELEASE</version>
<exclusions>
<exclusion>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
<version>1.5.8</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.5.8</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.5.8</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.14</version>
</dependency>
</dependencies>
In other words, you need four .jar files, and you need to make sure that the Commons Logging library is NOT on your classpath.
If you do not use Maven, you can download these .jars from the Maven Central Repository manually. Enter groupId, artifactId and version on that page, press Search, and download the .jar file (not sources.jar!). Here are direct links to these .jar files: jcl-over-slf4j, slf4j-api, slf4j-log4j12, log4j.
You will also need to create and put on your classpath the configuration file for log4j (log4j.xml or log4j.properties).
I think that by not using Maven you make your life harder, not easier. It's better to spend some time learning it, than spend a lot of time trying to avoid learning it.

I would actually argue against using pure SLF4J to begin with, because its own creators have already created a successor.
Reasons to use it instead of SLF4J are given on http://logback.qos.ch/reasonsToSwitch.html
And the "First baby steps" in the manual are at http://logback.qos.ch/manual/introduction.html

Related

Displaytag + Tomcat -> silent failure

I'm trying to rehabilitate project which is approx 10 years old.
It is a java webapp which used to run well in Tomcat 6. There is a small cluster of modules which were variously built with Ant and Maven, using Java 5 and Java 6.
I've now got them all building correctly with Maven, using Java 6, deploying to Tomcat 7, trying to aim for the same version of dependencies - just to get it running, before attempting upgrades.
Some of the JSP pages use DisplayTag 1.2. If my Maven build includes the displaytag dependencies then the webapp doesn't run. There's no errors in the logs. It just reports a 404 for everywhere. If I exclude displaytag from the Maven build, everything works fine, except the JSP pages needing DisplayTag.
If I try to run the webapp in Tomcat 6, I get exception to do with incompatibilities between commons-logging and slf4j.
If a webapp silently fails like this, with no errors or exceptions in the logs, what should I suspect or investigate?
UPDATE
Based on Kayaman's answer, here is what I did:
Any place in any pom.xml which had a dependency on commons-logging, add the following:
<exclusions>
<exclusion>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
</exclusion>
</exclusions>
Where there is an explicit dependency on commons-logging, mark it as provided:
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.1.1</version>
<scope>provided</scope>
</dependency>
When booting up the webapp now, this is what I saw in catalina.out:
org.apache.catalina.LifecycleException: Failed to start component [StandardEngine[Catalina].StandardHost[localhost].StandardContext[/webapp]]
Caused by: java.lang.NoClassDefFoundError: Lorg/apache/commons/logging/Log;
... 10 more
Caused by: java.lang.ClassNotFoundException: org.apache.commons.logging.Log
... 24 more
Next I added to the top-level webapp pom.xml the SLF4J "re-router" for commons-logging:
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
<version>1.6.4</version>
</dependency>
Also made sure that the SLF4J was wired up with Log4j, at the correct version (Log4J was the existing logging framework for this webapp, 10 years ago):
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.16</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.6.4</version>
</dependency>
Now when booting the webapp, this allowed JSP errors and Exceptions to be seen in catalina.out, which I was able to debug successfully!
So including the displaytag dependency causes the jsp compilation to fail for all jsps, resulting effectively in the webapp not having any views, hence the 404s. At least a very plausible sequence of events.
According to this any JSP compilation exceptions can be seen in tomcat's localhost_log.xxx file. However, the same thread goes on to complain that there's no info or not enough info, which probably means your logging config is borked.
For that you probably need to set up your logging bridge.
Since you're using slf4j, but other components are using commons-logging, you're losing the log information from the other components. For that you include commons-logging, but as provided, so it won't be pulled in by other libraries.
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.1.1</version>
<scope>provided</scope>
</dependency>
And then you include the jcl-over-slf4j (which is what provides commons-logging as we promised above).
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
<version>2.0.0-alpha2-SNAPSHOT</version>
</dependency>
This should allow components using commons-logging to bridge their logs to your slf4j (and to the actual implementation, logback or whatever).
Here's a link to Jasper's other config things, should they be necessary.

Unable to locate logger configuration in use

I have a jar, say a.jar, for which I'd like to enable logging only at INFO level. This jar also depends on another jar, say b.jar, which uses Apache HTTP client. When I run my application, I see a lot of debug output on the screen including stuff from the Apache HTTP client in this format alone, irrespective of what I put in the log4j.properties:
[com.amazonaws.AmazonWebServiceClient] : Internal logging successfully configured to commons logger: true Ignored FQCN: org.apache.commons.logging.impl.SLF4JLocationAwareLog
For the life of me, I'm unable to figure out where the jars are getting their configuration from. Here're things I tried.
1. Added a log4j.properties to only a.jar's main/resources dir
2. Added a log4j.properties to only b.jar's main/resources dir
3. Removed log4j.properties
Please help me with some inputs as to where the logging configuration may be getting picked up from.
Here're pom extracts of a.jar
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.5</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.15</version>
<scope>compile</scope>
</dependency>
Here's the extract for b.jar
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.7</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.7</version>
<scope>compile</scope>
</dependency>
I assume that you mean this “Apache HTTP client”? If so, then your logging configuration for Log4J does not affect the log output of the HttpClient simply because the latter does neither use SLF4J nor Log4J. As you can see from this POM, HttpClient uses Apache Commons Logging for its log output instead.
So your goal is to redirect all Commons Logging output via SLF4J to Log4J. This requires two steps:
Add an SLF4J bridge for Commons Logging.
Make sure that the bridge is used as a replacement for Commons Logging.
The bridge to add is described here. To make sure that the bridge is actually used, I would recommend to exclude the original Commons Logging JAR. You should be able to achieve both steps with the following new/updated dependencies for your project B:
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.3</version>
<exclusions>
<exclusion>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
<version>1.7.24</version>
</dependency>
I have added the jcl-over-slf4j bridge in the latest SLF4J version 1.7.24 since it seems that your version of SLF4J (1.7.7) doesn’t seem to support Commons Logging 1.2, yet, which might be used by the HttpClient (at least by the one in version 4.5.3).
(Note that I haven’t tested this. But the eventual solution should at least be pretty similar to the described approach.)
Looking at this, it seems like one of the amazon sdk jars is the place this logging configuration would be present in.
It uses apache commons logging and any configuration that you are doing in your project is being done for slf4j and hence is not taking any effect.

Dependency management for SLF4J and Logback

I'd like to start using SLF4J with Logback. I read over Logback's online documentation and am now ready to add the JARs to my repo and try it out.
But I'm at a loss! What JARs do I need? I downloaded that latest SLF4J (1.7.5) and expected to see something like slf4j-logback.jar, but don't see anything of the sorts. I've read that Logback contains a "native implementation" of SLF4J, but don't know exactly what this means, or if it also implies that I don't even need slf4j-api-1.7.5.jar on the classpath.
So I ask: to use the latest Logback (1.0.13), what JARs do I need? I took a look at the Maven central repo for logback 1.0.13 and don't see any dependencies listed, so that didn't help me at all. Thanks in advance!
You need to add logback-classic to your pom
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.0.13</version>
</dependency>
it will transitively add the following two:
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
<version>1.0.13</version>
</dependency>
and
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.5</version>
</dependency>
See https://logback.qos.ch/setup.html#mavenBuild for more information.

"This version of SLF4J requires log4j version 1.2.12" warning with log4j 1.2.17

I have a Java Maven project whose dependencies include slf4j and its log4j adapter.
I manage the versions of log4j, slf4j-log4j12 and slf4j-api to its newest versions according to http://mvnrepository.com and especially the log4j version of 1.2.17 is well over 1.2.12 but I still get the error
SLF4J: This version of SLF4J requires log4j version 1.2.12 or later.
See also http://www.slf4j.org/codes.html#log4j_version
which is totally unclear to me.
My Maven dependency management looks like this:
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.apache.jena</groupId>
<artifactId>apache-jena-libs</artifactId>
<type>pom</type>
<version>2.10.0</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.5</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.5</version>
</dependency>
</dependencies>
</dependencyManagement>
How can I get rid of the warning?
P.S.: I also get a java.lang.NoSuchMethodError: org.apache.log4j.Logger.isTraceEnabled().
P.P.S.: Because of your comments I remembered that the program has a "lib" folder which is not included in the classpath by Maven but by Eclipse itself so the conflicting dependencies must lie there. Sorry, I totally forgot that I guess that's my fault for mixing Maven with a lib folder. I guess I must try to convert as much of the libraries to maven dependencies.
The strange thing though is just that even if I edit "Order and Export" to put the Maven dependencies at the top, the problem still occurs.
StaticLoggerBinder code in slf4j-log4j12 which gets loaded very early on performs a check to determine whether the TRACE level is available in log4j. Here is the code:
private StaticLoggerBinder() {
loggerFactory = new Log4jLoggerFactory();
try {
Level level = Level.TRACE;
} catch (NoSuchFieldError nsfe) {
Util.report("This version of SLF4J requires log4j version 1.2.12 or later."+
" See also http://www.slf4j.org/codes.html#log4j_version");
}
}
It seems pretty airtight to me.
It may be that some other dependency is pulling in or actually embeds an earlier version of log4j. Some *-standalone.jar files are known to do that.
Check your class path at deployment time. Are you deploying in an app server? Is an older version of log4j on the server class path? In a java endorsed path?
You should define the <dependency> outside the <dependencyManagement> as the following: -
<dependencyManagement>
<dependencies>
...
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.apache.jena</groupId>
<artifactId>apache-jena-libs</artifactId>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>
</dependencies>
Please see Introduction to the Dependency Mechanism: Dependency Management for further information.
I hope this may help.
Changing comment to answer, since it appeared to solve the issue.
This is a classloader problem, maven built it correctly but is missing
for dependencies. Could you try to provide the missing dependencies to
maven? Otherwise I suggest you look in the Eclipse specific
dependencies.

Order of JAR loading inside EAR's APP-INF/lib

Will adding a MANIFEST.MF file with Class-Path attribute to META-INF directory inside EAR influence the order of loading of JARs located in APP-INF/lib under WebLogic 8.1?
I don't believe you can control the APP-INF/lib order via ClassPath attribute of MANIFEST.MF.
I've done this a couple different ways, depending on the client.
Add the patch jar to the system classpath for WLS. If you examine domain/bin/setDomainEnv.sh (or .cmd) there should pre, post, patch classpath environment variables. You could try to add your patch jar to the classpath here. This makes it available for all apps, which might not be what your client wants.
Patch somejar.jar & name it somejar-patched.jar. Replace the jar in APP-INF/lib with the "-patched" version.
I thought the class loader read JARs as they're required by your application.
I have two questions for you:
Why are you still using WebLogic 8.1? It's off support now, and the current version is 10.x. You're two versions behind. Is this a legacy app that hasn't migrated yet? You'll get a big boost by upgrading, because you'll be using JDK 5 or 6 with the -server option. I'd recommend it.
Why should you care about the order of loading? It should be immaterial to your app how the container loads and manages the beans.
UPDATE:
That sounds different, almost as if you were having conflicts with server JARs. There's that prefer-web-inf-classes setting for that situation. Is that what you mean?
I agree with duffymo
You shouldn't have to worry about the order of class loading, if this is due to conflicting classes you can always exclude the conflicting classes from Jars using Maven or a similar tool.
For instance this is a very simple example of adding jersey-spring4 jar but I'm excluding its dependencies so I can use a different version of the spring framework library.
<dependency>
<groupId>org.glassfish.jersey.ext</groupId>
<artifactId>jersey-spring4</artifactId>
<exclusions>
<exclusion>
<artifactId>spring-web</artifactId>
<groupId>org.springframework</groupId>
</exclusion>
<exclusion>
<artifactId>spring-aop</artifactId>
<groupId>org.springframework</groupId>
</exclusion>
<exclusion>
<artifactId>spring-context</artifactId>
<groupId>org.springframework</groupId>
</exclusion>
<exclusion>
<artifactId>spring-beans</artifactId>
<groupId>org.springframework</groupId>
</exclusion>
</exclusions>
</dependency>

Categories