Gradle – Introducing Logging

Introduction

I was reading about Aspect Oriented programming lately and Logging came up as the cross-cutting concern example in almost all the books/blogs etc I looked at and logging is certainly a prime candidate for AOP application. But then I realised that logging is itself a very important aspect of software development especially when something goes wrong in production and at that time you wish you had logging in place. So, I wanted to introduce logging to my own fun project which is not going to production any time soon but who knows 😛

One thing to note here is that java itself provides the default support for logging – java.util.logging but logack with its wrapper slf4j is the primary choice due to its flexibility and performance. And this is what I am trying to implement here.

Basic Setup

build.gradle

Add the slf4j and logback dependencies in your build file:

Line#4 alone is enough actually as it will transitively pull in the logback-core and slf4j-api dependencies.

For now, I am not providing any configuration file so logback will automatically use its default config and logging would work.

This is how to create a Logger by using the slf4j LoggerFactory class:

Next, simply use the typical logging APIs corresponding to the log level you’re looking for:


At this point you can directly jump to Execution section and verify if it works or not.

Advanced Setup

build.gradle

I intended to keep my logback config file as well as the log file in resources folder, so I added the resources folder to my source sets (see more here) as I am not following gradle’s default directory structure.

Note that, this is important because I want to build/run my project outside of my IDE too, otherwise you should be able to just add resources folder to classpath using your IDE and gradle plugin should be able to find the config file.

logback.xml

To create a configuration for Logback, you can use XML as well as Groovy. There are three valid standard file names you can choose from:

  • logback-test.xml
  • logback.groovy
  • logback.xml

As long as you choose the correct name above and make sure that your config file is in classpath, Logback will automatically pick the configuration. If due to some reason Logback can not use the config file, the default configuration will kick-in and logs will be visible on console.

Here is the config file I am using:

Here I am writing the logs in the resources/hellogradle.log for quick access but it is not the ideal place for a log file. With time the log file will become so bulky that it will kill my IDE and slow my application to death.

A quick fix to this is to set append property to false <append>false</append> and it will write new logs on every run of the app and clear the old logs. This way the log file’s size will be reasonable.

This setting and log file would be a very bad idea for production environment as you will lose critical logs this way. So, a good idea is to keep your log file at some shared location where support team could also check them for a basic investigation and most importantly use a RollingFileAppender instead of simple STDOUT and FILE appenders.

Appenders

  • ConsoleAppender – writes messages to the system console
  • FileAppender – appends messages to a file
  • RollingFileAppender – extends the FileAppender with the ability to roll over log files
  • SMTPAppender – sends log messages in an email, by default only for ERROR messages
  • DBAppender – adds log events to a database
  • SiftingAppender – separates logs based on a runtime attribute
The RollingFileAppender

Logging to file is naturally the way to go in any kind of production scenario where you need persistent logs. However, if all the logs are kept in a single file, this runs the risk of becoming too large to open the file let alone reading efficiently. That’s when rolling files come in handy.

To address this well-known limitation, Logback provides the RollingFileAppender, which rolls over the log file when certain conditions are met. The appender has two components:

  • RollingPolicy – which determines how the rollover is performed
  • TrigerringPolicy – which determines when the file is rolled over

To better understand these policies, let’s create an appender which makes use of a TimeBasedRollingPolicy and a SizeTriggeringPolicy:

The TimeBasedRollingPolicy implements both a RollingPolicy and a TriggeringPolicy.

The example above configures the fileNamePattern attribute based on the day – which means the name of each file contains the current date, and also that the rollover will happen daily.

Notice how we’re limiting the log data here – maxHistory is set to a value of 30, alongside a totalSizeCap of 1GB – which means that the archived logs will be kept for the past 30 days, up to a maximum size of 1GB.

Finally, the SizeBasedTriggeringPolicy defined configures the rollover of the file whenever it reaches 2 MB.

Execution

IDE
  1. Right click the project → Gradle → Refresh Gradle Project.
  2. Right click Application.java and run as Java Application.
Build

 
Source Code

Basic logging without logback configuration.
Logging with logback config to support logging to file.