Tools Used in SRE · Elastic Stack (ELK)

Elastic Stack (ELK)

When an incident needs an answer that only exists as a sentence buried in some container's stdout three hosts ago, the Elastic Stack is still, by a wide margin, the tool most SRE teams reach for. Elasticsearch, Logstash, Beats, and Kibana — Elastic, Logstash, Kibana gave the stack its original "ELK" name, and Beats was folded in later as the lightweight shipper — together answer one question that metrics and traces structurally can't: what did the system actually say, in its own words, at that exact moment? This page covers what each of the four pieces actually does, how a raw log line becomes a searchable document, the index lifecycle management that keeps that searchability from bankrupting you, and the operational fact every team learns the hard way — that log volume, not query complexity, is what takes an ELK deployment down first.

☺ Explain it like I'm 10

Imagine a library that doesn't just shelve books — it reads every single page of every book the moment it arrives and builds a card for every word, saying exactly which books and which pages that word appears on. Ask "which books mention dragons on page 40 or later" and the librarian doesn't search shelf by shelf; she pulls the "dragons" card and reads off the answer instantly. That librarian and her card catalog is Elasticsearch. Beats and Logstash are the delivery trucks and the clerks at the loading dock who unbox each new book, tidy up its cover and page numbers before it's shelved, and hand it to the librarian. Kibana is the reading room out front where you actually ask your question and get shown the answer on a screen. The catch, and it's the whole second half of this page: reading and carding every word of every page is expensive work, and if trucks start arriving ten times faster than usual, the librarian runs out of shelf space before anyone ever asks her a hard question.

🐘Your host for this topic: Ellie the Elephant — she holds every metric, log, and trace this course produces, and the Elastic Stack is the actual machine most teams build for the "log" third of that job when a full-text-searchable record of what a service said is worth more than what a metric can only summarize.

What the Elastic Stack is and the problem it solves

☺ Like you're 10: It's four separate programs that each do one job — collect, tidy up, file away and index, and let you search — and together they turn a mountain of scattered text into something you can ask a question about.

Every service in a fleet writes logs, and by default those logs sit on whatever host or container produced them, in whatever format the developer who wrote that print statement happened to choose. That's fine until an incident spans a dozen services, at which point "grep every host by hand" stops being a strategy and becomes the incident itself. The Elastic Stack's job is to centralize that mess: ship every log line off its origin host, parse it into structured fields, index it for full-text search, and put a query interface in front of the result — so "show me every ERROR from the checkout service in the last twenty minutes that mentions timeout" is a five-second query instead of an SSH session into six containers that may already be gone.

Elasticsearch, Logstash, Beats, and Kibana — four names, one stack

Elasticsearch is the engine underneath everything: a distributed, JSON-document store built on top of Apache Lucene, which does the actual full-text indexing and search. Logstash is a general-purpose, plugin-based data pipeline — it reads from an input, transforms each event through a chain of filters, and writes it to an output, most commonly Elasticsearch. Beats are single-purpose, lightweight shippers written in Go — Filebeat tails log files, Metricbeat polls system and service metrics, Packetbeat inspects network traffic, Winlogbeat reads the Windows Event Log, and Auditbeat watches file integrity and the Linux audit framework — designed to sit on every host with a far smaller footprint than a JVM-based Logstash instance would allow. Kibana is the web UI: Discover for ad hoc searching, Dashboards for saved visualizations, Dev Tools for raw queries against Elasticsearch's API, and — via a bundled Alertmanager-adjacent engine — rule-based alerting of its own.

◆ Key idea

Only one of these four pieces is mandatory. Elasticsearch has to exist for anything to be searchable. Everything else is a front door: you can ship straight from Filebeat to Elasticsearch's own ingest pipelines and skip Logstash entirely for simple parsing, and you can query Elasticsearch's REST API directly and skip Kibana entirely for programmatic access. Most real deployments use all four anyway, because each one is genuinely the easiest tool for its specific job — but knowing which piece is load-bearing is the first thing to reach for when something in the pipeline breaks.

A brief history, and the license fork worth knowing about

