Logging for Apache Tomcat and Velocity using Log4j
Written by Geoff Mottram (geoff at minaret dot biz).
Placed in the public domain on August 28, 2004 by the author.
Last updated: January 27, 2005.
This document is provided "as is", without warranty of any kind, express or implied, including but not limited to the warranties of merchantability, fitness for a particular purpose and noninfringement. In no event shall the author be liable for any claim, damages or other liability, whether in an action of contract, tort or otherwise, arising from, out of or in connection with this document or the use or other dealings in this document.
Contents
Introduction
Tomcat 5.0 Logging
Tomcat 5.5 Logging
Tomcat Commons Logging
Log4j
Log4j Properties File
Caveat
Tomcat Bootstrapping
Tomcat and Jakarta Velocity
WEB-INF Logging
Logger Identifiers in Apache Code
Appendix 1 - Logger Identifiers in Tomcat 5.0.27
Appendix 2 - Logger Identifiers in Jakarta Struts 1.1Introduction
It took a number of hours to get Apache Tomcat version 5.0.27 and Apache Velocity 1.4 to create log files the way I wanted them for a production environment. This document describes some of the things I discovered and provides step by step instructions for configuring Tomcat to generate log files that rotate nightly. This document covers both Tomcat 5.0 and 5.5.Please note: The new alpha version of Log4j 1.3 has added support for a daily rolling log file. See Log4j Version 1.3 and Apache Tomcat for instructions on how to install and configure this new feature.Tomcat 5.0 Logging
Tomcat 5.0 has two primary channels for logging information. The first is usually output to thecatalina.out
file and the other is the Servlet log, which typically saves its messages to files with a date as part of their name (i.e.catalina.2004-08-27.log
).The data in
catalina.out
comes from three sources: data that is written to standard output and standard error, and information that is logged via the Apache Commons Logging interface. This last category includes all manner of output from the Tomcat server about its state of affairs and is also used by other many other systems (like Jakarta Struts). Packages that use the Commons Logging interface can output varying amounts of log data according to how you configure your logging system (more on that in a moment).The data in the Servlet log is generated by calls to the
log()
method of the ServletContext class. For example:To save the output from the Server log in a file, all you need is a FileLogger directive in your TomcathttpServletRequest.getSession().getServletContext().log("Some message");server.xml
file (in the Tomcatconf
directory). It typically looks something like this:<!-- Global logger unless overridden at lower levels --> <Logger className="org.apache.catalina.logger.FileLogger" prefix="servlet." suffix=".log" timestamp="true" />The Servlet log is either on (by including a FileLogger directive) or off (by not having a FileLogger) but there is no way to specify a logging level (i.e. include only INFO messages and higher). While the Tomcat documentation mentions that all of its Loggers support averbosity
value, setting it doesn't seem to do anything.When configuring your Tomcat server, you want to capture both streams of logging data into files that "roll over" every day (i.e. change their name to reflect the date they were made). Using the FileLogger directive in your Tomcat configuration provides a standard way to capture the Servlet log stream to a file that changes each day. This allows you to backup, remove, analyze or whatever else you like to do with your server logs.
It would be nice if there was a Catalina Logger that utilized the Commons Logging interface. That would give you more control over the formatting of the output stream and such a module would be fairly easy to write, but who's got the time? The next section describes how to tame the
catalina.out
log stream.Tomcat 5.5 Logging
Tomcat 5.5 has two avenues for logging data. Anything written to standard out and standard error is always sent to thecatalina.out
file. Everything else has gone through the Apache Commons Logging interface. If you do not configure an alternate logger (like log4j), all logged messages (including everything that goes through commons-logging) ends up in an endlessly growingcatalina.out
.
One improvement in Tomcat 5.5 over version 5.0 is that the Servlet log no longer exists. This used to receive any messages that were passed to the
log()
method of the ServletContext class. For example:httpServletRequest.getSession().getServletContext().log("Some message");Tomcat now sends this information through the commons-logging interface as INFO level messages. By configuring a logger like log4j, you can redirect virtually all of your logging messages into files that "roll over" every day (i.e. change their name to reflect the date they were made). This allows you to backup, remove, analyze or whatever else you like to do with your server logs.
Tomcat Commons Logging
As mentioned above, much of the data in thecatalina.out
file is produced by calls to the Apache Commons Logging interface. Commons Logging gives you run-time control over the level of logging detail and permits you to use any number of underlying logging systems. The standard Tomcat distribution uses SimpleLog as the underlying logger. SimpleLog sends all of its output to standard error, which in Tomcat, is redirected to the filecatalina.out
by default. The biggest problem with this arrangement is that thecatalina.out
file grows forever -- there is no file rotation.Log4j
Log4j is a powerful log manager that supports the Commons Logging interface. It can be dropped into your Tomcat installation as a replacement for SimpleLog to provide log rotation and all manner of configuration options. In fact, you are not limited to saving your logs to a file. They can be sent to the syslog, a remote port or other destinations. You can also send them to more than one place. To use Log4j as your log manager in Tomcat (see the separate instructions on how to install and configure the new alpha version of Log4j 1.3 with Apache Tomcat):The configuration described here results in the creation of two log files for Tomcat 5.5 and three log files for Tomcat 5.0: the Servlet log file (only with Tomcat 5.0), which will roll over to a new file every night; the Commons Logging data via log4j (which will also roll over every night) and the
- Shutdown Tomcat if it is currently running.
- Download the Commons Logging package from the Apache web site (unless you already have it).
- Copy the
commons-logging.jar
file from the distribution into your Tomcatcommon/lib
directory.- Download the Log4j package from the Apache web site (unless you already have it).
- Copy the
log4j.jar
file from the distribution into your Tomcatcommon/lib
directory.- Create a
log4j.properties
file in your Tomcatcommon/classes
directory (see next section).- Restart Tomcat.
catalina.out
file, which will only contain messages that have been printed to standard output and standard error. The last file will grow forever but well behaved applications within your Tomcat server should not be printing to standard out or error, so this should not really be an issue (in general, the file should remain zero length).Note that the
commons-logging.jar
andlog4j.jar
files are installed in the Tomcatcommon/lib
directory and thelog4j.properties
file is installed in thecommon/classes
directory. This arrangement allows both the Tomcat server and your web applications access to the log4j system. If your web applications use the Commons Logging interface, their log data will be output to the Tomcat server log. You can configure the system to output your application data to a different file by changing the configuration of the Log4j properties file (for help with that, you will have to look elsewhere).Log4j Properties File
Yourlog4j.properties
file should look something like this:The only change you have to make is to edit the line with# # Configures Log4j as the Tomcat system logger # # # Configure the logger to output info level messages into a rolling log file. # log4j.rootLogger=INFO, R # # To continue using the "catalina.out" file (which grows forever), # comment out the above line and uncomment the next. # #log4j.rootLogger=ERROR, A1 # # Configuration for standard output ("catalina.out"). # log4j.appender.A1=org.apache.log4j.ConsoleAppender log4j.appender.A1.layout=org.apache.log4j.PatternLayout # # Print the date in ISO 8601 format # log4j.appender.A1.layout.ConversionPattern=%d [%t] %-5p %c - %m%n # # Configuration for a rolling log file ("tomcat.log"). # log4j.appender.R=org.apache.log4j.DailyRollingFileAppender log4j.appender.R.DatePattern='.'yyyy-MM-dd # # Edit the next line to point to your logs directory. # The last part of the name is the log file name. # log4j.appender.R.File=/usr/local/tomcat/logs/tomcat.log log4j.appender.R.layout=org.apache.log4j.PatternLayout # # Print the date in ISO 8601 format # log4j.appender.R.layout.ConversionPattern=%d [%t] %-5p %c - %m%n # # Application logging options # #log4j.logger.org.apache=DEBUG #log4j.logger.org.apache=INFO #log4j.logger.org.apache.struts=DEBUG #log4j.logger.org.apache.struts=INFOlog4j.appender.R.File=/usr/local/tomcat/logs/tomcat.log
to point to your Tomcat logs directory.The above log4j configuration will log info messages as well as those that are more important (warning, error and fatal) to the
tomcat.log
file in your Tomcat logs directory. The first message that is logged after midnight every day will cause the log file to be renamed with the current date appended to the nametomcat.log
and a newtomcat.log
file to be created.The one fly in the ointment with the log4j
DailyRollingFileAppender
is that in order for the log file to be renamed, a message must be logged to trigger the change. This is a problem if you run a cron job every night to do something with your log files. The Tomcat FileLogger solves this problem by always using the current date as part of the current log's file name. I have written a custom Log4j appender that mimics the behavior of the Tomcat FileLogger which you are free to use (source code included). A separate technical tip describes theDatedFileAppender
for Log4j along with installation and configuration instructions.Please note: The new alpha version of Log4j 1.3 has added support for a daily rolling log file. See Log4j Version 1.3 and Apache Tomcat for instructions on how to install and configure this new feature.You can override the default logging level for specific applications with the commands at the end of the configuration file. In production, you may want even less logging and you could change the
log4j.rootLogger=INFO, R
line at the top of the file to readlog4j.rootLogger=ERROR, R
instead.Caveat
Be careful when setting the logging level to DEBUG (particularly something likelog4j.logger.org.apache
, as an enormous amount of information can be generated, slowing your system down considerably.Tomcat Bootstrapping
Please note, you MUST installcommons-logging.jar
into yourcommon/lib
directory. You might have noticed that there is acommons-logging-api.jar
file in thebin
(bootstrap) directory of Tomcat. This jar file appears to be a stripped down version of the fullcommons-logging.jar
file which only implementsSimpleLog
or something like it. Basically, just enough of a logging system to get bootstrapped. While you can't boot without the API version of the logging system, you also can't replace it with a full blowncommons-loging.jar
file without adding your logging system (i.e. Log4j) to the bootstrap classpath.Through some classloading voodoo during bootstrapping, if you have the full
commons-logging.jar
file in your common/lib directory, it replaces the classes from thecommons-logging-api.jar
file and will reinitialize the logging system and attempt to locate log4j or whatever other logging system you may be using.Application Logging
You can log messages in your own Servlet applications by either writing to the Servlet log (i.e.servletContext.log("Some message")
) or by utilizing the Commons Logging interface. This section describes the latter and far superior method of logging and demonstrates how it integrates with the logging enhancements to Tomcat as described above.A sample application:
Thepackage com.acme.webapp; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; public class MyApplication { private Log myLog; public MyApplication() { myLog = LogFactory.getLog(MyApplication.class); } public void process() { // Do some processing myLog.debug("A debug message"); // Do something else myLog.info("An information message"); // etc. } }Log
object can be shared between classes and may be declared as a static class variable to facilitate sharing. In other words, your entire application can share a single Log object or you can use multiple Log objects to provide more run-time control over log generation. You pass theLogFactory.getLog()
method a class, from which the fully qualified name of that class is used as a unique name for that logging object. In the above example, the name would becom.acme.webapp.MyApplication
. By giving each log object a name, it can be controlled in thelog4j.properties
file using that same identifier. In this case, you could add the following line to your properties file to log DEBUG messages in your application:log4j.logger.com.acme.webapp.MyApplication=DEBUGThe name you give each Log object can be any arbitrary string. However, the general convention is to use the name of the class that creates the Log object. The log4j FAQ describes an alternate naming system.
Appendix 1 contains a list of Log objects used by Tomcat. One of the more powerful features of log4j is the ability to control hierarchies of Log objects with a single command. For example, the following entry in the
log4j.properties
file would produce DEBUG level output from all of the Tomcat login (or realm) handlers:This would affect JAASMemoryLoginModule, JAASRealm, MemoryRealm and RealmBase.log4j.logger.org.apache.catalina.realm=DEBUGTomcat and Jakarta Velocity
Version 1.4 of the Velocity template engine supports the log4j logger, amongst others. By default, Velocity will try to use the Jakarta Avalon Logkit. To change this behavior, you must either:The latter option is preferable.
- Make sure that no version of the
logkit
jar file exists in your Tomcat configuration; or- Add the following line to your
velocity.properties
file:runtime.log.logsystem.class=org.apache.velocity.runtime.log.SimpleLog4JLogSystemThat just gets Velocity using Log4j. Velocity will still send its log data to a file named
velocity.log
. To get Velocity to use the Tomcat system log instead, add the following directive to yourvelocity.properties
file:This is the name of the Log object to use. Just about any class name would work here, but this is consistent with recommended practice. To change the log level of the Velocity logger to INFO, for example, add this line to yourruntime.log.logsystem.log4j.category=org.apache.velocity.runtime.log.SimpleLog4JLogSystemlog4j.properties
file:log4j.logger.org.apache.velocity.runtime.log.SimpleLog4JLogSystem=INFOWEB-INF Logging
You can override the use of the system log by your applications and set up customized logging to other files or places (using remote sockets). This is done by installing thecommons-logging.jar
andlog4j.jar
files in theWEB-INF/lib
directory of the application in question, along with a customlog4j.properties
file in the correspondingWEB-INF/classes
directory. However, I have not tried this, so you are on your own with this one.Logger Identifiers in Apache Code
To see what classes are creating Log objects in an Apache project, run the following command in the corresponding source code directory:Code that uses the older and deprecated log4j API can be scanned thus:grep 'LogFactory.getLog' `find . -name '*.java'`grep 'Category.getInstance' `find . -name '*.java'`Assuming you know what you are looking for, you can use this information to enable more intense logging in a particular area of an Apache product to pinpoint your problem.
Appendix 1 - Logger Identifiers in Tomcat 5.0.27
The following is a list of logger names in Tomcat 5.0.27:jakarta-tomcat-connectors: org.apache.jk.apr.AprImpl org.apache.jk.common.ChannelJni org.apache.jk.common.ChannelSocket org.apache.jk.common.ChannelUn org.apache.jk.common.HandlerDispatch org.apache.jk.common.HandlerRequest org.apache.jk.common.JkInputStream org.apache.jk.common.JkMX org.apache.jk.common.JniHandler org.apache.jk.common.ModJkMX org.apache.jk.common.ModJkMX org.apache.jk.common.MsgAjp org.apache.jk.common.Shm org.apache.jk.config.WebXml2Jk org.apache.jk.server.JkCoyoteHandler org.apache.jk.server.JkMain org.apache.coyote.http11.Http11Processor org.apache.coyote.http11.Http11Protocol org.apache.naming.ant.JndiProperties org.apache.naming.ant.JndiSet org.apache.naming.modules.cache.ProxyDirContext org.apache.naming.modules.fs.FileDirContext org.apache.naming.modules.fs.fsURLContextFactory org.apache.naming.modules.java.ContextBindings org.apache.naming.util.DomXml org.apache.tomcat.util.compat.Jdk14Compat org.apache.tomcat.util.compat.JdkCompat org.apache.tomcat.util.http.mapper.Mapper org.apache.tomcat.util.net.jsse.JSSE14Support org.apache.tomcat.util.net.jsse.JSSEImplementation org.apache.tomcat.util.net.jsse.JSSESocketFactory org.apache.tomcat.util.net.jsse.JSSESupport org.apache.tomcat.util.net.puretls.PureTLSSocketFactory org.apache.tomcat.util.net.puretls.PureTLSSupport org.apache.tomcat.util.net.PoolTcpEndpoint org.apache.tomcat.util.net.SSLImplementation org.apache.tomcat.util.threads.ThreadPool jakarta-tomcat-catalina: org.apache.catalina.authenticator.AuthenticatorBase org.apache.catalina.authenticator.BasicAuthenticator org.apache.catalina.authenticator.DigestAuthenticator org.apache.catalina.authenticator.FormAuthenticator org.apache.catalina.core.ApplicationContextFacade org.apache.catalina.core.ApplicationDispatcher org.apache.catalina.core.ApplicationFilterConfig org.apache.catalina.core.ContainerBase org.apache.catalina.core.NamingContextListener org.apache.catalina.core.StandardContext org.apache.catalina.core.StandardContextValve org.apache.catalina.core.StandardEngine org.apache.catalina.core.StandardHost org.apache.catalina.core.StandardHostDeployer org.apache.catalina.core.StandardHostValve org.apache.catalina.core.StandardPipeline org.apache.catalina.core.StandardServer org.apache.catalina.core.StandardService org.apache.catalina.core.StandardWrapper org.apache.catalina.core.StandardWrapperValve org.apache.catalina.loader.WebappClassLoader org.apache.catalina.loader.WebappLoader org.apache.catalina.logger.LoggerBase org.apache.catalina.mbeans.GlobalResourcesLifecycleListener org.apache.catalina.mbeans.MBeanUtils org.apache.catalina.mbeans.ServerLifecycleListener org.apache.catalina.realm.JAASMemoryLoginModule org.apache.catalina.realm.JAASRealm org.apache.catalina.realm.MemoryRealm org.apache.catalina.realm.RealmBase org.apache.catalina.security.SecurityConfig org.apache.catalina.security.SecurityUtil org.apache.catalina.session.ManagerBase org.apache.catalina.session.ManagerBase org.apache.catalina.session.PersistentManagerBase org.apache.catalina.startup.Catalina org.apache.catalina.startup.ContextConfig org.apache.catalina.startup.Embedded org.apache.catalina.startup.HostConfig org.apache.catalina.startup.TldConfig org.apache.catalina.util.ExtensionValidator org.apache.catalina.valves.ExtendedAccessLogValve org.apache.catalina.valves.ValveBase org.apache.coyote.tomcat5.CoyoteAdapter org.apache.coyote.tomcat5.CoyoteConnector org.apache.coyote.tomcat5.MapperListener org.apache.naming.NamingContext org.apache.catalina.cluster.deploy.FarmWarDeployer org.apache.catalina.cluster.deploy.WarWatcher org.apache.catalina.cluster.io.XByteBuffer org.apache.catalina.cluster.mcast.McastService org.apache.catalina.cluster.mcast.McastServiceImpl org.apache.catalina.cluster.session.DeltaManager org.apache.catalina.cluster.session.DeltaSession org.apache.catalina.cluster.session.SimpleTcpReplicationManager org.apache.catalina.cluster.tcp.AsyncSocketSender org.apache.catalina.cluster.tcp.Jdk13ReplicationListener org.apache.catalina.cluster.tcp.PooledSocketSender org.apache.catalina.cluster.tcp.ReplicationListener org.apache.catalina.cluster.tcp.ReplicationTransmitter org.apache.catalina.cluster.tcp.ReplicationValve org.apache.catalina.cluster.tcp.SimpleTcpCluster org.apache.catalina.cluster.tcp.SocketSender org.apache.catalina.cluster.tcp.TcpReplicationThread org.apache.catalina.cluster.tcp.WorkerThread org.apache.catalina.cluster.util.SmartQueue jakarta-tomcat-jasper: org.apache.jasper.compiler.Compiler org.apache.jasper.compiler.JspConfig org.apache.jasper.compiler.JspReader org.apache.jasper.compiler.JspRuntimeContext org.apache.jasper.compiler.TagLibraryInfoImpl org.apache.jasper.compiler.TldLocationsCache org.apache.jasper.runtime.JspFactoryImpl org.apache.jasper.runtime.PageContextImpl org.apache.jasper.security.SecurityClassLoad org.apache.jasper.servlet.JspServlet org.apache.jasper.servlet.JspServletWrapper org.apache.jasper.xmlparser.ParserUtils org.apache.jasper.EmbeddedServletOptions org.apache.jasper.JspCAppendix 2 - Logger Identifiers in Jakarta Struts 1.1
The following is a list of logger names in Jakarta Struts 1.1:example: org.apache.struts.webapp.example.memory.MemoryDatabasePlugIn org.apache.struts.webapp.example.memory.MemoryUserDatabase org.apache.struts.webapp.example.EditRegistrationAction org.apache.struts.webapp.example.EditSubscriptionAction org.apache.struts.webapp.example.LogoffAction org.apache.struts.webapp.example.LogonAction org.apache.struts.webapp.example.SaveRegistrationAction org.apache.struts.webapp.example.SaveSubscriptionAction share: org.apache.struts.action.ActionServlet org.apache.struts.action.RequestProcessor org.apache.struts.actions.DispatchAction org.apache.struts.actions.SwitchAction org.apache.struts.config.ModuleConfigFactory org.apache.struts.taglib.html.BaseHandlerTag org.apache.struts.taglib.html.MessagesTag org.apache.struts.taglib.tiles.DefinitionTag org.apache.struts.taglib.tiles.InsertTag org.apache.struts.tiles.actions.DefinitionDispatcherAction org.apache.struts.tiles.xmlDefinition.I18nFactorySet org.apache.struts.tiles.xmlDefinition.XmlDefinition org.apache.struts.tiles.ComponentDefinition org.apache.struts.tiles.DefinitionsUtil org.apache.struts.tiles.TilesPlugin org.apache.struts.tiles.TilesRequestProcessor org.apache.struts.tiles.TilesServlet org.apache.struts.tiles.TilesUtil org.apache.struts.tiles.TilesUtilImpl org.apache.struts.upload.CommonsMultipartRequestHandler org.apache.struts.upload.DiskMultipartRequestHandler org.apache.struts.util.MessageResources org.apache.struts.util.MessageResourcesFactory org.apache.struts.util.PropertyMessageResources org.apache.struts.util.RequestUtils org.apache.struts.validator.DynaValidatorActionForm org.apache.struts.validator.DynaValidatorForm org.apache.struts.validator.FieldChecks org.apache.struts.validator.ValidatorActionForm org.apache.struts.validator.ValidatorForm org.apache.struts.validator.ValidatorPlugIn test: test.org.apache.struts.mock.MockServletContext tiles-documentation: tiles-documentation.org.apache.struts.webapp.tiles.rssChannel.Channels