Terminal.skills
Use Cases/Debug Production Incidents with AI Log Analysis

Debug Production Incidents with AI Log Analysis

Quickly identify root causes in production incidents by analyzing logs, correlating errors, and generating incident reports.

DevOps#logs#debugging#incident-response#observability#data-analysis
Works with:claude-codeopenai-codexgemini-clicursor
$

The Problem

Production incidents hit at the worst times. Engineers scramble through thousands of log lines across multiple services, grepping for patterns while Slack channels explode with "is the site down?" messages. Finding the root cause in a sea of cascading failures takes 30-60 minutes even for experienced engineers — and that's before writing the incident report that leadership expects by morning.

The real danger is cascading failures. One service goes down, which causes timeouts in three others, which triggers retries that make everything worse. By the time you open the logs, you're looking at 15 different error types across 6 services, and the original cause is buried under an avalanche of symptoms. The engineer's instinct is to fix the most visible error first — but visible errors are usually symptoms, not causes. Fixing symptoms while the root cause persists turns a 15-minute incident into a 2-hour whack-a-mole session.

The Solution

Using the log-analyzer skill to parse logs, build a timeline, and pinpoint the root cause, combined with data-analysis to correlate metrics and error rates, thousands of log lines collapse into a structured incident timeline that leads straight to the first failure. The cascade becomes visible, the root cause becomes obvious, and the fix becomes specific.

Step-by-Step Walkthrough

Here's how to go from "the site is down" to "here's the root cause and the fix" in under 15 minutes, using an actual incident that took down a checkout flow on a Monday afternoon.

Step 1: Feed in the Logs

Start with what you have — raw logs from the service that's screaming the loudest:

Analyze these application logs from the last 30 minutes. We're getting reports of failed checkouts. The logs are in /var/log/app/checkout-service.log

Don't pre-filter. Don't grep for a specific error you think might be the cause. The whole point is to let chronological analysis reveal the pattern rather than confirming your hypothesis.

No formatting, no pre-filtering. The entire log file goes in — megabytes of timestamps, request IDs, debug output, and error traces. Trying to grep for the "right" errors before understanding the incident is premature optimization — you don't know what's relevant yet, and pre-filtering based on assumptions is how engineers spend 30 minutes debugging the wrong service.

Step 2: Identify the Error Pattern

The logs get scanned chronologically — this is the critical part. Instead of grouping by error type (which is what most engineers do instinctively), the chronological scan reveals which errors came first. Errors get filtered, deduplicated, and grouped by type with timestamps:

Error TypeCountFirst SeenLast Seen
Redis ConnectionTimeout2,34114:02:0314:31:45
CartService NullPointer41214:02:0814:31:40
PaymentGateway 50318914:05:2214:31:42

Three observations from this table change everything about the debugging approach:

  1. Redis errors started first (14:02:03) — 5 seconds before cart failures, 3 minutes before payment failures. Chronological order reveals causation.
  2. Redis error count is 5x higher than other errors — it's not a secondary effect, it's the epicenter.
  3. All errors share the same time window — they started within 3 minutes of each other and are all still occurring. This is one incident with three symptoms, not three separate problems.

The first error in the timeline is the most important data point in incident response. Everything that follows is a consequence of that first failure.

Step 3: Correlate Across Services

One service's symptoms are another service's root cause. The checkout service logs show Redis timeouts, but the checkout service didn't cause the problem — Redis did. Follow the chain backward to the upstream system:

Now check the Redis server logs at /var/log/redis/redis-server.log for the same time window. Also check /var/log/redis/redis-sentinel.log if it exists.

The Redis server logs reveal what happened 5 seconds before the checkout errors started:

14:01:58.332 # WARNING: maxmemory reached, eviction policy: noeviction
14:01:58.333 # Client connection rejected: OOM command not allowed

Redis hit its 16GB memory limit at 14:01:58 with noeviction policy. This is the critical detail: unlike allkeys-lru (which evicts old keys to make room for new ones), noeviction simply rejects every new operation — reads and writes alike. It's the nuclear option. Every application that depends on Redis suddenly gets connection errors.

The cascade unfolded in three stages:

  1. Five seconds later, the checkout service couldn't read cart data — Redis ConnectionTimeout errors start at 14:02:03
  2. Cart lookups returned null, which the CartService didn't handle gracefully, throwing NullPointerExceptions — cart failures start at 14:02:08
  3. Three minutes later, orders were being submitted with empty cart data, and the payment gateway returned 503s because it couldn't process zero-dollar orders — payment failures start at 14:05:22

The entire cascade traces back to two lines in the Redis log. Every other error — all 2,942 of them across three services — is a symptom of this one event. An engineer grepping for PaymentGateway 503 would be looking at symptoms and never find the cause. An engineer starting with "what errored first?" finds it in seconds.

Step 4: Build the Incident Timeline

Build an incident timeline and recommend immediate fixes.

The timeline traces the cascade from root cause to customer impact:

TimeEventImpact
14:01:58Redis hit maxmemory limit (16GB), noeviction rejects all operationsNone yet
14:02:03Checkout service: first ConnectionTimeout to RedisCart reads fail
14:02:08Cart lookups return null, NullPointerException in CartServiceCart display broken
14:05:22Payment requests fail — orders submitted with empty cartsCheckout broken
14:12:00PagerDuty alert fires on error rate thresholdTeam notified
14:15:00On-call engineer opens investigationResponse begins

Two things stand out in this timeline. First, the 10-minute gap between the first error (14:02:03) and the PagerDuty alert (14:12:00) — that's 10 minutes of failed checkouts before anyone knew something was wrong. The alert threshold was set on error rate, and it took a few minutes for the rate to cross the threshold. A Redis memory utilization alert at 80% would have fired before any customer impact.

Second, the NullPointerException on the cart service is a code-level issue independent of Redis. The cart service should handle a Redis connection failure gracefully — return a cached response, show an error message, retry — not throw an unhandled exception. This is a resilience gap that will surface again the next time any dependency becomes unavailable.

Root cause: Redis instance reached its 16GB memory limit with noeviction policy, rejecting all new operations and cascading into checkout and payment failures.

Why it happened: Session keys were being created with application-level TTL management instead of Redis-native EXPIRE commands. The application was supposed to clean up expired sessions in a background job, but the job was silently failing due to an unrelated deployment change two weeks ago. Sessions accumulated until Redis hit its ceiling.

Immediate actions (do these now, in order):

  1. Flush expired session keys: redis-cli --scan --pattern "sess:*" | xargs redis-cli del — this frees 3GB immediately
  2. Increase Redis maxmemory from 16GB to 24GB — buys headroom while the permanent fix is implemented
  3. Restart checkout-service pods to clear stale connection pool entries that are still retrying dead connections
  4. Switch eviction policy to allkeys-lru — so if memory fills again, Redis evicts old keys instead of rejecting all operations

Follow-up actions (for the post-mortem):

  • Add Redis memory utilization alert at 80% capacity — this would have fired 2 hours before the incident
  • Add null-safety to CartService Redis calls — the NullPointerException is a resilience gap independent of Redis
  • Add circuit breaker to checkout flow so Redis failures return a user-friendly "please try again in a moment" instead of a 503
  • Fix the broken session cleanup job — the root root cause is that sessions accumulated for two weeks
  • Investigate what filled Redis to 16GB — set proper TTL on Redis keys directly, don't rely on application-level cleanup

Step 5: Analyze Error Rate Trends

Parse the error counts per minute from the logs and show me the trend. I need to confirm the incident is actually over after applying the fix.

The per-minute error distribution shows the sharp spike at 14:02, the sustained plateau while Redis was full, and the drop-off after the fix. This matters for two reasons: confirming the fix actually worked (error rate returns to pre-incident baseline), and ruling out that the incident entered a quieter phase before another wave. If errors are declining but not zero, the fix is partial — something else is still wrong.

The distribution also reveals whether retries are creating a secondary load spike. When Redis came back online, did 2,341 backed-up retry attempts all hit at once and cause a thundering herd? If the error count spikes again briefly right after the fix, that's the thundering herd — every connection in the pool simultaneously discovers Redis is available again and floods it with requests. The fix for next time is exponential backoff with jitter on the connection retry logic, so reconnection attempts spread out over a few seconds instead of all hitting at once.

The per-minute view also establishes the baseline for "normal." If pre-incident error rate was 2 per minute and post-fix it's 5 per minute, the incident isn't fully resolved — something else is still broken, or the fix created a new problem.

Real-World Example

Marta, a platform engineer at a 20-person fintech startup, gets paged at 2 AM because checkout success rates dropped from 99.2% to 34%. She opens her terminal and pastes the last 30 minutes of logs from three services.

The cascade traces in seconds: Redis OOM at 14:01:58, cart lookup failures 5 seconds later, payment timeouts 3 minutes after that. Instead of spending 40 minutes grepping through logs half-asleep, she has the root cause in under 2 minutes. What used to be "which of these 15 error types is the real problem?" becomes a clear timeline with one starting point.

She flushes 3GB of expired session keys and bumps Redis maxmemory from 16GB to 24GB. She restarts the checkout-service pods to clear the dead connection pool. Error rate drops back to baseline within 90 seconds. Incident resolved in 12 minutes instead of the usual 45 — and most of that time was spent connecting to the Redis host, not figuring out what was wrong.

The key difference isn't AI doing something magical — it's that chronological error correlation across multiple services happens in seconds instead of 20 minutes of manual grep-and-scroll. At 2 AM, that time savings is the difference between resolving in 15 minutes and thrashing for an hour.

The next morning, she generates a formal incident report from the timeline for the 10 AM post-mortem. The report includes the cascade diagram, the 10-minute alert gap, and four follow-up items: Redis memory alerts at 80%, allkeys-lru eviction policy, null-safety in CartService, and proper TTL on Redis session keys. The post-mortem takes 20 minutes instead of an hour because the timeline is already written, the root cause is identified, and nobody's arguing about what happened when. The follow-up items are actionable and specific — not "improve Redis monitoring" but "add memory utilization alert at 80% and switch eviction policy to allkeys-lru." Those two changes prevent this exact incident from recurring.