Elasticsearch was first released in 2010 by Shay Banon, wrapping Lucene's mature but low-level search library in a distributed, JSON-native, horizontally scalable service. Logstash and Kibana were built separately and joined the same company shortly after; Beats arrived in 2015 as a lighter-weight answer to Logstash's JVM overhead, at which point the branding shifted from "ELK Stack" to "Elastic Stack" to reflect the fourth member. For most of that history the core software shipped under the permissive Apache 2.0 license. In January 2021, Elastic relicensed Elasticsearch and Kibana away from Apache 2.0 to a dual Elastic License / Server Side Public License (SSPL) model, citing cloud providers — chiefly AWS — offering the software as a managed service without licensing or contributing back. AWS responded within weeks by forking the last Apache-2.0 version into OpenSearch, which it has maintained since (governance later moved to the Linux Foundation). Elastic subsequently added AGPLv3 as a third licensing option for its own core products. Treat all of this as a moving target rather than settled fact — verify the current license terms for whatever version and distribution you're actually deploying on Elastic's own licensing page before you build a procurement or compliance decision on it.

⚠ "Elastic Stack" and "OpenSearch" are not interchangeable, even where they look identical

OpenSearch and Elasticsearch shared a common ancestor and still look similar in their REST APIs, but they have diverged independently since the 2021 fork — new Elasticsearch-only features (and vice versa) are not guaranteed to be API-compatible going forward. Don't assume a Logstash config, an ILM policy, or a Kibana dashboard written against one will simply work unmodified against the other; verify compatibility for your specific versions before treating this page's examples as portable between them.

Architecture: from a log line to a searchable document

☺ Like you're 10: A log line gets picked up at the source, walks through an optional tidying-up step, lands in the librarian's card catalog, and the reading room out front is where you ask about it.

Every deployment, however it's wired, is one variant of the same pipeline: collect at the source, optionally parse and enrich in flight, index into Elasticsearch, query and visualize through Kibana. The two decisions that actually distinguish real deployments from each other are where parsing happens and how long data stays searchable before it's aged out — the first is this section's subject, the second is Index Lifecycle Management, covered next.

App logs container stdout / stderr JSON or free text System & audit logs syslog, journald, auditd one host, one agent Kubernetes pod logs via the kubelet's log dir one DaemonSet per node Filebeat / Elastic Agent tails files, tracks offsets, lightweight, Go binary Logstash optional — input · filter · output grok / dissect / enrich JVM-based, heavier Elasticsearch cluster Ingest pipeline (grok, dissect, date, geoip processors) Inverted index — one Lucene index per shard Hot tier: fast NVMe/SSD, actively written & queried Index templates + mappings applied per data stream Only Elasticsearch itself is load-bearing — everything else is a front door onto it. Kibana Discover · Dashboards Dev Tools · Alerting Index Lifecycle Management (ILM) — runs underneath, on a timer hot → warm → cold → frozen → delete enrich direct

Beats vs. Logstash vs. Elasticsearch ingest pipelines — where parsing happens

Raw text isn't queryable in any structured way; a log line has to be broken into fields — timestamp, service, level, message — before "show me only ERRORs" means anything to Elasticsearch. That parsing can happen in three different places, and the choice is a real architectural decision, not a style preference. Beats can do light, single-purpose parsing via built-in modules for known formats (nginx, Docker, syslog) but isn't a general transform engine. Logstash is the heaviest and most capable option — its grok filter matches log lines against named regex patterns (%{TIMESTAMP_ISO8601:timestamp} \[%{WORD:service}\] %{LOGLEVEL:level} %{JAVACLASS:class} - %{GREEDYDATA:message}), its dissect filter splits fixed-delimiter text without regex at all (faster, but only works when the format never varies), and it has plugins for geoip lookups, user-agent parsing, and arbitrary field mutation. Elasticsearch's own ingest pipelines run the same class of processors — grok, dissect, date, geoip, set, rename — but execute inside Elasticsearch itself, on the node handling the write, with no separate JVM process to run or scale. For a genuinely simple, well-structured log format, an ingest pipeline alone is often enough and removes a whole tier of infrastructure; Logstash earns its JVM overhead when you need multi-input fan-in, conditional routing to different outputs, or plugins ingest pipelines don't have.

