Monday, 25 November 2013

Logging is an essential cross cutting aspect in (Java) applications. A widely used logging library is log4j (Homepage), another project of the Apache Group. To abstract the logging implementation from your application it is common use to put SLF4j (Homepage) as logging facade in front of the implementation (here log4j).

Installation

To use log4j and slf4j in your Maven-project you need this dependencies:
<dependency>
  <groupId>org.slf4j</groupId>
  <artifactId>slf4j-api</artifactId>
  <version>1.6.4</version>
</dependency>
<dependency>
  <groupId>org.slf4j</groupId>
  <artifactId>slf4j-log4j12</artifactId>
  <version>1.6.4</version>
</dependency>
<dependency>
  <groupId>log4j</groupId>
  <artifactId>log4j</artifactId>
  <version>1.2.17</version>
</dependency>

Configuration

The logging configuration is done for the underlying implementation. For log4j the config file "log4j.xml" (or log4j.properties) has to be in the root of the classpath. If not, specify the path to the config file through the system property "log4j.configuration" (this is the preferred way to specify the default initialization file):
-Dlog4j.configuration=path/to/your/config.xml
The configuration manual is here.

Output Format

Output format is defined using PatternLayout configuration.
Example:
<layout class="org.apache.log4j.PatternLayout">
  <param name="ConversionPattern" value="[%d{ISO8601} %-5p] %-25c{1} (%-8t) > %m%n"/>
</layout>
Description:
Pattern Description
%d{ISO8601} timestamp in format "yyyy-MM-dd HH:mm:ss,SSS", e.g. "1999-11-27 15:49:37,459".
%-5p Loglevel (left aligned, min. 5 characters long)
%-25c{1} category of the logging-event (left aligned. min. 25 characters long, only last classpath element (class name / last package) printed in full length, parent packages shortend to one character)
%-8t thread-name (left aligned, min. 8 characters long)
%m%n logging message and line break
Example output:
[2013-09-18 08:36:48,802 INFO ] UserServiceImpl            (http-8080-12) > try to login user 'heino'

Appenders (targets for the output)

File

Logging usually goes to a file on the local filesystem. Example configuration of a FileAppender (%X{...} is explained in detail in this article):
<appender name="myFileAppender" class="org.apache.log4j.RollingFileAppender">
  <param name="File" value="/var/log/webapp/my-webapp.log" />
  <param name="append" value="false" />
  <param name="MaxFileSize" value="5MB" />
  <param name="MaxBackupIndex" value="20" />
  <layout class="org.apache.log4j.PatternLayout">
    <param name="ConversionPattern" value="[%d{ISO8601} %-5p] [%X{username} / %.5X{sessionID}...] %-25c{1} (%-8t) > %m%n" />
  </layout>
</appender>

Email

For production it is useful to get Exceptions immediately reported to the developers. This can be achieved by using the SMTPAppender.
<appender name="mail-errors" class="org.apache.log4j.net.SMTPAppender">
  <param name="SMTPHost" value="..." />
  <param name="From" value="noreply@..." />
  <param name="To" value="email1@...,email2@..." />
  <param name="Subject" value="MyWebapp Exception in production" />
  <param name="BufferSize" value="1" />
  <param name="threshold" value="error" />
  <layout class="org.apache.log4j.PatternLayout">
    <param name="ConversionPattern" value="%d %-5p [%X{username} / %.5X{sessionID}...] [%t] %l > %m%n" />
  </layout>
</appender>

Usage

Logging can be implemented explicitely in the code or using AOP (see this article about Spring AOP logging). Manual logging is done this way:
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
 
public class XYZ {
  private static final Logger logger = LoggerFactory.getLogger(XYZ.class);
  ...
  public void someMethod(String arg) {
    logger.info("someMethod called with argument {}", arg);
  }
}
Note: There are discussions about the member "logger" if it should be in uppercase (because it is static) or not. After reading some discussions http://stackoverflow.com/questions/3842823/should-logger-be-private-static-or-not and http://stackoverflow.com/questions/1417190/should-a-static-final-logger-be-declared-in-upper-case I changed my previous behavior (using uppercase "LOGGER") and started to use lowercase ("logger")... What are your best practices?

0 comments:

Post a Comment