Blog

Two dependencies and one config block: Spring Boot metrics to Elasticsearch over Prometheus remote write

Prometheus remote write forwards Micrometer's Actuator metrics into an Elasticsearch time series data stream. JVM heap, request latency, GC pauses and HikariCP activity all become queryable with ES|QL, and nothing new has to run alongside it.

Store high-cardinality metrics efficiently with time series data streams, and keep your Prometheus and PromQL workflows along for the ride. 

Dig into infrastructure and metrics monitoring. Start a free cloud trial or try Elastic on your local machine now.

Prometheus Remote Write gives Spring Boot a direct path to Elastic Serverless: no dedicated long-term metrics store, no extra infrastructure to operate. Add two dependencies to pom.xml, point a remote_write block in prometheus.yml at Elastic, and JVM, HTTP request, and database metrics flow into a queryable time series data stream. The AI Agent can then inspect those fields and generate a full metrics dashboard (heap usage, latency percentiles, HikariCP pool activity) from a conversational prompt.

The Curly-Engine implements the PetClinic API and runs Spring Boot alongside Prometheus, so Prometheus can scrape /actuator/prometheus and forward samples to Elastic.

Prerequisites

  • An Elastic Observability Serverless project.
  • An API key that can write to metrics-*.
  • Java 17 or later, Docker, and Docker Compose to run the sample.
  • The Prometheus endpoint from your Serverless project settings.

Expose Spring Boot Actuator metrics with the Micrometer Prometheus registry

The Curly-Engine uses Spring Boot Actuator and Micrometer's Prometheus registry. Add these dependencies to your application's pom.xml:

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
  <groupId>io.micrometer</groupId>
  <artifactId>micrometer-registry-prometheus</artifactId>
</dependency>

Expose the /actuator/prometheus endpoint in application.properties:

management.endpoints.web.exposure.include=health,prometheus
management.endpoint.prometheus.enabled=true

Configure the Prometheus metrics:

management.metrics.tags.application=${spring.application.name}
management.metrics.distribution.percentiles-histogram.http.server.requests=true

Start the application and inspect the endpoint:

curl http://localhost:8080/actuator/prometheus

Alongside JVM and process metrics, Micrometer emits HTTP request histograms with bucket, count, and sum series:

http_server_requests_seconds_bucket{method="GET",status="200",uri="/owners",le="0.01"} 0.0
http_server_requests_seconds_count{method="GET",status="200",uri="/owners"} 42.0
http_server_requests_seconds_sum{method="GET",status="200",uri="/owners"} 3.827

The bucket series contain the latency distribution you can explore after ingestion.

Configure Prometheus remote write

Spring Boot has no built-in Remote Write sender, so run Prometheus beside the application to scrape the Actuator endpoint and push samples to Elastic.

Add this configuration to prometheus.yml, replacing the placeholders with your Prometheus endpoint and API key:

global:
  scrape_interval: 15s
  evaluation_interval: 15s

scrape_configs:
  - job_name: 'petclinic-api'
    metrics_path: '/actuator/prometheus'
    static_configs:
      - targets: ['petclinic-api:8080']

remote_write:
  - url: "https://YOUR_PROMETHEUS_ENDPOINT/api/v1/write"
    authorization:
      type: ApiKey
      credentials: YOUR_API_KEY

The scrape_interval of 15 seconds is a reasonable default; lower it only if you need sub-minute alerting windows and understand the cardinality cost.

The default Remote Write URL routes metrics to metrics-generic.prometheus-default. For separate datasets or namespaces, see Ship Prometheus Metrics to Elasticsearch with Remote Write.

Keep API keys out of committed configuration; for local development, pass the key through an environment variable or a secret manager.

Start the PetClinic sample and Prometheus:

docker-compose up --build
  1. Open http://localhost:9090/targets
  2. Confirm the petclinic-api target is UP
  3. Send a few requests to the API first so request and database metrics have something to show

Verify Prometheus remote write is delivering to Elasticsearch