Documents, indices, shards, and the inverted index underneath

Everything Elasticsearch stores is a JSON document, and every document lives in exactly one index — a logical namespace, roughly analogous to a database table. Physically, an index is split into one or more shards, and each shard is a completely self-contained Lucene index with its own inverted index: a map from every distinct term to the list of documents containing it, which is what makes "find every document containing the word timeout" a lookup instead of a scan. Replica shards are full copies of primary shards on different nodes, giving both fault tolerance and read throughput. Two field types matter more than any other mapping decision: text fields are analyzed — tokenized, lowercased, run through a language analyzer — and support full-text search but not exact-match filtering or sorting; keyword fields are stored verbatim and support exact-match, aggregation, and sorting but not full-text search. Mapping a log's service field as text instead of keyword is a common early mistake — it silently breaks the exact-match dashboards and aggregations built on top of it later.

◆ Key idea

New documents become searchable on the next index refresh, not instantly — the default refresh interval is one second, which Elasticsearch calls near-real-time search rather than real-time. That one-second gap is invisible in nearly all incident work, but it's worth knowing by name the first time a just-shipped log line doesn't show up in Discover on the very next keystroke.

Index Lifecycle Management: the mechanism that actually controls cost

☺ Like you're 10: A policy that automatically moves old logs from the librarian's fast front desk to a cheaper back room, then to a storage warehouse, then eventually shreds them — without anyone having to remember to do it by hand.

Full-text indexing every log line is expensive relative to just storing compressed raw text — the inverted index, the stored fields, and the doc-values structures Elasticsearch keeps for aggregations commonly add somewhere in the range of 1.1x to 3x overhead versus the raw log data, depending on settings. Keeping that overhead on your most expensive, fastest storage forever is how an ELK deployment's disk bill quietly becomes the biggest line item in the whole observability budget. Index Lifecycle Management (ILM) is Elastic's built-in answer: a declarative policy, attached to an index or a data stream, that automatically moves data through storage tiers as it ages, without anyone running a cron job or a manual migration.

The five phases: hot, warm, cold, frozen, delete

ILM defines up to five phases, each with its own actions and a min_age that gates when an index becomes eligible to enter it. Hot is where an index is actively written and queried, typically on the fastest local storage a cluster has; a rollover action here closes the current write index once it crosses a size, age, or document-count threshold and opens a new one, which is what keeps any single index from growing without bound. Warm holds indices that are read-mostly — typical actions here are a forcemerge (collapsing many small Lucene segments into fewer, larger ones for cheaper storage and faster search) and a shrink (reducing shard count, since a warm index no longer needs the write throughput its shard count was originally sized for). Cold holds rarely-queried data, often moved to cheaper storage tiers or nodes. Frozen is the cheapest tier that's still searchable at all — Elasticsearch's searchable snapshots keep the actual data in object storage like S3 and mount it on demand, trading query latency for a dramatically smaller local footprint. Delete removes the index outright once it's aged past whatever retention the organization actually needs.

Index templates, component templates, and data streams

ILM policies don't attach themselves — an index template matches a naming pattern (logs-checkout-*) and applies mappings, settings, and an ILM policy name to every new index that matches it automatically, so a rollover doesn't quietly leave the new index unmanaged. A data stream is the abstraction built specifically for this pattern: it presents as one logical, append-only name for writes and searches, while internally managing a sequence of auto-generated, hidden backing indices that rollover and progress through ILM behind the scenes — the modern replacement for the older, hand-rolled "index-per-day plus an alias" convention teams used to build themselves.

The config you actually write

☺ Like you're 10: A handful of files decide how a log line gets tidied up, what it's allowed to look like once it's filed, and how long it's allowed to stick around before it's thrown out.

A realistic pipeline for one service's logs touches four files: a Logstash filter (if Logstash is in the path at all), an Elasticsearch ingest pipeline, an ILM policy, and an index template that ties the ILM policy to a naming pattern.

