LearnDevOps
DevOps08. Observability·EXPERT·5 min read

27. Logging

Logging

TL;DR

  • Logging backends fall into two indexing models: full-text (Elasticsearch/OpenSearch) and metadata-label-only (Loki) — the choice is a permanent trade-off between search power and operational cost.
  • Structuring logs at collection time (Fluent Bit) shifts parsing cost from every query to once, at ingestion.
  • Log correlation via a shared trace/request ID is what makes debugging a multi-service request tractable.
  • “Log everything at DEBUG in production” is a cost problem and a signal-to-noise problem, not a free safety net.
  • Biggest trade-off: full-text indexing buys powerful free-text search at real storage/compute cost that requires active lifecycle management to stay bounded.

Core Concepts

Indexing models: Loki vs. full-text

Loki indexes only metadata labels (the same model Prometheus uses for metrics), not log line content. Queries filter by label first (fast, indexed), then grep the matching log content directly (not pre-indexed). This is cheap to store and operate at scale but slower for broad free-text search across large volumes. OpenSearch/Elasticsearch fully index log content itself, enabling rich, fast free-text search — at the cost of significantly higher storage and compute per byte ingested.

Structuring at collection time

Fluent Bit and similar log shippers/processors extract fields (status_code, duration_ms) from raw log lines during ingestion rather than leaving them as unstructured text to parse at query time. Every downstream query, dashboard, and alert can then filter/aggregate on those fields directly. Query-time regex parsing re-runs the same extraction cost on every single search instead of paying it once during ingestion.

Log correlation

Without a shared trace/request ID propagated across every service a request touches, reconstructing a distributed request’s behavior means manually correlating logs across separate streams by timestamp proximity — slow and error-prone. A propagated correlation ID (ideally the same trace ID OpenTelemetry generates) turns that into a single query filtered by one identifier, pulling every relevant log line from every service in one shot.

Index lifecycle management

Full-text indexing’s storage/compute cost requires active management at scale: rollover policies (create a new index at a size/time threshold), retention windows (delete or archive indices past a certain age), and tiered/cold storage for older indices. Without this, logging backend cost grows unbounded as volume grows.

Log volume and level discipline

Excessive log volume increases storage cost and ingestion/indexing load, and — separately — makes the relevant log line during an incident harder to find, buried in noise. Deliberate log-level and content discipline (log what’s diagnostically useful, at an appropriate level) improves both cost and incident-response speed.

Logs vs. Metrics vs. Traces

Aspect Logs Metrics Traces
Granularity Discrete event, per occurrence Aggregated numeric value over time Per-request timeline across services
Best for “What exactly happened” “Is the system healthy, trending” “Where did time go for this request”
Cardinality tolerance High Low (high cardinality is expensive) High
Storage cost driver Volume × retention × indexing model Series cardinality Span count × volume
Correlation mechanism Trace/correlation ID Labels Trace/span ID
Query pattern Full-text search or label filter + grep Aggregation/query language (PromQL) Timeline reconstruction from spans

Command / Configuration Reference

# fluent-bit.conf equivalent (YAML) — parse and structure at collection time
pipeline:
  inputs:
    - name: tail
      path: /var/log/app/*.log
  filters:
    - name: parser              # extracts structured fields from raw log lines
      match: app.*
      key_name: log
      parser: json
  outputs:
    - name: loki                # ships structured logs to Loki with labels
      match: app.*
      labels: job=app, env=prod
# LogQL (Loki query language) — label filter first, then content grep
{job="app", env="prod"} |= "error" | json | status_code >= 500
// Elasticsearch/OpenSearch Index Lifecycle Management (ILM) policy
{
  "policy": {
    "phases": {
      "hot":    { "actions": { "rollover": { "max_size": "50gb", "max_age": "1d" } } },
      "warm":   { "min_age": "7d", "actions": { "shrink": { "number_of_shards": 1 } } },
      "delete": { "min_age": "30d", "actions": { "delete": {} } }
    }
  }
}
# Propagate a correlation/trace ID through a request (shell example)
curl -H "traceparent: 00-$(uuidgen)-0000000000000001-01" https://service-b/api

Common Pitfalls

  • Pitfall: Migrating from Elasticsearch to Loki and hitting slow free-text search. Why: Loki indexes labels only, not log content, so unindexed content search is inherently slower. Fix: Understand the indexing trade-off before migrating; structure logs with rich labels to compensate.
  • Pitfall: Logging backend storage cost grows quietly for months. Why: No index lifecycle management (rollover/retention/tiering) configured. Fix: Set explicit ILM policies before volume grows unchecked.
  • Pitfall: Debugging a distributed request takes hours of manual timestamp correlation. Why: No shared correlation ID propagated across services. Fix: Propagate a trace/request ID (ideally shared with the tracing system) through every service boundary.
  • Pitfall: Production logs left at DEBUG level everywhere. Why: Treated as a free safety net with no downside. Fix: Apply deliberate log-level and content discipline; log what’s diagnostically useful, not everything.
  • Pitfall: Parsing log content at query time via regex. Why: Re-runs parsing cost on every query instead of once at ingestion. Fix: Structure and extract fields at collection time (Fluent Bit or equivalent).

Interview Questions

  • A team wants to migrate from Elasticsearch to Loki for cost reasons. What trade-off do you make sure they understand first? — Tests whether the indexing-model difference and its query-performance consequence is understood.
  • A distributed request across 5 services fails, and debugging it means manually correlating 5 separate log streams by timestamp. What’s missing, and how do you fix it? — Tests whether correlation ID propagation is the immediate diagnosis.
  • Why is “log everything at DEBUG in production, just in case” a bad practice beyond storage cost? — Tests whether the incident-response signal-to-noise argument is articulated, not just the cost argument.
  • When would you choose full-text indexing over label-based indexing for a logging backend? — Tests understanding of the search-power-versus-cost trade-off.
  • How would you design log structure to make future queries and alerts efficient? — Tests understanding of collection-time structuring versus query-time parsing.
🔒 Locked
Sign in and unlock the full syllabus to keep reading.
Sign in to continue
Knowledge check
5 scenario questions on this topic
Take the quiz →
Related in 08. Observability
23. Prometheus
EXPERT
24. Grafana
EXPERT
25. Grafana Alloy
EXPERT
26. OpenTelemetry
EXPERT