DataDog setup with Spring Boot (Kotlin)

Ondrej Kvasnovsky
2 min readApr 2, 2024

--

The following article shows and explains how to setup DataDog for custom metrics in Spring Boot, using Gradle and Kotlin.

Dependencies

First we need to add dependencies to our Gradle build file:

implementation("org.springframework.boot:spring-boot-starter-actuator") 
implementation("io.micrometer:micrometer-registry-statsd:latest.release")
implementation("org.springframework:spring-aspects")

Why we need each dependency:

Spring Boot Actuator provides dependency management and auto-configuration for Micrometer, which is an application metrics facade

Micrometer dependency to get the metrics to DataDog through StatsD

Spring Aspects to enable @Timed, @Counted, @MeterTag and @NewSpan annotations

Local setup (for macOS)

  1. Open https://<yourdomain>.datadoghq.com/account/settings/agent/latest?platform=macos
  2. Create API key if one is not created for your product
  3. Follow instructions to install the DataDog agent locally.

It is useful to have it running locally when you are setting it up, and also when developing new application (custom) metrics

Configuration

Everything is configured by automatically by Spring Boot, we only need to do few things to make life easier.

Enable annotations

In your application.properties or application.yml, enable the annotations (e.g. @Counted, @Timed).

management.observations.annotations.enabled=true

Provide Spring config

Now we need to configure the beans to add custom tags to each metric.


import io.micrometer.core.aop.TimedAspect
import io.micrometer.core.instrument.MeterRegistry
import io.micrometer.core.instrument.Tag
import io.micrometer.core.instrument.Tags
import io.micrometer.core.instrument.binder.jvm.JvmThreadMetrics
import io.micrometer.core.instrument.config.NamingConvention
import org.springframework.boot.actuate.autoconfigure.metrics.MeterRegistryCustomizer
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.core.env.Environment

@Configuration(proxyBeanMethods = false)
class MetricsConfig {

@Bean
fun metricsCommonTags(env: Environment): MeterRegistryCustomizer<MeterRegistry> {
val currentEnvironment = env.getProperty("spring.profiles.active")
return MeterRegistryCustomizer { registry ->
registry
.config()
.commonTags(
Tags.of(
Tag.of("env", currentEnvironment ?: "local"),
Tag.of("appId", "123"),
Tag.of("appName", "my-service"),
)
)
.namingConvention(NamingConvention.dot)
}
}

@Bean
fun timedAspect(registry: MeterRegistry): TimedAspect {
val timedAspect = TimedAspect(registry)
return timedAspect
}
}

If you want to track JVM Thread Metrics, add the following bean to the config above:

    @Bean
fun threadMetrics(): JvmThreadMetrics {
return JvmThreadMetrics()
}

Creating and using custom application metrics (examples)

Here is an example of using @Counted and @Timed annotations on a method.

@Counted(value = "name.of.my.metrics.count")
@Timed(value = "name.of.my.metrics.time")
fun doIt() {
// ...
}

Here is a service that encapsulates Gauge metrics (it helps to keep metrics on one place and avoids pollution of code with random metrics):


import io.micrometer.core.instrument.Metrics
import org.springframework.stereotype.Component
import java.util.concurrent.atomic.AtomicInteger

@Component
class AppMetrics {

private var itemsQueueSizeGauge = AtomicInteger(0)
// ...

init {
Metrics.gauge("items.queue.size", itemsQueueSizeGauge)
// ...
}

fun reportItemsQueueSize(size: Int) {
itemsQueueSizeGauge.set(size)
}

// ...
}

Resources

Micrometer guides

Spring guides

DataDog guides

--

--