In Kibana Discover, switch to ES|QL and run:

TS metrics-generic.prometheus-default
| WHERE @timestamp > NOW() - 15 minutes
| LIMIT 500

Discover returns each available metric with a small time series visualization. If the query returns data, Prometheus is scraping the application and Elastic is accepting the Remote Write requests.

Remote Write stores samples in the Elastic metrics data stream. Metric values are available under metrics.*, with Prometheus labels as dimensions for filtering and grouping.

Create a metrics dashboard with the Elastic AI Agent

Open the Elastic AI Agent from the AI Agent icon in the top navigation and ask it to inspect the data stream:

I have Spring Boot Prometheus metrics in the metrics-generic.prometheus-default data stream. Create a dashboard to visualize the metrics.

The AI Agent inspects the fields it finds and creates editable Kibana visualizations. For this sample, useful panels include:

  • JVM heap memory.
  • CPU usage.
  • Request rate by endpoint.
  • HikariCP connection activity.
  • JVM garbage-collection pause time.

Click Preview in the AI Agent response to open the new Dashboard and Save to save it. The generated panels are standard Kibana visualizations; open any of them in Edit to inspect or adjust the ES|QL query, time bucket, aggregation, or breakdown.

Dashboard quality depends on what data the AI Agent finds when it samples the stream. If metrics are sparse, generate some traffic and re-ask with a wider time range.

Add HTTP latency percentiles to the dashboard

Rate metrics show demand; latency percentiles show how endpoints hold up under it. Follow up with:

Add HTTP request latency percentiles to the dashboard, including p50, p90, and p99 by endpoint URI.

The AI Agent builds the panel from Micrometer's HTTP request histogram bucket metric. Review the result before relying on it, paying attention to the selected fields, aggregation, time range, and URI breakdown. This is the query you're most likely to want to tune.

Import the prebuilt dashboard instead

The Curly-Engine repository also includes an importable dashboard.ndjson. To use it, open Stack Management > Saved Objects in Kibana and import the file after metrics are arriving in metrics-generic.prometheus-default.

Take Prometheus remote write to production

Prometheus Remote Write gives a Spring Boot application a direct path from Actuator metrics to Elastic Serverless without a separate long-term metrics store.

Whether that is the right trade-off depends on what you need from the store:

Prometheus remote write into ElasticsearchDedicated long-term store (Thanos, Mimir, Cortex)
Components to operateThe Prometheus instance you already run, plus the Elastic projectSidecar or distributor, store gateway, querier, compactor, and an object storage bucket
Query languageES|QL and PromQLPromQL
DownsamplingHandled by Elasticsearch time series data stream downsamplingBuilt in, typically at fixed resolutions
Global view across many Prometheus instancesEvery instance writes to the same cluster, so one query spans all of themA core design goal, with deduplication across overlapping instances
Use the AI Agent to start a dashboard conversation, then validate and refine the generated panels for the metrics and labels that matter to your service.

Before applying this to a high-cardinality production workload, review the scrape job and add metric_relabel_configs to drop metrics you don't need.

How helpful was this content?

Related Content

Cut log storage costs with two Elasticsearch data tiers instead of four

Cut log storage costs with two Elasticsearch data tiers instead of four

Peter Simkins
Temporal Cloud observability in Elastic: 50+ metrics, zero collectors

Temporal Cloud observability in Elastic: 50+ metrics, zero collectors

Ishleen Kaur
Not every log deserves 90 days: per-stream retention in Elastic Streams

Not every log deserves 90 days: per-stream retention in Elastic Streams

Peter Simkins
Monitor Supabase in Elastic: dashboards, alert templates, SLO templates, and zero agents

Monitor Supabase in Elastic: dashboards, alert templates, SLO templates, and zero agents

Ishleen Kaur
Native OTLP metrics ingestion on Elastic Cloud Hosted

Native OTLP metrics ingestion on Elastic Cloud Hosted

Maurizio Branca

Elastic Observability Labs Newsletter