Embed info in the Tomcat logs using Logback

Rationale

Let’s supose you are using CI/CD and you want to embed the build number in your logs. This is a good practice because, while checking the logs, that would allow you to find out what version was having that problems. However, we would like that to happen automagically from our CI/CD.

Let’s suppose we’re running Jenkins. If you’re using other CI/CD solutions like TravisCI or CircleCI your milleage will certainly vary.

The solution

To make this easier, we would like to start from maven. The idea would be to call maven with an additional variable -Dbuild.number=${BUILD_NUMBER}. What happens if that variable is not being provided? Then maven will automatically use a default value (maybe 1?).

After that, maven should ‘save’ that value somewhere for logback to pick up. How do we do that? We can ask maven to patch a placeholder in the application.properties file.

Finally, because we’re using Spring Boot you would need to pull in spring-boot-starter-logging. It is included by default in spring-boot-starter so probably you are good to go! We can then use the ${build.number} variable inside the logback xml configuration and log the build number.

Using the BUILD_NUMBER Jenkins variable

The ${BUILD_NUMBER} variable is already available when using Jenkins. Nothing to do here but call maven passing that value:

mvn -Dbuild.number=${BUILD_NUMBER} 

Inside the parent pom file, under the properties tag we need to add something like this:

<build.number>1</build.number>

Patching the application properties Spring Boot file

You need to use the filtering maven plugin and instruct it to patch files in a given directory. For example, in my case my various (depending on the environment) application-$env.yml files are under src/main/resources:

   <resource>
      <directory>src/main/resources</directory>
      <filtering>true</filtering>
   </resource>

The relevant stuff you’d need to add to your application.yml file to have the build number there are:

build.number: @build.number@

Maven will replace the @build.number with whatever value you passed to maven (or the default value).

Picking up the build number with Logback

Finally we need to pick up the build number value in the application.yml file. Because Logback loads the logback.xml before Spring Boot’s Application context is there, you need to rename your logback.xml to logback-spring.xml. The later one is being processed after Spring Boot magic happens, so then the application.yml is being picked and the build.number is available to Logback to use. According to the documentation [1]:

When possible, we recommend that you use the -spring variants for your logging configuration (for example, logback-spring.xml rather than logback.xml). If you use standard configuration locations, Spring cannot completely control log initialization.

Remember, you need to use spring-boot-starter-logging, if you are using spring-boot-starter then you already have it in place.

The only thing you need is to use the build number variable. In my case:

<Pattern>%date{yyyy-MM-dd'T'HH:mm:ss.SSSZ} [%thread] [build.number:${build.number}] [%X{user}] %-5level %marker       %logger{36} - %msg %throwable{full}%n</Pattern>

This makes it really easy to parse the message and filter by build number.


[1] https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-logging.html