Intelligent microservice metrics with Spring Boot and Statsd

I’ve often heard the phrase “you can’t improve what you can’t measure.” When developing high-performance systems, this is especially true. Such systems typically have strict non functional requirements, such as requests/second and response time. When we collect metrics about the various layers of a system, we can then take action to improve the performance of wayward components.

The technology stack introduced in the article includes the following:

This article assumes knowledge of how to create restful services with spring boot and gradle. It will give examples on how to start collecting various application metrics and send those to statsd. It does not talk about how to consume metrics with influxdb, graphite, ganglia, etc. – this is left as an exercise for the reader.

Dropwizard metrics defines a rich collection of metric types:

  • Gauges – record raw values
  • Counters – record event counts
  • Timers – record execution time metrics
  • Meters – record execution rates
  • Histograms – record value distributions

See https://dropwizard.github.io/metrics/3.1.0/manual/core/ for more information about each of these types.

To start, let’s get our application setup to record metrics, and install statsd.

Gradle Setup

Add the readytalk bintray repository to your build.grade.

repositories {
  mavenRepo(url: 'http://dl.bintray.com/readytalk/maven')
}

Now add dropwizard-metrics, metrics-spring, and metrics-statsd to your dependencies.

compile 'com.readytalk:metrics3-statsd:4.1.0'
compile ('com.ryantenney.metrics:metrics-spring:3.0.4') {
 exclude group: 'com.codahale.metrics'
 exclude group: 'org.springframework'
}
compile 'io.dropwizard.metrics:metrics-core:3.1.1'
compile 'io.dropwizard.metrics:metrics-annotation:3.1.1'
compile 'io.dropwizard.metrics:metrics-healthchecks:3.1.1'
compile 'org.springframework.boot:spring-boot-starter-web:1.2.3.RELEASE'
compile 'org.springframework:spring-aspects:4.1.6.RELEASE'
compile 'org.springframework:spring-context-support:4.1.6.RELEASE'

Application Configuration Setup

Add the following to an @Configuration or @SpringBootApplication annotated class, for example:

@SpringBootApplication
@EnableMetrics(proxyTargetClass = true)
class BlogApplication extends MetricsConfigurerAdapter {
 
    @Bean
    MetricsConfigurerAdapter metricsConfigurerAdapter() {
        new BaseMetricsConfigurerAdapter()
    }
 
    static void main(String[] args) {
        SpringApplication.run BlogApplication, args
    }
}

Install and Configure statsd

See https://github.com/etsy/statsd#installation-and-configuration for installation and configuration instructions. Don’t forget to change the port to 8125. Here is my example config file:

{
debug: true,
port: 8125,
backends: [ "./backends/console" ]
}

Now run statsd.

node stats.js localConfig.js

Add controller timed annotation

Now, let’s say I want to record timing statistics for a rest endpoint. Add something like this:

@RestController
@RequestMapping(value = '/hello')
class BlogMetricsController {
 
  @Timed(absolute = true, name = 'sayhello')
  @RequestMapping(value = '/{name}', method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
  @ResponseStatus(HttpStatus.OK)
  String sayHello(@PathVariable(value = 'name') String name) {
    "Hello $name"
  }
 
}

Run the application and  you can view statistics in the console.

gradle bootRun

You can hit the url and see the statistics change in the application log. You can also see the same metrics in the statsd console output.

Other Use Cases

One other interesting way to record metrics on arbitrary code blocks is to use Java8 lambdas or Groovy closures.

Java8

@Component
public class MetricWriterJava {
 
    @Autowired
    private MetricRegistry metricRegistry;
 
    public <T> T time(String name, Supplier<T> s) {
        Timer timer = metricRegistry.timer(name);
        final Timer.Context context = timer.time();
        T result = null;
        try {
            result = s.get();
        }
        finally {
            context.stop();
        }
        return result;
    }
}

Groovy

@Component
class MetricWriterGroovy {
 
    @Autowired
    MetricRegistry metricRegistry
 
    def time(String name, Closure c) {
        Timer timer = metricRegistry.timer(name)
        final Timer.Context context = timer.time()
        def result = null
        try {
            result = c.call()
        }
        finally {
            context.stop();
        }
        result
    }
}

Then you can create metrics like this and see them immediately in the output.

//random java metric
int t = metricWriterJava.time('java.metric', {
    (1..1000).each { sleep(1) }
    42
})
 
//random groovy metric
int x = metricWriterGroovy.time('groovy.metric', {
    (1..1000).each { sleep(1) }
    99
})

The examples above can be applied to all metrics types. The links at the top of the article provide excellent in depth documentation on how to configure and use the individual components of this stack.

Full source code available here

Happy metrics!

About the Author

Object Partners profile.

One thought on “Intelligent microservice metrics with Spring Boot and Statsd

Leave a Reply

Your email address will not be published.

Related Blog Posts
Natively Compiled Java on Google App Engine
Google App Engine is a platform-as-a-service product that is marketed as a way to get your applications into the cloud without necessarily knowing all of the infrastructure bits and pieces to do so. Google App […]
Building Better Data Visualization Experiences: Part 2 of 2
If you don't have a Ph.D. in data science, the raw data might be difficult to comprehend. This is where data visualization comes in.
Unleashing Feature Flags onto Kafka Consumers
Feature flags are a tool to strategically enable or disable functionality at runtime. They are often used to drive different user experiences but can also be useful in real-time data systems. In this post, we’ll […]
A security model for developers
Software security is more important than ever, but developing secure applications is more confusing than ever. TLS, mTLS, RBAC, SAML, OAUTH, OWASP, GDPR, SASL, RSA, JWT, cookie, attack vector, DDoS, firewall, VPN, security groups, exploit, […]