Observability in Java: From "Why did it crash?" to "I know what will happen in a minute"
\n\nImagine: your Java application is running in production. Everything is fine. And then — bam! — users complain that the page takes 10 seconds to load. You log into the server, look at the logs, see a bunch of INFO and not a single ERROR. What to do? Where to look?
In classic monitoring, you check: is the server alive, how much memory is used, has the process crashed. But that's like checking if the light bulb on the dashboard is on — useful, but not enough. Observability is the next level. It's the ability to understand the internal state of a system from its external outputs: logs, metrics, and traces.
\n\nIn this article, I'll show you how to implement observability in Java using real-world examples. We'll use OpenTelemetry, Micrometer, Spring Boot Actuator, and classic SLF4J. You'll learn how to link logs, metrics, and traces into a single picture, rather than just "collecting everything in a pile."
\n\nWhat is Observability and why is it not just "log collection"?
\n\nObservability comes from control theory. A system is observable if its internal state can be inferred from its output data. In the Java world, this means three pillars:
\n\n- \n
- Logs — structured records of events (what happened?); \n
- Metrics — numerical indicators (how many? how long?); \n
- Traces — chains of calls (what path did the request take?). \n
Without observability, you are blind. You know the CPU is at 95%, but you don't know which specific endpoint is loading it. You see an error in the log, but you don't understand which user triggered it and which services were involved. Observability in Java is not about "installing a library," but about a development culture.
\n\nOpenTelemetry: A universal tool for observability
\n\nIn the past, there was a zoo: Zipkin for tracing, Prometheus for metrics, ELK for logs. Each with its own SDK. OpenTelemetry (OTel) came to unify them. It's an open-source standard for collecting telemetry. It supports Java natively and integrates easily into Spring Boot, Micronaut, Quarkus.
\n\nHow does it work? You add an agent or SDK to your Java application, and OTel automatically intercepts HTTP requests, database calls, and message queues. You don't need to write code for each tool separately.
\n\nExample: Setting up OpenTelemetry in Spring Boot
\n\nAdd the dependency to pom.xml:
<dependency>\n <groupId>io.opentelemetry</groupId>\n <artifactId>opentelemetry-api</artifactId>\n <version>1.40.0</version>\n</dependency>\n<dependency>\n <groupId>io.opentelemetry</groupId>\n <artifactId>opentelemetry-sdk</artifactId>\n <version>1.40.0</version>\n</dependency>\n<dependency>\n <groupId>io.opentelemetry.instrumentation</groupId>\n <artifactId>opentelemetry-spring-boot-starter</artifactId>\n <version>2.6.0</version>\n</dependency>\n\nNow in the configuration (application.yml), specify the exporter, for example, to Jaeger or an OTLP collector:
otel:\n exporter:\n otlp:\n endpoint: http://localhost:4317\n traces:\n exporter: otlp\n metrics:\n exporter: otlp\n logs:\n exporter: otlp\n\nVoila! Now every HTTP request to your controller automatically creates a trace. You can see how long each database call, external API call, or just a thread delay took.
\n\nTracing in Java: How to find the "bottleneck"
\n\nTracing is perhaps the most powerful part of observability. When your application consists of dozens of microservices, traces are the only way to understand why a request takes 2 seconds, even though each ser