Embedded Tomcat using log4j for logging - java

I'm using embedded Tomcat 8.5.4, i.e.,
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-core</artifactId>
<version>8.5.4</version>
</dependency>
The implementation is working perfectly (Tomcat works like a charm), the only thing that's bothering me, is that the embedded Tomcat logs on System.out. Internally within my application I'm using log4j for logging, so this leads to the following logging mixture (and not logging of Tomcat to any file):
...
2017-07-30 17:57:54 DEBUG EmbeddedTomcat:136 - Binding servlet 'sample' to path '/sample/*'.
Jul 30, 2017 5:57:54 PM org.apache.coyote.AbstractProtocol init
INFO: Initializing ProtocolHandler ["http-nio-15000"]
Jul 30, 2017 5:57:54 PM org.apache.tomcat.util.net.NioSelectorPool getSharedSelector
INFO: Using a shared selector for servlet write/read
Jul 30, 2017 5:57:54 PM org.apache.catalina.core.StandardService startInternal
INFO: Starting service Tomcat
Jul 30, 2017 5:57:54 PM org.apache.catalina.core.StandardEngine startInternal
INFO: Starting Servlet Engine: Apache Tomcat/8.5.4
Jul 30, 2017 5:57:54 PM org.apache.coyote.AbstractProtocol start
INFO: Starting ProtocolHandler [http-nio-15000]
2017-07-30 17:57:54 INFO EmbeddedTomcat:80 - Successfully started Tomcat on port 15000 (base: null, url: http://localhost:15000).
...
In this snippet the first and the last line (after and before the ...) are logged by my application using log4j and the configuration of log4j (which writes to a file and the System.out). Nevertheless, the middle part (logging of Tomcat) is handled by the Embedded Tomcat and I have no clue, how to get Tomcat to use the available log4j (and it's configuration).
I tried to add the following dependency (a 8.5.4 version is not available on Maven Repository or Maven Central), but without any success.
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-logging-log4j</artifactId>
<version>8.5.2</version>
</dependency>
Does anyone know how to get the Embedded Tomcat to log using log4j (Version 1, I'm not using log4j2)?
I looked at/tried the following StackOverflow answers:
https://tomcat.apache.org/tomcat-8.0-doc/logging.html
So I looked at the documentation, which mentions log4j as logging framework. It mentions tomcat-juli-adapters.jar, which I could not find for the embedded version (is it the same as the "normal" Tomcat?). How would I do that programmatically, i.e., within my Embedded Tomcat implementation.
Tomcat Logging using log4j?
That's not really the problem I'm having, it's not based on the Embedded Tomcat, the version is pretty old, and I'm actually using log4j not System.out.
Embedded Tomcat logging over logback / sl4j
This question actually deals with logback and the author mentions that I found some info about using a standalone tomcat with log4j, but the standalone is different, I see the author is using similar dependencies, but not sure if there was ever a solution.
How to enable embedded tomcat logging
First I thought his may be the solution, but it all just deals with an additional logging for the Embedded Tomcat. I want the Embedded Tomcat to use the applications log4j, so one log4j.properties file, which defines how everything is logged.
Logging in Embedded Tomcat
I'm not sure why this answer is even marked as correct, but this is just an explanation how Tomcat writes the catalina.out file and not how the logging of the Embedded Tomcat works.

It took me a while, but after I got the sources of the 8.5.4 implementation, I realized that the juli logging implementation is added in the core jar.
Version <= 8.5.2
So I went back and started to work with the 8.5.2 version and used tomcat-embed-logging-log4j-8.5.2.jar, as well as tomcat-embed-core-8.5.2.jar. The first important thing to notice is, that against most of the documentation online, it is important that you do not add the tomcat-embed-logging-juli-8.5.2.jar. With that said, the 8.5.2 version works with log4j out of the box and there is nothing more to be done.
Version > 8.5.2
When using a newer version of the embedded Tomcat, i.e., 8.5.4. or even the newest one 8.5.19, the LogFactory is already included in the jar. Thus, when adding the older tomcat-embed-logging-log4j-8.5.2.jar on the classpath there are two LogFactory implementations available now. The first one is provided with the core and loads the DirectJDKLog (I refer to this one as Core-LogFactory) and the second one is provided through log4j (referred to as Log4j-LogFactory). Thus, when the LogFactory is loaded from the class-path, the Core-LogFactory is picked (because it is in the same jar and thus "closer" (no need to get too deep into the classpath loading order)). In general, it is bad practice to have the same class (in the same package) on the classpath. This will only lead to confusion and you mostly never know which class is actually used (yes I know there are ways and rules, but long story short, it is not good). Thus, I decided instead of using the tomcat-embed-logging-log4j-8.5.2.jar furthermore, I followed the ServiceLoader approach, which is actually implemented in the Core-LogFactory of the newer versions (https://svn.apache.org/repos/asf/tomcat/trunk/java/org/apache/juli/logging/LogFactory.java).
private LogFactory() {
// Look via a ServiceLoader for a Log implementation that has a
// constructor taking the String name.
ServiceLoader<Log> logLoader = ServiceLoader.load(Log.class);
Constructor<? extends Log> m=null;
for (Log log: logLoader) {
Class<? extends Log> c=log.getClass();
try {
m=c.getConstructor(String.class);
break;
}
catch (NoSuchMethodException | SecurityException e) {
throw new Error(e);
}
}
discoveredLogConstructor=m;
}
To do so, I added the file org.apache.juli.logging.Log in the META-INF/services folder (within my jar/sources) and added the fully qualified name of my "own" Log implementation, i.e., net.meisen.tomcat.logging.Log4jLog, which is as following:
package net.meisen.tomcat.logging;
import org.apache.juli.logging.Log;
import org.apache.log4j.Logger;
public class Log4jLog implements Log {
private final Logger logger;
// this constructor is important, otherwise the ServiceLoader cannot start
public Log4jLog() {
logger = Logger.getLogger(Log4jLog.class);
}
// this constructor is needed by the LogFactory implementation
public Log4jLog(final String name) {
logger = Logger.getLogger(name);
}
// now we have to implement the `Log` interface
#Override
public boolean isFatalEnabled() {
return true;
}
// ... more isLevelEnabled()
#Override
public boolean isTraceEnabled() {
return logger.isTraceEnabled();
}
// ... and also all the fatal(...) - trace(...) methods
#Override
public void fatal(final Object msg) {
logger.fatal(msg);
}
#Override
public void fatal(final Object msg, final Throwable throwable) {
logger.fatal(msg, throwable);
}
}
And et voilĂ , here is the final result:
2017-07-31 19:27:04 TRACE EmbeddedTomcat:48 - Initializing Tomcat on port 15000 (base: null)...
2017-07-31 19:27:33 INFO Http11NioProtocol:69 - Initializing ProtocolHandler ["http-nio-15000"]
2017-07-31 19:27:33 INFO NioSelectorPool:69 - Using a shared selector for servlet write/read
2017-07-31 19:27:33 INFO StandardService:69 - Starting service [Tomcat]
2017-07-31 19:27:33 INFO StandardEngine:69 - Starting Servlet Engine: Apache Tomcat/8.5.19
2017-07-31 19:27:34 WARN SessionIdGeneratorBase:79 - Creation of SecureRandom instance for session ID generation using [SHA1PRNG] took [170] milliseconds.
2017-07-31 19:27:34 INFO Http11NioProtocol:69 - Starting ProtocolHandler ["http-nio-15000"]
2017-07-31 19:27:34 INFO EmbeddedTomcat:80 - Successfully started Tomcat on port 15000 (base: null, url: http://localhost:15000).
Appendix:
Here are some links that helped me to figure out the ServiceLoader stuff and why I decided pretty fast not to have the same class in the same package in different jars in my project:
ServiceLoader using ClassLoader pointing to different path
Java ServiceLoader explanation
http://tshikatshikaaa.blogspot.com/2013/03/java-serviceloader-example.html

Related

Running vert.x cluster backed by hazelcast cache in distributed mode

We are using Vert.X library to develop REST service layer to receive messages from many sources. Part of the requirements is to run REST verticle(s) in High availability (HA) mode. We are following vert.x core manual for implementation of VertX cluster to run in distributed cluster (3 nodes to start with).
Based on the documentation we did the following
Included hazelcast library in dependencies
io.vertx
vertx-hazelcast
3.3.0
Created a fat jar with the following manifest entries and added resources folder in classpath which has required configurations to load. We took hazelcast-default.xml from vertx-examples from github
log4j.properties
config.json
hazelcast-default.xml
io.vertx.core.Launcher
com.msg.verticles.RootVerticle
resources/
Created a script file to trigger the launcher
java -jar -Xmx2048m -Xms512m message-1.0-SNAPSHOT.jar -ha -D config=resources/config.json
Launcher fails to to pickup hazelcast-default.xml from resurce folder and stops with the following exception. Not sure what I am missing here.
$>java -jar -Xmx2048m -Xms512m message-1.0-SNAPSHOT.jar -ha -D config=resources/config.json
Jul 16, 2017 7:20:26 PM io.vertx.core.impl.launcher.commands.RunCommand
INFO: Starting clustering...
Jul 16, 2017 7:20:27 PM io.vertx.core.impl.launcher.commands.RunCommand
INFO: No cluster-host specified so using address 127.0.0.1
Jul 16, 2017 7:20:28 PM io.vertx.spi.cluster.hazelcast.HazelcastClusterManager
WARNING: Cannot find cluster configuration on 'vertx.hazelcast.config' system property, on the classpath, or specified programmatically. Using default hazelcast configuration
Jul 16, 2017 7:20:28 PM com.hazelcast.config.XmlConfigLocator
INFO: Loading 'hazelcast-default.xml' from classpath.
Jul 16, 2017 7:20:28 PM com.hazelcast.config.AbstractXmlConfigHelper
WARNING: Name of the hazelcast schema location incorrect using default
Jul 16, 2017 7:20:28 PM io.vertx.core.impl.VertxImpl
SEVERE: Failed to join cluster
com.hazelcast.core.HazelcastException: org.xml.sax.SAXParseException; schema_reference.4: Failed to read schema document 'null', because 1) could not find the document; 2) the document could not be read; 3) the root element of the document is not <xsd:schema>.
at com.hazelcast.util.ExceptionUtil.peel(ExceptionUtil.java:73)
According to the documentation of Hazelcast cluster manager you need to specify your Hazelcast configuration in a file named cluster.xml in your classpath (either embedded in the root of your fatjar or in a directory that is in your classpath).
Solved the issue by configuring zookeeper as co-ordination service. Which worked like a champ!!
https://github.com/vert-x3/vertx-zookeeper

Figuring out Spring Logging

I've inherited a, well, messy, Spring MVC application. Some things don't work and I want to enable DEBUG or even TRACE logging to get more information and found that even that is not that simple.
When starting the application (by running a Tomcat 8 server from Eclipse), it seems to output two kinds of log messages. Here is an example of the first kind:
Jun 20, 2017 1:47:07 PM org.hibernate.Version logVersion INFO:
HHH000412: Hibernate Core {4.3.8.Final} Jun 20, 2017 1:47:07 PM
org.hibernate.cfg.Environment <clinit> INFO: HHH000206:
hibernate.properties not found Jun 20, 2017 1:47:07 PM
org.hibernate.cfg.Environment buildBytecodeProvider INFO: HHH000021:
Bytecode provider name : javassist
These messages are all in red. The second kind looks like this:
13:47:16.949 [localhost-startStop-1] INFO org.springframework.web.servlet.DispatcherServlet:489 - FrameworkServlet 'spring': initialization started
13:47:16.952 [localhost-startStop-1] INFO org.springframework.web.context.support.XmlWebApplicationContext:583 - Refreshing WebApplicationContext for namespace 'spring-servlet': startup date [Tue Jun 20 13:47:16 IDT 2017]; parent: Root WebApplicationContext
13:47:16.952 [localhost-startStop-1] INFO org.springframework.beans.factory.xml.XmlBeanDefinitionReader:317 - Loading XML bean definitions from ServletContext resource [/WEB-INF/spring-servlet.xml]
These are all in black.
Obviously there are at least two active logging formats. This is were it gets weird:
I found numerous log4j2.xml as well as log4j.propertiesfiles. All of them seem to be ignored. Changing them makes no difference. I just deleted them all, and it did not affect the logging output. In addition, log4j 1.2, log4j 2.0.2 and slf4j are all Maven dependencies. pom.xml references version 1.2, other Maven dependencies probably need the other versions.
My question is - how do I configure the logging myself? Placing a log4j.xml file under WEB-INF (were all other property files are located) doesn't make any difference. Neither that placing a log4j.properties file there. I need to somehow turn debug printouts of log4j itself, so I can figure out where it's reading it's configuration from.
I tried adding -Dlog4j.debug as a VM argument to the Tomcat run configuarion. Other than printing -Dlog4j.debug command line argument or something similar, nothing changed.
You can use following code snippet that I have used for my project. Over here class name is FolderReader.class and placed lo4j.properties file in folder "conf".Passing argument "../conf/log4j.properties" as args[2] argument when running the application.
final FileSystemXmlApplicationContext applicationContext = new FileSystemXmlApplicationContext(args[0]);
Logger logger=Logger.getLogger(FolderReader.class);
PropertyConfigurator.configure(args[2]);
logger.info("Intializing beans..");
ServiceContext serviceContext = (ServiceContext) BeanFactoryLocator.getBean("serviceContext");
PropertyConfigurator.configure(args[2]);loads the log4j.properties file from location. Configuration is taken from this property file and formatting is done accordingly.

War deployment in Embedded Tomcat

I have an embedded tomcat (7.0.64) on MAC and am deploying a war file, running on java 1.7.067. For some reason my tomcat server hangs on the call "Tomcat.start()".
I know for sure that it's getting stuck deploying the war file. The way i figured this i plugged in a different war file(a simple hello world) and that worked.
I tried hooking up tomcat log.properties and got the logs directed to file with hope of getting any clues. But i don't see any exception, the logging stops at these lines,
FINE: Loading class from parent
Nov 16, 2015 9:30:01 PM org.apache.catalina.loader.WebappClassLoader loadClass
FINE: Loading class from parent
Nov 16, 2015 9:30:01 PM org.apache.catalina.loader.WebappClassLoader loadClass
FINE: loadClass(com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderFactoryImpl, false)
Nov 16, 2015 9:30:01 PM org.apache.catalina.loader.WebappClassLoader loadClass
FINE: loadClass(com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderFactoryImpl, false)
Nov 16, 2015 9:30:01 PM org.apache.catalina.loader.WebappClassLoader loadClass
FINE: loadClass(com.sun.org.apache.xerces.internal.impl.dv.dtd.DTDDVFactoryImpl, false)
Nov 16, 2015 9:30:01 PM org.apache.catalina.loader.WebappClassLoader loadClass
FINE: loadClass(com.sun.org.apache.xerces.internal.impl.dv.dtd.DTDDVFactoryImpl, false)
Not sure if it can't find "DTDDVFactoryImpl", since this is part of the jdk libraries itself as well as i am including xercesimpl.jar as well.
Basically i am looking for ways that can help me figure out, what or which class is blocking from the web deployment from happening.
Any ideas/pointers?
TIA
Updated - My log.properties looks like,
handlers=java.util.logging.ConsoleHandler, org.apache.juli.FileHandler
org.apache.juli.FileHandler.level=ALL
org.apache.juli.FileHandler.directory=./logs
org.apache.juli.FileHandler.prefix=tomcat-
java.util.logging.ConsoleHandler.level=ALL
java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter
org.apache.catalina.level=FINEST
org.apache.catalina.handlers=org.apache.juli.FileHandler
the line -
FINE: loadClass(com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderFactoryImpl, false)
The above message means that a web application have already been
stopped, but the TimerTask tries to load a class from it.
What web application has started this timer?
If the timer was started by this web application, then it is your
fault. You should have configured a
javax.servlet.ServletContextListener to stop (cancel) the timer when
the web application stops. You cannot load classes when web
application have already been stopped.
OR
If the timer was started by a different web application, it means
that you have PermGen memory leak somewhere. Ensure that you have
JreMemoryLeakPreventionListener configured in server.xml.
It is known that there was a PermGen memory leak in Java XML APIs. A
workaround to suppress it was added to JreMemoryLeakPreventionListener
in r884341 [1]
Mark has a presentation on Memory Leaks
http://people.apache.org/~markt/presentations/2010-11-04-Memory-Leaks-60mins.pdf
OR
Bundling a separate copy of Apache Xerces with the web application
may help. It will not help if the root cause is your failure to cancel
the timer.
[1] http://svn.apache.org/viewvc?view=revision&revision=r884341
hope this helps.

How to configure commons-logging for JUnit testing of Hibernate

I'm trying to debug some hibernate functionality in a spring app with a junit test and commons logging, but I can't seem to get anything other than the default INFO messages to appear. I'm also running these junit tests from Eclipse.
I've had no luck from the spring forums either.
I'm particularly interested in the debug logging output by Hibernate (to try and figure out why it takes 23 seconds to run this test).
Current output shows the default setting of INFO:
Mar 29, 2011 4:44:35 PM org.springframework.test.AbstractTransactionalSpringContextTests onSetUp
INFO: Began transaction: transaction manager [org.springframework.orm.hibernate3.HibernateTransactionManager#5f873eb2]; defaultRollback true
testGetSubjectsForSite time: [00:00:00:068]
Mar 29, 2011 4:44:58 PM org.springframework.test.AbstractTransactionalSpringContextTests endTransaction
INFO: Rolled back transaction after test execution
I've tried to add a commons-logging.properties file to the classpath (the same location as the hibernate.properties and test-components.xml) but still only the default INFO messages appear.
Here's the commons-logging.properties file:
org.apache.commons.logging.Log=org.apache.commons.logging.impl.Jdk14Logger
# handlers
handlers=java.util.logging.ConsoleHandler
# default log level
.level=FINE
org.springframework.level=FINE
org.hibernate.level=FINE
# level for the console logger
java.util.logging.ConsoleHandler.level=FINE
java.util.logging.ConsoleHandler.formatter=java.util.logging.SimpleFormatter
Is anyone able to shed any light on why I can't get the DEBUG messages to print out? Is there a logging setting I'm missing?
Edit: I've tried FINEST and DEBUG to no avail.
Unfortunately, it seems the logging configuration file used by Jdk14Logger should be specified at runtime.
See the following file in your JDK directory: JDK_HOME/jre/lib/logging.properties (it's the default one used if no config file is found)
Moreover, the file path should be absolute, otherwise it's relative to the folder where the JRE is executed - see the code of java.util.logging.LogManager.readConfiguration()
Also see:
http://www.javapractices.com/topic/TopicAction.do?Id=143
http://cyntech.wordpress.com/2009/01/09/how-to-use-commons-logging/
Your default and hibernate logging is at Level "FINE" which is more of a "INFO" in log4j terms.
You need set DEBUG level for org.hibernate which in JDK logging is equal to 'FINEST'
Set
org.hibernate.level=FINEST (in the above log which should enable debug logs)

josso newbie setup problems - can't use tomcat's manager page

I'm trying to setup josso on an apache tomcat server running on windows.
I've installed Apache Tomcat/6.0.26 fro zip file to c:\tomcat
then installed josso following the documentation at
http://www.josso.org/confluence/display/JOSSO1/Quick+Start
started tomcat with c:\tomcat\bin\startup.bat, and noticed the following warnings
ADVERTENCIA: [SetPropertiesRule]{Server/Service/Engine/Realm} Setting property '
debug' to '1' did not find a matching property.
21/03/2010 15:55:03 org.apache.tomcat.util.digester.SetPropertiesRule begin
ADVERTENCIA: [SetPropertiesRule]{Server/Service/Engine/Host/Valve} Setting prope
rty 'appName' to 'josso' did not find a matching property.
...
ADVERTENCIA: Unable to find required classes (javax.activation.DataHandler and j
avax.mail.internet.MimeMultipart). Attachment support is disabled.
...
ADVERTENCIA: Bean with key 'josso:type=SSOAuditManager' has been registered as a
n MBean but has no exposed attributes or operations
...
but then everything seems to work fine, the problem is I can no longer access http://localhost:8080/manager/html using user tomcat /tomcat, as configured in \conf\tomcat-users.xml (before installing josso it worked)
I tried with tomcat/tomcatpwd as defined in \lib\josso-credentials.xml and even added tomcat and the manager role to \lib\josso-users.xml, with no luck...
Is anybody having the same problem? how can I access tomcat's manager page?
Thanks a lot
saludos
sas
This is my config:
C:\tomcat\bin>catalina version
Using CATALINA_BASE: "C:\tomcat"
Using CATALINA_HOME: "C:\tomcat"
Using CATALINA_TMPDIR: "C:\tomcat\temp"
Using JRE_HOME: "c:\java"
Using CLASSPATH: "C:\tomcat\bin\bootstrap.jar"
Server version: Apache Tomcat/6.0.26
Server built: March 9 2010 1805
Server number: 6.0.26.0
OS Name: Windows XP
OS Version: 5.1
Architecture: x86
JVM Version: 1.5.0_22-b03
JVM Vendor: Sun Microsystems Inc
ps: moreover, when shutting down, I get a couple of error like this
GRAVE: A web application appears to have started a thread named [JOSSOAssertionM
onitor] but has failed to stop it. This is very likely to create a memory leak.
21/03/2010 15:57:06 org.apache.catalina.loader.WebappClassLoader clearReferences
Threads
and then tomcat's shutdown freezes at
21/03/2010 15:57:07 org.apache.coyote.ajp.AjpAprProtocol destroy
INFO: Parando Coyote AJP/1.3 en ajp-8009
ps: sorry for this lengthy question...
this may helps you to correct the problem (can't access manager page).
1:In the $CATALINA_BASE/conf/server.xml file remove the following code if present
$CATALINA_BASE/conf/server.xml
<Realm className="org.apache.catalina.realm.UserDatabaseRealm" resourceName="UserDatabase"/>
2:For each non-jossified application add a with configuration in $CATALINA_BASE/conf//
(i.e. In Catalina/localhost set the Tomcat Manager web application as non-jossified)
$CATALINA_BASE/conf/Catalina/localhost
<Context docBase="${catalina.home}/server/webapps/manager" privileged="true" antiResourceLocking="true" antiJARLocking="true">
<Realm className="org.apache.catalina.realm.UserDatabaseRealm" resourceName="UserDatabase"/>
http://www.josso.org/confluence/display/JOSSO1/Jossify+your+Application+for+Tomcat+-+Quick+Start

Categories

Resources