Elasticsearch as the backbone of microservices observability: centralized logging across services, structured logging and trace IDs, distributed tracing with Elastic APM and OpenTelemetry, service maps, and service discovery patterns.

Microservices architecture splits one large application into dozens of small services. Behind the benefit of independent deployment lies a classic problem: when something fails, the error can appear in any service — and hunting for its source across piles of logs on many machines feels like looking for a needle in a haystack. This is where Elasticsearch comes in.
Episode 26 covers Elasticsearch's role in microservices: centralized logging across services, structured logging practices with trace IDs, distributed tracing with Elastic APM and OpenTelemetry, service maps, and patterns for using Elasticsearch as a service registry.
The first principle: don't let logs scatter across services. All services send logs to one Elasticsearch (or observability cluster), so a single search can answer "what happened across the whole system". The architecture: each service writes logs to stdout/stderr, an agent (Filebeat, episode 24) picks them up, and the data enters a data stream.
service-a ---+
service-b ---+--> Filebeat --> Logstash (opsional) --> Elasticsearch --> Kibana
service-c ---+The benefits: a single source of truth, cross-service search, and dashboards covering the entire system. This is the standard logging architecture that almost always uses the Elastic Stack.
Logs must be structured, not free text. Structured logs (JSON) can be filtered, aggregated, and searched by field; free logs can only be grokked (which is fragile). A comparison example:
{
"timestamp": "2026-08-03T10:00:00.123Z",
"level": "error",
"service.name": "order-service",
"trace.id": "abc123def456",
"message": "koneksi ke payment-service timeout",
"http.status": 504,
"duration_ms": 5230
}This field consistency is what lets dashboards like "error per service" or queries like "all logs with trace.id X" run smoothly.
Important
Standardizing the log format across services is collaborative work: create a shared log schema (required fields: timestamp, level, service.name, trace.id, message) and enforce it via linting or an internal logging library. Services whose logs have "their own personality" are the root cause of bad observability.
A trace ID is a unique identity propagated from one incoming request through all the inter-service calls within it. When a user sends one HTTP request crossing 5 services, all logs from those 5 services share the same trace ID.
Implementation: the tracing library injects a traceparent header into each call, and each service reads then forwards the ID. In Elasticsearch, you then search:
{
"query": {
"term": {
"trace.id": "abc123def456"
}
}
}With a single search, the entire journey of one request across all services is visible — which services were called in what order, how long each hop took, and where the failure occurred. This is the answer to "why is this request slow" in seconds.
Elastic APM automates this tracing. APM agents are installed in each service; they capture transactions (one incoming request) and spans (each internal call), then send them to the APM Server and Elasticsearch:
environment: production
server_url: https://apm-server:8200
service_name: order-service
api_key: apm-key-hereFrom this data, Kibana assembles a transaction timeline: each span with its duration, including calls to databases, external APIs, and Elasticsearch itself. When "order-service" is slow, you immediately see which span took the time.
Tip
APM works best if all services in one system use the same agent. Half the services instrumented and half not makes traces break mid-way — worse than none at all. Standardize the APM agent (or OpenTelemetry) as an architectural requirement, not a choice.
Elasticsearch/Kibana supports OpenTelemetry (OTel) — the open observability standard. You can instrument services with the OTel SDK, then forward traces to Elastic observability (via an OTel collector to APM). The benefit: vendor-agnostic — your code isn't locked into Elastic; you can switch providers without rewriting instrumentation.
exporters:
otlp:
endpoint: apm-server:8200
headers:
Authorization: "Bearer otel-token"With OTel, you keep the industry standard while enjoying Elastic integration. Many organizations use this as an "open standards with Elastic dashboards" strategy.
Kibana's Service Map presents an automatic visualization of all services and their dependencies, built from APM data: nodes represent services, lines represent connections between them, and color/size indicate health. A single glance answers "what's our system topology" and "where's the bottleneck".
An older pattern, but still relevant at small scale: using Elasticsearch as a service registry. Services register themselves into the service-registry index at startup:
PUT /service-registry/_doc/order-service-1{
"service.name": "order-service",
"instance.id": "order-service-1",
"host": "10.0.2.15",
"port": 8080,
"status": "up",
"updated_at": "2026-08-03T10:00:00Z"
}Other services look it up when they need to communicate, and instances that don't update their heartbeat within a period are considered dead (health check). In modern production, Kubernetes service discovery and Consul usually replace this pattern — but understanding it helps you understand what service discovery actually does.
Warning
Don't use Elasticsearch as a source of truth for conflict-prone state — it isn't a transactional database (episode 2). Service registries use Elasticsearch because of easy search and TTL, not because of write integrity. For large systems, evaluate dedicated service discovery tools.
Unstructured logs. Free text can't be reliably filtered — use JSON with fixed fields.
Trace IDs not propagated. Cross-service calls must forward the trace header — otherwise traces break.
Inconsistent log schemas. Standardize required fields across teams.
Half the services instrumented. Broken traces are more confusing — roll it out fully.
Using Elasticsearch for stateful transactions. It isn't an ACID database — keep the role separation.
In episode 26 you mastered Elasticsearch's role in microservices: centralized logging with cross-service log aggregation, structured logging with consistent fields, log correlation with trace IDs, distributed tracing with Elastic APM and OpenTelemetry, service maps, and service registry and health check patterns.
Key takeaways:
All of this runs on physical machines. But these days deployments more often run on top of containers and Kubernetes. In episode 27 we'll cover container orchestration: the Elasticsearch Docker image, multi-node Docker Compose, volume management; Kubernetes deployment with ECK, StatefulSets, PVCs, services/ingress, secrets; and production considerations such as resource limits, anti-affinity, init containers, and probes. See you there!