# logstash.conf — parse checkout service application logs
input {
  beats { port => 5044 }
}
filter {
  # "2026-08-16T03:14:07.552Z [checkout] ERROR OrderService - Failed to charge card: timeout after 3000ms"
  grok {
    match => { "message" => "%{TIMESTAMP_ISO8601:timestamp} \[%{WORD:service}\] %{LOGLEVEL:level} %{JAVACLASS:class} - %{GREEDYDATA:log_message}" }
  }
  date {
    match => [ "timestamp", "ISO8601" ]
    target => "@timestamp"
  }
  mutate {
    remove_field => [ "timestamp", "message" ]
  }
}
output {
  elasticsearch {
    hosts => ["https://es-hot-01:9200"]
    data_stream => "true"
    data_stream_dataset => "checkout"
    data_stream_namespace => "prod"
  }
}
# PUT _ilm/policy/logs-checkout-policy
{
  "policy": {
    "phases": {
      "hot":    { "min_age": "0ms",
                  "actions": { "rollover": { "max_primary_shard_size": "50gb", "max_age": "1d" },
                               "set_priority": { "priority": 100 } } },
      "warm":   { "min_age": "3d",
                  "actions": { "forcemerge": { "max_num_segments": 1 },
                               "shrink": { "number_of_shards": 1 },
                               "set_priority": { "priority": 50 } } },
      "cold":   { "min_age": "14d",
                  "actions": { "set_priority": { "priority": 0 } } },
      "frozen": { "min_age": "30d",
                  "actions": { "searchable_snapshot": { "snapshot_repository": "logs-snapshots" } } },
      "delete": { "min_age": "90d",
                  "actions": { "delete": {} } }
    }
  }
}

# PUT _index_template/logs-checkout — ties the policy above to every matching index
{
  "index_patterns": ["logs-checkout-*"],
  "data_stream": {},
  "template": {
    "settings": { "number_of_shards": 1, "number_of_replicas": 1,
                  "index.lifecycle.name": "logs-checkout-policy" },
    "mappings": { "properties": {
      "@timestamp":  { "type": "date" },
      "service":     { "type": "keyword" },
      "level":       { "type": "keyword" },
      "log_message": { "type": "text" }
    } }
  }
}

Day-to-day commands and queries

☺ Like you're 10: A handful of questions cover almost every real workday: is the cluster healthy, how big are my indices, and can I ask it a specific question in its own language.

# cluster and index health — the first three commands during any "why is Kibana slow" report
$ curl -s localhost:9200/_cluster/health?pretty
$ curl -s "localhost:9200/_cat/indices?v&s=store.size:desc" | head -20
$ curl -s "localhost:9200/_cat/nodes?v&h=name,heap.percent,ram.percent,disk.used_percent"
$ curl -s "localhost:9200/_cat/shards/logs-checkout-*?v"

# see exactly what's stuck, and why, before you touch anything
$ curl -s localhost:9200/_cluster/allocation/explain?pretty

# clear a disk-watermark-triggered read-only block after freeing space — see Gotchas below
$ curl -X PUT "localhost:9200/logs-checkout-*/_settings" -H 'Content-Type: application/json' \
    -d '{ "index.blocks.read_only_allow_delete": null }'
# Query DSL — the checkout ERRORs from the last hour that mention "timeout"
POST logs-checkout-*/_search
{
  "query": {
    "bool": {
      "must":   [ { "match": { "log_message": "timeout" } } ],
      "filter": [
        { "term":  { "level": "ERROR" } },
        { "range": { "@timestamp": { "gte": "now-1h" } } }
      ]
    }
  }
}

# the same question, as KQL, typed straight into Kibana's Discover search bar
service:checkout and level:ERROR and log_message:"timeout"

Snapshots are how data leaves the cluster at all — for backup, and for the frozen tier's searchable snapshots above. Register a repository once, then snapshot on a schedule (Kibana's Snapshot Lifecycle Management, SLM, automates this the same way ILM automates tier movement):

