Best Practice for Logging
Use a logging framework
Using a logging framework is always recommended and shall be preferred over
System.err.println
or
System.out.println
! Logging output and layouting shall be configurable to the end user's needs.
If you are not sure why you should use logging, take a look at the article
Logging 101.
Use slf4j as logging API
When using a logging framework there shall exist only be one single configuration point for logging, without loosing the flexibility of exchange the actual logging API to be used when running a 52°North application (either a webservice or when using an API within a custom application, like the
OxFramework).
SLF4J is more flexible and performant than commons-logging. Use it!
And switching is easy - there is a
migration tool and also support for
external legacy APIs that your application depends on.
slf4j API provides a logging interface which enables late binding of message formatting. This actually means that log messages are formatted
after the API has determined if the current log level is configured to be active. For example, if configuration is configured to INFO log level, the following String message would not be formatted (String formatting, or even concatenation with the
+
-operator really slows down the application):
LOGGER.debug("This message will not be {}", "formatted");
Tip: If you are using Java 1.5, use slf4j-api version 1.7.x. The Logger interface offers message formatting via Java's
varargs mechanism instead of
Object[]
.
Bindings
You can use several log APIs along with SLF4J. Just look for an appropriate SLF4J bridge. However,
logback is the native SLF4J implementation and comes with great
set of log appenders, is easy and flexible to configure. And it is
more performant than log4j, so you should switch if you care about your software.
Binding logging APIs like log4j is just a matter of classpath setting. Ensure you have on your classpath:
- slf4j-api-x.y.z.jar (note that you can use any version of slf4j, as long as the version of slf4j-api.jar and its binding match)
- the jar of the chosen logging framework (like
log4j-1.2.16.jar
)
- the jar providing the binding between slf4j and chosen logging framework (e.g.
slf4j-logj12.jar
)
Tip: SLF4J's native log implemenation logback provides a
log4j.properties converter.
Note: Separating log settings in
logback-test.xml
and
logback.xml
files might cause some IDEs (at least eclipse) to use the first
logback-test.xml
found on classpath rather than using
logback.xml
at application start. This may confuse log configuration as tests often differ in configuration (do not log in files, and may have different log levels). To overcome this issue set the
-Dlogback.configurationFile=/path/to/file
parameter at startup to ensure the application picks up the right log settings file. See
the logback jira for a more detailed discussion on this. (telling eclipse to just ignore all
logback-text.xml
files is just a matter of configuration:
https://github.com/52North/SensorWebClient/issues/22#issuecomment-20515421)
logback examples
Adding slf4j and logback to Maven pom.xml file
<properties>
<slf4j.version>1.6.4</slf4j.version>
<logback.version>1.0.1</logback.version>
</properties>
<dependencies>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${slf4j.version}</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>${logback.version}</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
<version>${logback.version}</version>
</dependency>
</dependencies>
If you want to use the Maven properties as shown below, add the following properties (containing example values):
<config.logger.fileappender.filepath>D:/logs</config.logger.fileappender.filepath>
<config.logger.level>DEBUG</config.logger.level>
Configuration of File and StdOut appender
This example comes with properties which can be filtered during a Maven build. However, besides Maven properties, you can define your own properties within the file itself (see the
${logFile}
parameter).
The FILE appender is configured so that it keeps log files for 30 days in a separate directories. This leaves a clean logs directory.
Save the following content in a file
../src/main/resources/logback.xml
.
<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true">
<!-- refer to http://logback.qos.ch/manual/appenders.html -->
<property name="logFile"
value="${config.logger.fileappender.filepath}/${pom.artifactId}-${project.version}" />
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${logFile}.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${logFile}/%d{yyyy-MM-dd}.log</fileNamePattern>
<!-- keep 30 days' worth of history -->
<maxHistory>30</maxHistory>
</rollingPolicy>
<encoder>
<pattern>
%date %level [%thread] [%file:%line] %msg%n
</pattern>
</encoder>
</appender>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>
%d{HH:mm:ss.SSS} [%thread] %-5level %logger{0} - %msg%n
</pattern>
</encoder>
</appender>
<logger name="org.n52" level="${config.logger.level}" />
<root level="WARN">
<appender-ref ref="FILE" />
<appender-ref ref="STDOUT" />
</root>
</configuration>