Instrument Spring Boot with OpenTelemetry

Send traces, logs and metrics from a Spring Boot app to Telemetry Machine with the OpenTelemetry Java agent. No code changes.

Open in Claude

The OpenTelemetry Java agent traces every request, database call and outgoing HTTP call, sends your Logback or Log4j logs as logs, and records HTTP and JVM metrics. Your code doesn't change.

Create the datasets

Each signal goes to its own dataset. Create three, and an ingest key that can write to all of them, with tm-cli or the MCP server:

$ tm-cli datasets create --name shop-prod-traces --type traces
$ tm-cli datasets create --name shop-prod-logs --type logs
$ tm-cli datasets create --name shop-prod-metrics --type metrics
$ tm-cli api-keys create --name shop-api --dataset shop-prod-traces --dataset shop-prod-logs --dataset shop-prod-metrics

tm-cli shows the key once, in api_key.api_key. Over MCP, your agent gets it once and saves it in your app's configuration. In the app, create each dataset, then a key for all three under API keys in your organization's settings.

Install

Download the agent:

Terminal
$ curl -L -O https://github.com/open-telemetry/opentelemetry-java-instrumentation/releases/latest/download/opentelemetry-javaagent.jar

Configure

Shell
export TM_INGEST_KEY='<ingest-key>'
export OTEL_SERVICE_NAME=shop-api
export OTEL_EXPORTER_OTLP_ENDPOINT=https://api.telemetrymachine.com
export OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf
export OTEL_EXPORTER_OTLP_TRACES_HEADERS="X-API-Key=$TM_INGEST_KEY,X-Dataset-Name=shop-prod-traces"
export OTEL_EXPORTER_OTLP_LOGS_HEADERS="X-API-Key=$TM_INGEST_KEY,X-Dataset-Name=shop-prod-logs"
export OTEL_EXPORTER_OTLP_METRICS_HEADERS="X-API-Key=$TM_INGEST_KEY,X-Dataset-Name=shop-prod-metrics"

Run

Start your app with the agent:

Terminal
$ java -javaagent:opentelemetry-javaagent.jar -jar target/shop-0.0.1-SNAPSHOT.jar

With the Maven plugin:

Terminal
$ ./mvnw spring-boot:run -Dspring-boot.run.jvmArguments=-javaagent:opentelemetry-javaagent.jar

Check it arrived

Send your app a few requests, then open each explorer and choose the dataset:

  • Traces, shop-prod-traces: one server span per request, named after its mapping, such as GET /items/{id}.
  • Logs, shop-prod-logs: your log records, each with its request's trace.trace_id.
  • Metrics, shop-prod-metrics: http.server.request.duration and the jvm.* metrics, sent once a minute.

Or count spans by name with tm-cli or the MCP server:

$ tm-cli query shop-prod-traces --since 15m --select "name, count(*)" --group-by name

Troubleshooting

  • No telemetry, and no opentelemetry-javaagent - version line at startup: the agent isn't loaded. Pass -javaagent before -jar, or set JAVA_TOOL_OPTIONS=-javaagent:/path/to/opentelemetry-javaagent.jar where you can't change the command.
  • Server responded with HTTP status code 400 and Invalid API key: the key doesn't exist, or doesn't cover the dataset in that signal's X-Dataset-Name. Check the dataset names against the key's datasets.