# PUT _snapshot/logs-backups
{ "type": "s3", "settings": { "bucket": "acme-es-snapshots", "region": "us-east-1" } }

# PUT _snapshot/logs-backups/2026-08-16
# POST _snapshot/logs-backups/2026-08-16/_restore

Gotchas and failure modes — why log volume breaks it before query complexity does

☺ Like you're 10: A slow, complicated question rarely knocks the librarian over — but ten times the usual number of trucks showing up overnight absolutely will, and it happens quietly, not with a crash.

Nearly every serious ELK outage traces back to the same root cause: something upstream — a bug left in DEBUG logging, a traffic spike, a retry loop gone noisy — multiplies log volume far faster than anyone budgeted disk or heap for, and the stack degrades or stops accepting writes long before anyone has written a query complicated enough to be the actual problem.

Disk-based shard allocation watermarks: the silent ingestion stop

Elasticsearch protects itself from filling a node's disk with default watermark thresholds: at 85% used, the node stops receiving new shards; at 90%, shards actively relocate away from it; at 95% — the flood-stage watermark — every index with a shard on that node is forced read-only, and every write to it is rejected. This is, by a wide margin, the single most common "why did our logs just stop appearing" incident: nothing crashes, no alert necessarily fires on the application side, ingestion simply stops the instant a hot-tier node crosses 95% disk, exactly when a volume spike is already underway and logs matter most. Freeing disk space lets the watermark clear on its own in current versions, but under incident pressure most operators still explicitly unset index.blocks.read_only_allow_delete themselves — shown in the commands above — rather than wait and hope it clears in time.

⚠ The read-only block is per-index, and it doesn't discriminate

When flood-stage trips, every index with a shard on the affected node goes read-only — not just the noisy one that caused the disk pressure. A single misbehaving service can silently stop logging for the entire fleet sharing that hot tier, which is exactly why hot-tier capacity planning and per-service log-volume alerting belong together, not as separate concerns.

Mapping explosion

Dynamic mapping — letting Elasticsearch infer a field's type from the first document it sees — is convenient until logs contain arbitrary, highly variable JSON (a raw error object, a user-supplied payload logged verbatim). Every previously-unseen field name creates a new mapping entry, and Elasticsearch enforces a default cap of 1000 fields per index for exactly this reason; past it, indexing starts failing outright. Cluster state, which includes every index's full mapping, is held in memory and broadcast to every node on every change — so a mapping that grows unbounded doesn't just risk hitting the field limit, it slows the whole cluster down before it gets there. The fix is a strict mapping wherever the field set is knowable in advance, and "dynamic": "strict" (rejecting unmapped fields outright) or "dynamic": false (accepting but not indexing them) wherever it isn't.

Shard sizing: oversharding and undersharding

Every shard is a separate Lucene index with its own file handles, memory overhead, and per-shard cost during a cluster state update or a rebalance — a widely cited rule of thumb keeps shard sizes in roughly the 10–50GB range for logs and caps shard count well below 20 per GB of heap on a node. Oversharding (too many small shards) wastes overhead on bookkeeping instead of data. Undersharding (too few, oversized shards) makes recovery and rebalancing slow, and concentrates query and indexing load onto fewer nodes than the cluster could otherwise spread it across. ILM's rollover action, sized correctly against real ingest volume, is the practical mechanism that keeps shard size in the healthy range automatically instead of as a one-time guess made on day one and never revisited.

JVM heap, GC pauses, and the 32GB ceiling

Elasticsearch runs on the JVM, and its guidance is specific: allocate roughly 50% of a node's available RAM to heap, and never set it above approximately 30–32GB regardless of how much RAM the node has. Past that boundary, the JVM loses the ability to use compressed ordinary object pointers, and the larger heap ends up storing fewer usable objects than a smaller one just under the line — a genuinely counterintuitive result that catches people sizing nodes for the first time. Under a sustained volume spike, heap pressure and garbage-collection pauses are the mechanism that actually takes a node down: a long enough GC pause can make a node miss cluster-state heartbeats and get ejected from the cluster, turning a log-volume problem into a cluster-stability incident — again, well before anyone's run a query complex enough to be blamed.

