Using the Spring Cloud Sleuth trace ID


Here is a way to interact with Spring Cloud Sleuth in an API service that works with an asynchronous workflow.


On a recent project we implemented an API service using Spring Boot with two operations:

  1. initiate a new, asynchronous workflow
  2. report on the status of an existing workflow

Each workflow is identified by a unique ID that is generated by the service on the first call and returned to the consumer. The consumer then uses that ID in subsequent status requests to identify the workflow.

Spring Cloud Sleuth

The service is one of a mesh of microservices and we added Spring Cloud Sleuth to provide tracing across microservice calls. In Sleuth, a Span is a basic unit of work, and spans are linked together into a Trace for a single logical transaction. The Sleuth Reference provides much more detail, including this useful diagram:

Spring Cloud Sleuth: Span and Trace visualisations
Spring Cloud Sleuth: Span and Trace visualisations

Use the Sleuth trace ID for each workflow

Instead of generating a separate ID (such as a UUID) we decided to take the trace ID from Sleuth. Sleuth generates a random long integer as a trace ID at the beginning of the request and passes that as part of requests to other services.

Part of our rationale for using the trace ID is to reduce log message clutter. When Sleuth is included, the IDs are inserted into the Spring logs via the SLF4J MDC. Here is a simple Spring Boot log message with information added by Sleuth:

2017-07-14 13:32:59.094  INFO [api-service,92e9013d25cca084,92e9013d25cca084,false] [] 25453 --- [nio-8080-exec-1] c.e.s.WorkflowController : Received request
  • api-service is the service name
  • 92e9013d25cca084 is the trace ID; here it is also the span ID because this is the first span in the trace
  • false means that the log is not exportable to Zipkin

Getting the Sleuth trace ID

Getting the trace ID turned out to be very simple. We created a Spring service called Breadcrumb to return the formatted trace ID.

public class Breadcrumb {

  private Tracer tracer;

