Enterprise Java

Improve your Logging in your Java EE Application with tinylog 1.1

tinylog is a lightweight logging framework for Java. In opposite to Apache Log4j and Logback, tinylog consists of a single JAR file of only 80KB without any dependencies and has a static logger class. This means that you haven’t to use any boilerplate code for creating a logger instance for each class.

public static void main(String[] args) {
   Logger.info("Hello World!"); // Logging methods are static
}

Logging Context

One of the new features of tinylog 1.1 is the support of logging context. This feature is known as mapped logging context (MDC) from other logging frameworks and allows thread-based enrichment of log entries with additional data. For example, you can set the user IP once for a thread and tinylog will include this IP in all log entries.

public class HelloWorld extends HttpServlet {

   private static final long serialVersionUID = 1L;

   protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
      LoggingContext.put("ip", request.getRemoteAddr()); // Set IP for this and all client threads

      Logger.info("Handle request");
      response.getWriter().append("<h1>Hello World</h1><p>");
      Logger.info("Done request");
   }

   protected void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException {
      doGet(request, response);
   }

}

If you use a load balancer or a proxy, you will get the real user IP by calling request.getHeader("X-FORWARDED-FOR").The logging context has to be included in the logging format pattern. tinylog can be configured via a properties file, system properties or the Fluent API. You can use your preferred way to set the logging format pattern for example to “{date} [{context: ip}] {level}: {message}” for getting the following output:

2016-05-15 11:40:31 [89.12.191.39] INFO: Handle request
2016-05-15 11:40:31 [89.12.191.39] INFO: Done request

Such logging context is helpful for reconstructing: which log entry belongs to which request. If you have a log-in system, the user name is another good candidate for logging context. It is possible as well to set multiple values. If you use a thread pool, you shouldn’t forget to clear the logging context while returning a thread to the thread pool.

Writers

tinylog supports multiple writers for outputting log entries. For Java EE applications, the RollingFileWriter and the JdbcWriter are the most popular writers.

The RollingFileWriter can write log entries to a file. In opposite to the basic FileWriter, a new log file can be started after defined events. Such events can be the start of the application, a maximum file size or a date. A defined number of old log files can be kept as backups.

Example for configuring a RollingFileWriter via a properties file:

tinylog.writer = rollingfile
tinylog.writer.filename = log.txt
tinylog.writer.backups = 10
tinylog.writer.label = count
tinylog.writer.policies = startup, daily

In this example, the RollingFileWriter starts a new log file at the application start and after each day runtime. The ten newest log files will be kept as backups and be numbered consecutively.
The JdbcWriter can write log entries to a SQL database. This is a way to centralize logs if you have multiple servers.
Example for configuring a JdbcWriter via a properties file:

tinylog.writer = jdbc
tinylog.writer.url = jdbc:mysql://localhost/demo
tinylog.writer.table = logs
tinylog.writer.columns = date, ip, level, message
tinylog.writer.values = DATE, CONTEXT, LEVEL, MESSAGE
tinylog.writer.username = demo
tinylog.writer.password = demo

In modern standard Java environments and the most web application servers, the JVM can find a database driver via services. Unfortunately, a standalone Apache Tomcat requires a manual loading of the database driver. This can be done by a ServletContextListener.

@WebListener
public class LifeCycleListener implements ServletContextListener {

   @Override
   public void contextInitialized(ServletContextEvent event) {
      try {
         new com.mysql.jdbc.Driver(); // Your database driver
      } catch (SQLException e) {
         Logger.error(e);
      }
    }

    @Override
    public void contextDestroyed(ServletContextEvent event) {}

}

tinylog 1.2 will support Java EE data sources. You have to define a database connection just once for your application and you can refer to the data source in your tinylog configuration. Another new feature is the reestablishing of a database connection in case of connection losses as soon as the database is up again.

Writing Thread

Out of the box, tinylog writes all log entries synchronously. tinylog’s writing thread can be used to execute writers in a separate thread to avoid blocking by slow IO operations. If activated, the writing thread has to be shutdown together with your application. This can be done my observing a main thread or calling the shutdown method. As there are no reliable long-living threads in Java EE applications, the proposed way is to use a ServletContextListener to shutdown the writing thread.

@WebListener
public class LifeCycleListener implements ServletContextListener {

   @Override
   public void contextInitialized(ServletContextEvent event) {}

    @Override
    public void contextDestroyed(ServletContextEvent event) {
	   Configurator.shutdownWritingThread(false);
	}

}

Source Code

The whole source code of the Java EE example application is available on GitHub. Further information about tinylog can be found on the tinylog website, including a complete manual.

Martin Winandy

Martin is a Java developer for Eclipse RCP and Jave EE applications. He supports multinational vehicle manufactures and technical inspection associations in developing custom product data management solutions. Independent of his job, Martin is actively involved in open source projects and is the initiator of tinylog.
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Inline Feedbacks
View all comments
Back to top button