Logstash grok performance and backpressure

A grok filter compiles down to a regular expression, and a poorly written pattern — an unanchored .*, deeply nested optional groups — can hit catastrophic backtracking on a single unusual log line, stalling that pipeline worker thread. Because Logstash's internal queue is bounded, a stalled filter stage backs up into the input stage, which backs up into Beats' own outbound queue, which can eventually pause Filebeat's own file-tailing — turning one slow regex into a growing, unshipped backlog sitting on disk across the fleet. dissect avoids this entirely for genuinely fixed-delimiter formats, since it splits on literal positions rather than evaluating a regex engine at all; the standard practice is dissect first wherever the format is truly fixed, grok only for the genuinely variable remainder.

Alternatives and when to choose it

☺ Like you're 10: Other tools track logs too — some index everything the way Elasticsearch does and cost more for it, some only index a little and search the rest on the fly, which is cheaper but slower per query.

The real fork in the road is whether you index the full text of every log line at all. Elasticsearch does, which is what makes ad hoc full-text search fast — and what makes storage the thing you have to actively manage with ILM. Several real alternatives take a deliberately different trade.

OptionModelBest whenCosts you
Elastic StackFull-text inverted index over every log fieldYou need fast, arbitrary full-text search — "find every line mentioning X" across any field, unplanned in advanceThe most storage- and heap-hungry option here; ILM discipline is mandatory, not optional, at real volume
LokiIndexes only a small set of labels; log content itself lives compressed and unindexed in object storage, scanned at query timeCost matters more than query speed, and queries can usually start from a known label (service, namespace, pod)Full-text search across unindexed content is a slow grep-at-query-time operation, not an instant index lookup
OpenSearchThe Apache-2.0 fork of pre-2021 Elasticsearch/Kibana, evolving independently sinceLicensing terms are a hard requirement and Apache 2.0 specifically matters to your organizationDiverging feature set and compatibility from Elastic's own roadmap going forward — verify per feature, don't assume parity
SplunkMature commercial platform, its own SPL query language, strong enterprise toolingBudget is available and the operational maturity and support contract are worth paying for directlyTypically the most expensive option here, usually licensed by daily ingest volume
Cloud-native (CloudWatch Logs Insights, Cloud Logging, Azure Monitor Logs)Bundled with the cloud providerSingle-cloud estate, no appetite to run or size a logging cluster yourselvesWeak or absent once you're multi-cloud; query languages and retention controls are provider-specific

Most mature SRE organizations don't pick exactly one forever — it's common to see Loki carrying the high-volume, low-cardinality bulk of routine service logs at low cost, with the Elastic Stack (or a smaller, deliberately scoped slice of it) reserved for the logs that genuinely need full-text search: security and audit trails, or a small number of services where "search everything" really is the requirement. Deciding which category a given service's logs fall into, before the ingest pipeline is built rather than after the storage bill arrives, is most of the architecture decision.

Where the Elastic Stack fits in the SREF blueprint

☺ Like you're 10: The exam wants you to recognize "this is the centralized-logging category" from a description, not memorize a specific ILM policy's JSON.

The DevOps Institute SRE Foundation (SREF) exam is closed-book and tests tool categories over vendor trivia, per SRE Tools & Automation — the Elastic Stack is the representative example for centralized log aggregation and search, alongside Loki as the lower-cost alternative model. Monitoring & Service Level Indicators is where the underlying practice actually gets tested: know that logs are one of the three observability pillars alongside metrics and traces, covered together in monitoring & observability, and that "index lifecycle management" as a concept — automatically aging data through cheaper tiers to control cost — recurs across nearly every stateful monitoring tool this course covers, not just this one. The specific grok syntax and ILM JSON on this page are for the job, not the exam.

🐘 Ellie's workshop · 20 min

