Imagine you’ve got microservices scattered across a dozen servers, and suddenly, a user reports a bug. Now, you’re staring at logs from each service, each on its own machine, trying to stitch together a narrative. This isn’t just inconvenient; it’s a fundamental bottleneck in debugging distributed systems.
Let’s look at a common setup for aggregating logs, using Elasticsearch, Fluentd, and Kibana (often called the EFK stack).
The System in Action: EFK Stack
First, we need a way to collect logs from our services. Fluentd is a popular choice for this. It’s a daemon that runs on each host, tailing log files or receiving logs over the network.
Here’s a simplified Fluentd configuration snippet (fluentd.conf):
<source>
@type tail
path /var/log/my_app/*.log
pos_file /var/log/td-agent/my_app.pos
tag my_app.log
<parse>
@type json
</parse>
</source>
<match my_app.log>
@type elasticsearch
host 192.168.1.100
port 9200
index_name my_app-%Y.%m.%d
type_name log
</match>
This configuration tells Fluentd to watch /var/log/my_app/*.log, parse each line as JSON, tag it my_app.log, and then send it to an Elasticsearch instance running at 192.168.1.100:9200. The index_name creates daily indices, which is good for managing data volume.
Next, Elasticsearch. It’s a distributed search and analytics engine. Fluentd pushes logs into Elasticsearch, which then indexes them for fast searching.
Finally, Kibana. This is the visualization layer. You connect Kibana to your Elasticsearch cluster, and it provides a web interface to search, filter, and graph your logs.
You’d typically access Kibana through a web browser, often at http://kibana.yourdomain.com. Inside Kibana, you’d define an "Index Pattern" that matches your log indices (e.g., my_app-*) and then you can start exploring your logs. You might see something like this in the Kibana Discover tab:
| @timestamp | message | level | service | user_id |
|---|---|---|---|---|
| 2023-10-27T10:00:01Z | User 'alice' logged in successfully. | INFO | auth | alice |
| 2023-10-27T10:00:05Z | Request received for order 123. | DEBUG | orders | alice |
| 2023-10-27T10:00:06Z | Failed to process payment for order 123. | ERROR | orders | alice |
| 2023-10-27T10:00:07Z | Payment gateway timed out. | WARN | orders | alice |
This unified view lets you trace alice’s actions across the auth and orders services, pinpointing the payment gateway issue.
The Mental Model
The core problem this stack solves is correlation. When events happen across multiple independent services, you need a way to link them. The EFK stack provides this by:
- Collection (Fluentd): Standardizing log formats and shipping them from disparate sources to a central point. It acts as a universal adapter.
- Storage & Indexing (Elasticsearch): Providing a scalable, searchable repository. Elasticsearch’s strength is its ability to index vast amounts of text data and return search results incredibly quickly.
- Visualization (Kibana): Offering an intuitive interface to query and explore the indexed data, turning raw logs into actionable insights.
The key levers you control are:
- Log Format: Standardizing on a structured format like JSON (or even better, a common schema like Common Schema) makes parsing and searching much more reliable.
- Tagging/Routing: How Fluentd categorizes logs (e.g., by service name, environment) determines how you’ll group and filter them later.
- Elasticsearch Indexing Strategy: How you name and structure your indices (daily, weekly, by service) impacts performance, storage management, and query complexity.
- Kibana Dashboards & Visualizations: The queries and graphs you build in Kibana are your primary tool for understanding system behavior.
The most surprising aspect of this setup is how much emphasis is placed on metadata. It’s not just about shipping the log message; it’s about enriching it with context before it hits Elasticsearch. This means adding fields like service_name, environment, request_id, user_id, trace_id, and hostname to every single log entry. Without these, searching for "user X had a problem" becomes a painful, manual process of sifting through unstructured text. When you have these fields, you can instantly filter logs for user_id: "alice" and service_name: "orders", and Kibana will show you only those relevant entries, regardless of which server they originated from.
The next challenge is often real-time alerting on specific log patterns or error rates.