The incident was not a logging problem

At 18:07, during another evening load-shedding cycle, the checkout team saw a familiar pattern: API latency climbing, payment retries increasing, and a flood of “connection reset” messages from a Johannesburg service. The first dashboard suggested a database problem.…

The incident was not a logging problem

Advanced Log Intelligence and Correlation Systems: From Noisy Events to Faster Incident Decisions

At 18:07, during another evening load-shedding cycle, the checkout team saw a familiar pattern: API latency climbing, payment retries increasing, and a flood of “connection reset” messages from a Johannesburg service. The first dashboard suggested a database problem. The logs suggested three different problems. The trace showed one overloaded dependency in eu-west-1.

This is where Advanced Log Intelligence and Correlation Systems earn their keep. They do not merely search larger volumes of text. They connect logs, metrics and traces around the same service, request and failure, so an engineer can distinguish a local power event from a regional network delay, a genuine application fault or an alerting artefact.

The incident was not a logging problem

The application was running across a small on-premises cluster in Johannesburg and cloud workloads in Europe. Node exporters reported a brief rise in CPU steal time. Prometheus showed elevated request duration. Loki contained thousands of retry messages, but their labels were limited to app, namespace and level. Tempo had the useful evidence: the slow spans were concentrated around an external fraud-scoring call, with a noticeably longer network leg to eu-west.

Without a shared correlation key, those signals remained separate tabs in separate mental models. Engineers searched timestamps, guessed at offsets and paged the network team. With a consistent trace_id, span_id, service name and deployment identifier, the path from symptom to cause became considerably shorter.

The practical lesson is uncomfortable: a centralised log store does not automatically create intelligence. Correlation must be designed into the telemetry contract, collection pipeline and query model.

Advanced Log Intelligence and Correlation Systems start with identity

Every event should answer four questions:

  • Which service and environment produced it?
  • Which deployment, pod or host was involved?
  • Which request, trace or span does it belong to?
  • When did the event occur, and when was it observed?

OpenTelemetry provides a useful common vocabulary for these fields. Logs can be sent through Grafana Alloy or an OpenTelemetry Collector, while Prometheus-compatible metrics continue to flow into Mimir and traces into Tempo. Loki can receive OTLP logs and retain attributes as structured metadata rather than forcing every value into an index label. Structured metadata is particularly useful for high-cardinality fields such as trace IDs, customer-safe request identifiers and cloud availability zones.

Do not turn every field into a Loki label. A label such as trace_id, user_id or request_id can create a stream explosion and inflate operational cost. Keep low-cardinality routing dimensions in labels, and place investigative context in structured metadata or the log body.

limits_config:
  allow_structured_metadata: true

common:
  replication_factor: 3

In Loki 3.0 and later, structured metadata is enabled by default in the relevant configurations, but explicit configuration remains valuable when validating an estate or migrating older clusters. The exact limits for metadata size and entry count should also be tested against the application’s real payloads.

Make the telemetry contract boring and enforceable

A useful log event is structured, stable and deliberately uninteresting. JSON is preferable to a sentence that changes whenever a developer improves its wording.

{
  "timestamp": "2026-09-26T16:08:12.481Z",
  "severity": "WARN",
  "service.name": "checkout-api",
  "deployment.environment": "production",
  "cloud.region": "af-south-1",
  "event.name": "dependency_retry",
  "dependency.name": "fraud-score",
  "retry_count": 2,
  "trace_id": "4bf92f3577b34da6a3ce929d0e0e4736",
  "span_id": "00f067aa0ba902b7"
}

Use semantic names consistently. service.name should not become service in one collector and app_name in another. Normalisation at the edge prevents a correlation dashboard from becoming a translation exercise.

Redaction belongs in the collection pipeline, not in a dashboard query. POPIA considerations are especially important when logs cross borders or are retained in a shared cloud tenancy. Remove identity numbers, access tokens, payment details and unnecessary personal information before the event reaches Loki. A trace ID is normally a better investigation handle than an email address or account number.

For teams under ZAR cloud-cost pressure, sample successful traces aggressively while retaining error traces and representative slow requests. Keep enough logs to explain failures, but do not use “store everything forever” as a substitute for deciding what an incident requires.

Correlate from the metric that raised the alarm

Metrics should identify where to look; logs and traces should explain what happened. A Prometheus or Mimir alert might identify a latency burn, but it should carry the same service and environment dimensions used by Loki and Tempo.

histogram_quantile(
  0.99,
  sum by (le, service, environment) (
    rate(http_request_duration_seconds_bucket{
      service="checkout-api",
      environment="production"
    }[5m])
  )
) > 1.5

In practice, the alert should link an engineer to a dashboard containing:

  • The affected service and deployment.
  • Request rate, error rate and latency from Prometheus or Mimir.
  • Loki queries filtered by service, environment and time window.
  • Tempo traces for failed or unusually slow requests.
  • Dependency and region breakdowns, including eu-west latency.

Grafana makes this workflow practical through data-source links, exemplars and trace-to-logs navigation. A span can lead to matching Loki records, while a metric exemplar can lead to the trace behind a latency spike. That matters during an outage: engineers should not have to copy a timestamp between tools and manually compensate for clock drift.

A representative LogQL query might look like this:

{service_name="checkout-api", environment="production"}
  | json
  | event_name="dependency_retry"
  | dependency_name="fraud-score"
  | line_format "{{.timestamp}} {{.trace_id}} retry={{.retry_count}}"

Keep queries selective. Start with indexed dimensions, then parse JSON and filter fields. Parsing the entire historical firehose before narrowing the stream is an easy way to make a shared Loki cluster feel broken.

Use traces to test the story told by logs

Logs often describe intent: “request sent”, “retrying”, “circuit opened”. Traces describe timing and causality. When the two disagree, the trace usually reveals whether the log was emitted before a queue delay, after a timeout or on a different attempt than the one an engineer is examining.

Configure bidirectional navigation between Tempo and Loki. A span should expose the relevant logs using its trace and span identifiers, while a log line should open the corresponding trace. Allow a small start and end time shift because collection, batching and clock synchronisation introduce slight differences.

Tempo also supports the reverse journey from metrics through exemplars. A latency point in Mimir can therefore lead to a trace, and the trace can lead to the exact logs emitted by the affected request. This three-step path is more reliable than searching for “timeout” across every service.

Design for South African failure modes, not ideal networks

Load shedding complicates alerting. A power event can restart nodes, interrupt exporters and delay log delivery without indicating an application defect. Alert rules should distinguish “no data” from “healthy”, and dashboards should show collector lag, node uptime and queue depth alongside service errors.

Last-mile instability creates another trap. If a branch application cannot reach the central observability endpoint, the absence of logs is not evidence that the application is quiet. Local buffering, bounded retry queues and an explicit data-loss metric are more useful than an unbounded agent queue that consumes the remaining disk.

For hybrid estates, preserve the original event timestamp and add collection time. The difference between them exposes transport delay. In a Johannesburg-to-Europe deployment, that delay can be the difference between an application incident and an observability pipeline incident.

Use recording rules in Mimir for expensive, frequently viewed aggregations. Use retention tiers for logs and traces. Keep incident-relevant data searchable for long enough to support post-incident review, but do not retain sensitive raw records indefinitely merely because storage is cheap in one region