On a throwaway single-node Elasticsearch + Kibana stack (Docker is the fastest path): create the index template and ILM policy above, then write ten documents to logs-checkout-000001 by hand with curl, varying the level field. Search for them from Kibana's Dev Tools console using the Query DSL example above, then again from Discover using the equivalent KQL. Now break the mapping on purpose: write one more document where service is a nested JSON object instead of a plain string, and read the mapping-conflict error that comes back. Finally, fill the node's disk artificially (a large dummy file works) until _cluster/health shows a yellow or red status from allocation issues, watch the index go read-only, delete the dummy file, and confirm whether the block clears itself or needs the manual unset command above. That last step is the gotcha section, felt instead of just read.

🎬 At the Reliability Watch
🦊

Foxy: Checkout's logs just vanished from Kibana. No alert fired. Nothing crashed. They're just... gone.

🐘

Ellie the Elephant: Check disk on the hot-tier nodes before anything else. If we're past 95% used, Elasticsearch marks every index on that node read-only on its own — on purpose, to protect itself.

🦫

Benny the Beaver: We're at 96%. Someone shipped a change that logs the full request body on every retry, and checkout retries a lot right now.

🐢

Timmy the Turtle: So the guardrail worked exactly as designed — it just designed itself to look like an outage from the outside. Free the disk, then clear the read-only block explicitly. Don't assume it clears itself mid-incident.

🦥

Sol the Sloth: While you free space — I make it ILM's warm phase hasn't rolled anything off the hot tier in nine days. That's not this incident's cause, but it's why we had less headroom than we should have going in.

🦊

Foxy: Two fixes, then. Roll back the request-body logging, and find out why warm-phase rollover stalled.

🐘

Ellie the Elephant: Both go in the postmortem's action items. Neither one is "add more disk and hope" — that's the same incident again in three months, just slower to arrive.

✓ Checkpoint

1. Name the four pieces of the Elastic Stack and which single one is actually load-bearing. 2. Where can log parsing happen, and what's the tradeoff between doing it in Logstash versus an Elasticsearch ingest pipeline? 3. What is the flood-stage disk watermark, what does it do to an index, and why is it usually the true cause of an "our logs just stopped" incident rather than a crash? 4. What is mapping explosion, what causes it, and what's the fix? 5. What does an ILM policy actually automate, and name the five phases in order. 6. In one sentence, what's the structural tradeoff between the Elastic Stack and Loki?

Check your answers
  1. Elasticsearch (the search/storage engine), Logstash (a general-purpose parsing/enrichment pipeline), Beats (lightweight per-purpose shippers), and Kibana (the query and visualization UI). Only Elasticsearch is load-bearing — Logstash and Beats are ingest paths that can be bypassed with Elasticsearch's own ingest pipelines, and Kibana can be bypassed by querying the REST API directly.
  2. In Beats (light, module-based only), in Logstash (heaviest, most capable — grok, dissect, geoip, arbitrary plugins, its own JVM process), or inside Elasticsearch's own ingest pipelines (the same class of processors, running on the node handling the write, with no separate process to run). Logstash earns its overhead for multi-input fan-in or conditional routing; a simple, well-structured format often doesn't need it at all.
  3. At 95% disk usage on a node, Elasticsearch forces every index with a shard on that node into read-only mode, rejecting new writes. It's usually the true cause because nothing crashes and no application-side alert necessarily fires — ingestion simply stops the instant the watermark trips, which is exactly when a volume spike already underway makes logs matter most.
  4. Dynamic mapping inferring a new field type for every previously-unseen field name in highly variable JSON, until an index approaches or exceeds the default 1000-field cap and bloats the in-memory cluster state shared across every node. The fix is an explicit mapping wherever the field set is known, and "dynamic": "strict" or "dynamic": false wherever it isn't.
  5. It automatically moves an index or data stream through storage tiers as it ages, without manual intervention. In order: hot (actively written and queried, fastest storage), warm (read-mostly, force-merged and shrunk), cold (rarely queried, cheaper storage), frozen (cheapest searchable tier, backed by object storage via searchable snapshots), delete (removed once past retention).
  6. The Elastic Stack fully indexes log content for fast, arbitrary full-text search at higher storage and heap cost; Loki indexes only a small set of labels and leaves content unindexed and cheap to store, at the cost of slower, grep-like search when a query can't start from a known label.