22 March 2026
In this tutorial, we'll explore a simple and clear way to integrate observability into your workloads using Spring Boot 4.x and Elastic Cloud through mOTLP.
By the end of this tutorial, you'll have a configuration similar to:

One of the simplest ways I've found to describe OTLP is to think of observability as a data pipeline, similar to the one in the following image:

In most data pipelines, regardless of the technology, we establish the following stages:
In the DevSecOps world, this analysis platform has become mandatory to operate our heterogeneous workloads. Whether it's root cause analysis, incident resolution, alerting, or even autonomous agents, the data generated by our applications is fundamental to decision-making.
As a result, the logical consequence was the creation of a protocol so that all components of the ecosystem can participate in these efforts. This effort is OpenTelemetry, a top-level project of the Cloud Native Computing Foundation.
OpenTelemetry's proposal is as follows:

Through abstractions and similar to a data pipeline, OpenTelemetry allows us to:
All of this through a common protocol with support for HTTP or protobuf formats.
As I demonstrated in a previous post, configuring these collectors and observability platforms is an extensive task. So cloud providers—like Elastic—offer, in addition to the analysis platform, receivers/collectors compatible with the OpenTelemetry protocol.

In this configuration, your workloads deliver the three dimensions of observability (traces, metrics, logs) directly to an OTLP-compatible endpoint with the following advantages:
And, of course, with some special considerations:
The simplest way to explore this functionality is directly in Elastic, specifically in a Serverless project, where services are managed by Elastic. When you create this project, there's a specific template for observability -Elastic for Observability- that will work in most situations.

By default, a serverless project will let you choose from three cloud providers: Azure, Google, and Amazon.

When you're done, you'll have a Kibana-based workspace similar to the following:

The Kibana dashboard offers a fairly explicit section for adding data, among which you'll see the OpenTelemetry option.

Among other things, the assistant provides useful links to instrument workloads in various programming languages. The assistant will also ask you for a service name and provide 3 important elements:
You should store these securely as they'll be useful for integrating our instrumentation.

For this demonstration, I've prepared two services that can be run locally:
Full source code is available at GitHub.
For Java, there are two main ways to instrument workloads:
In the case of Spring Boot, there are TWO major instrumentation options:
For this post, we'll use option #1 in both artifacts, which I consider the simplest.
As always, it is also good to consider the official documentation.
Otel instrumentation with the Spring starter is activated in three steps:
<dependencyManagement>
<dependencies>
<dependency>
<groupId>io.opentelemetry.instrumentation</groupId>
<artifactId>opentelemetry-instrumentation-bom</artifactId>
<version>2.33.1</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
...
<dependency>
<groupId>io.opentelemetry.instrumentation</groupId>
<artifactId>opentelemetry-spring-boot-starter</artifactId>
</dependency>
There is a set of optional libraries and adapters that you can configure if your workloads have already diverged from the "Spring Way".
Finally, you need to activate (or not) the observability dimensions (metrics, traces, and logs). Also, you can fine-tune the exporting parameters like ports, URLs, or exporting periods. You can do this using Spring Properties or environment variables:
# Configure exporters
otel.logs.exporter=otlp
otel.metrics.exporter=otlp
otel.traces.exporter=otlp
# Configure metrics generation
otel.metric.export.interval=5000 # Export metrics every five seconds
otel.instrumentation.micrometer.enabled=true # Enable Micrometer metrics bridge
If you already explored the source code, you probably noticed there are not credentials in the properties file. As suggested in the configuration within Elastic Cloud, the most recommended approach would be to inject these values through environment variables. For example, the following .env file would be sufficient for local development:
export OTEL_EXPORTER_OTLP_ENDPOINT="https://my-observability-project-..."
export OTEL_EXPORTER_OTLP_HEADERS="Authorization=ApiKey dX..."
Which you can source as part of the execution of these services (on local testing environment).
source .env
Then, it's time to boot the services. You only need Java 25 on the active shell:
cd springboot-demo
mvn spring-boot:run
And:
cd springboot-client-demo
mvn spring-boot:run
To demonstrate observability in the three dimensions, both sprinboot-demo (8080) and springboot-client-demo (8081) have some interactions to:
Generate CPU workload using Naive Fibonacci:
curl http://localhost:8080/fibo\?n\=45
Generate logs at different levels:
curl http://localhost:8080/log
Persist data using a CRUD:
curl -X POST --location "http://localhost:8080/books" \
-H "Content-Type: application/json" \
-d '{
"author": "Miguel Angel Asturias",
"title": "El señor presidente",
"isbn": "978-84-376-0494-7",
"publisher": "Editorial planeta"
}'
And then retrieve the data using a secondary service:
curl http://localhost:8081/trace-demo
After running the above commands and allowing a few seconds for data propagation, you should see observability data flowing into your Elastic deployment. The best way to confirm this is by using the Discovery tab, where you can explore data using ES|QA queries. Also, the Cloud instance offers an AI assisted query builder, capable of translating natural language queries to actual deterministic queries.
You'll see structured logs from both services showing:
The logs are automatically enriched with:

For example, when you hit the logs endpoint, you'll see entries like:
INFO Info level
You'll observe application and JVM metrics being reported every 5 seconds (based on our configuration):
Application Metrics:
JVM Metrics:
Run the fibonacci operation multiple times and watch the CPU metric spike:
for i in {1..5}; do curl http://localhost:8080/fibo\?n\=45; done
You'll see corresponding CPU utilization spikes in Elastic, with each spike correlated to your curl requests.

The Traces reveal the full journey of each operation through your system:
Example trace from /trace-demo:
Each span shows:
Click on any span to see:
Correlation across dimensions: The trace ID connects all three observability dimensions. A single trace ID appears in logs, metrics, and traces, allowing you to correlate a user request with log entries and performance metrics—the foundation of effective observability.

Kibana also includes an "eagle-eye" in the service inventory section. Where you can spot-check all the tree dimensions, in a service-oriented way.

mOTLP is one of many options to implement observability in our Java workloads. In my opinion, it's one of the easiest ways to get fast results and enable the next level: doing something with the data, like dashboards, alarms, and even AI analysis. So don't miss my next publications on these topics.