  public String breadcrumbId() {
    return tracer.getCurrentSpan().traceIdString();

Span#traceIdString() returns the trace ID in the same hexadecimal format used in the log messages.

The controller that handles the request to start the workflow injects this service and calls breadcrumb.getBreadcrumb() to get the current trace ID string.

Inserting the Sleuth trace ID

When a consumer requests status of a workflow they provide the breadcrumb ID to use, e.g.:

GET /v1/workflow/92e9013d25cca084

We want to set that value as the Sleuth trace ID.

Filter that injects the trace ID

The solution we chose is to create a Spring web filter that addes a Sleuth span as an attribute of the HTTP request so the Sleuth TraceFilter behaves as if the request is part of an existing Sleuth trace. Our filter:

  • is in the filter chain before TraceFilter
  • reads the breadcrumb ID from the request
  • constructs an appropriate Span object
  • adds the span as an attribute of the request with the correct key

When TraceFilter executes it finds the span in the request attribute and uses it as if the service had been called by another one in the same trace.

Here is the filter code, abridged for clarity, with explanatory comments:

// Load this filter before TraceFilter
@Order(TraceFilter.ORDER - 1)
public class InjectTraceFilter extends GenericFilterBean {

    // Only modify requests that match this pattern
    private static final Pattern REQUEST_PATTERN = Pattern.compile("^/v1/workflow/(?<crumbId>[0-9a-f]+)$");
    // Key of the request attribute that TraceFilter searches for
    private static final String TRACE_REQUEST_ATTR = TraceFilter.class.getName() + ".TRACE";
    // Used to construct the span name
    private static final String SPAN_NAME_BASE = "http:/v1/workflow/";

    private final Random random = new Random(System.currentTimeMillis());

    public void doFilter(final ServletRequest request, final ServletResponse response,
                         final FilterChain chain) throws IOException, ServletException {
        final HttpServletRequest httpRequest = (HttpServletRequest) request;
        final String breadcrumbId = extractBreadcrumbId(httpRequest);
        if (breadcrumbId != null) {
            // Set up a span with this breadcrumb ID as the trace ID
            httpRequest.setAttribute(TRACE_REQUEST_ATTR, spanForId(breadcrumbId));
            chain.doFilter(httpRequest, response);
        } else {
            chain.doFilter(request, response);

     * Returns the breadcrumb ID if a GET request matches the pattern, otherwise null. 
    private String extractBreadcrumbId(final HttpServletRequest httpRequest) {
        if ("GET".equals(httpRequest.getMethod())) {
            final Matcher matcher = REQUEST_PATTERN.matcher(httpRequest.getRequestURI());
            if (matcher.matches()) {
        return null;

     * Constructs a span for the specified trace ID with a random span ID. 
    private Span spanForId(final String traceId) {
        return Span.builder()
                .name(SPAN_NAME_BASE + traceId)

Configuration to use the filter

The filter is configured in the standard way:

public class InjectTraceFilterAutoConfigure {

    public InjectTraceFilter injectTraceFilter() {
        return new InjectTraceFilter();


Showing tags on posts


After adding a Categories page I wanted to add tag-handling to the blog. I wanted to display the tags assigned to each post under the title.

Using the same principles as for categories and adapting some CSS from Codinfox, I have achieved that. Each tag name is a link to the relevant section of the Tags page.

Like categories, tags are specified for a post in the front matter, as for this post:

layout: post
title: Showing tags on posts
categories: tech
tags: blog

Adding a categories page to this blog


I succeeded in adding a Categories page to this blog.

Jekyll supports specification of variables category, categories and tags in the front matter of blog posts but it is left as an Exercise for the Reader™ to do anything with them. The Lanyon theme does not itself include page with category or tag lists (but of course is infinitely expandable).

So I created a contents page by adapting this technique with my own amateur CSS applied. The page is contents.html in the root directory of the site and has front matter:

layout: page
title: Categories

The Lanyon sidebar automatically creates links to any pages with layout: page in the front matter so the Categories page is easily found.

Welcome (back) to my relative ignorance


I have resuscitated a blog after about 10 years’ absence. As in that previous life, it is called Relatively Ignorant and contains bits and pieces of things I have observed at work and elsewhere.

This incarnation is hosted at GitHub and is produced using Jekyll with the Lanyon theme. Thanks to my ThoughtWorks colleague Matt Newman for providing a model of the simple kind of blog I wanted.

It also uses HTTPS exclusively so I feel all grown up now.

Gradle build file organisation and reuse


Some ideas on how to organise and reuse Gradle build files in a multi-project build.


Our project was to create a set of related microservices in Java using Spring Boot, built as a set of Gradle projects all under a single root project.

We wanted to reuse Gradle build scripts as much as possible and reduce the amount of copy-and-paste between service projects.

General layout

  +- build.gradle
  +- settings.gradle
  +- gradle/
  |    +- code-standards.gradle
  |    +- idea.gradle
  |    +- package.gradle
  |    +- spring-actuator-info.gradle
  |    +- spring-boot.gradle
  |    +- spring-rest-docs.gradle
  +-- microservice-a/
  |     +- build.gradle
  |     +-
  |     +- src/
  +-- microservice-b/
        +- build.gradle
        +- src/

Gradle scripts

Project root

The project root contains settings.gradle with: = 'api-microservices'

include 'microservice-a', 'microservice-b'

There can only be one settings.gradle file and it must be in the root directory.

The root build.gradle contains information in common with all projects:

// Common build versions for Spring Boot, Cloud and Prometheus, and Boot plugin.
buildscript {
    ext {
        springBootVersion = '1.5.4.RELEASE'
        springCloudVersion = 'Dalston.SR1'
        springMetricsVersion = '0.5.1.RELEASE'
        prometheusVersion = '0.0.23'
    dependencies {

// External plugins cannot be declared in an external build script but will be available to
// all child projects.
plugins {
    id 'org.asciidoctor.convert' version '1.5.3'
    // Plugin to generate on the classpath that will be included
    // in the Actuator info response.
    id 'com.gorylenko.gradle-git-properties' version '1.4.17'

group 'com.example'

// These things are applied to all projects.
allprojects {

    apply plugin: 'java'
    sourceCompatibility = 1.8

    repositories {
        maven {
            // Search local repo first.
            url ''

If you don’t want all your services to use the same version of Spring Boot (etc.) you will need a different configuration.

Service projects

The build.gradle for each service project is now simplified to start with:

apply from: '../gradle/spring-boot.gradle'
apply from: '../gradle/idea.gradle'
apply from: '../gradle/code-standards.gradle'
apply from: '../gradle/spring-rest-docs.gradle'
apply from: '../gradle/spring-actuator-info.gradle'
apply from: '../gradle/package.gradle'

Other, project-specific declarations follow. For example, to use Redis:

dependencies {

Each project contains a file containing the current version of the service. It is separate from build.gradle so it can be read and written by the Gradle Release Plugin.

Common, reusable scripts

Here is a brief description of the reusable scripts that we created.

File Description
spring-boot.gradle Apply Spring Boot plugin and specify Spring and other dependencies for all projects.
idea.gradle Apply and configure the IntelliJ IDEA plugin.
code-standards.gradle Apply and configure Checkstyle and Jacoco plugins.
spring-rest-docs.gradle Apply and configure the AsciiDoctor plugin; also include the generated doc in the assembled JAR.
spring-actuator-info.gradle Apply and configure the Gradle Git Properties plugin; Specify that Spring Boot generates that will returned by the Actuator info endpoint.
package.gradle Apply and configure the Gradle Linux Packaging plugin to package the service as an RPM.


We also used the Gradle Release Plugin but I was not able (in the time available) to get it to work from an external script using apply from. This meant that each service build script contained the same big block of code (not shown here).

Perhaps I will solve that one in the future.