Stage 7 · Master
Incident Response With AI
Automated Timeline Generation
Reconstructing the sequence of events from chat, alerts, and deploys.
Why Timelines Matter
A timeline is the backbone of a postmortem. It answers: what happened, when, and in what order. Manually reconstructing a timeline from Slack messages, alert logs, and deploy records is tedious. An automated timeline generator does this in seconds.
Data Sources
- Slack incident channel messages with timestamps.
- PagerDuty alert and acknowledgment timestamps.
- Deploy pipeline records with commit hashes and timestamps.
- Metric dashboards showing when thresholds were crossed.
- Change management records for config changes.
Extracting Events
def extract_events_from_chat(messages):
"""Use an LLM to extract key events from incident chat."""
conversation = "\n".join([
f"[{m['timestamp']}] {m['user']}: {m['text']}"
for m in messages
])
response = openai.ChatCompletion.create(
model="gpt-4",
temperature=0.0,
messages=[
{
"role": "system",
"content": """Extract key events from this incident channel.
Return JSON array of events, each with:
- timestamp: ISO format
- event_type: one of [alert, investigation, action, observation, decision]
- description: what happened
- actor: who did it (or "system" for automated events)
- impact: effect on the system (if any)
Focus on factual events, not opinions or speculation."""
},
{"role": "user", "content": conversation}
]
)
return json.loads(response["choices"][0]["message"]["content"])The LLM extracts structured events from unstructured chat, separating facts from speculation.
Correlating Events
def merge_timeline(chat_events, alert_events, deploy_events):
"""Merge events from multiple sources into a single timeline."""
all_events = []
for e in chat_events:
all_events.append({**e, "source": "chat"})
for e in alert_events:
all_events.append({
"timestamp": e["created_at"],
"event_type": "alert",
"description": f"Alert: {e['name']} - {e['description']}",
"actor": "system",
"source": "pagerduty"
})
for e in deploy_events:
all_events.append({
"timestamp": e["deployed_at"],
"event_type": "deploy",
"description": f"Deploy: {e['service']} {e['version']}",
"actor": e["deployer"],
"source": "deploy_pipeline"
})
# Sort by timestamp
all_events.sort(key=lambda x: x["timestamp"])
# Deduplicate similar events
return deduplicate_events(all_events)Merging multiple sources gives a complete picture. Alerts show system state. Chat shows human actions. Deploys show changes.
Timeline Formatting
def format_timeline(events):
"""Format events into a readable timeline."""
lines = ["## Incident Timeline\n"]
current_date = None
for event in events:
ts = datetime.fromisoformat(event["timestamp"])
if ts.date() != current_date:
current_date = ts.date()
lines.append(f"\n### {current_date}\n")
time_str = ts.strftime("%H:%M:%S")
emoji = {"alert": "🚨", "action": "⚡", "observation": "👁️",
"decision": "📋", "deploy": "🚀"}.get(event["event_type"], "•")
lines.append(f"**{time_str}** {emoji} {event['description']}")
if event.get("actor") and event["actor"] != "system":
lines.append(f" — _{event['actor']}_")
return "\n".join(lines)The formatted timeline is ready to paste into a postmortem document.
Store timeline format templates for different incident types. A database incident timeline emphasizes queries and locks. A network incident emphasizes connectivity and DNS.
Mark this lesson complete to store local progress and unlock a cleaner resume path the next time you visit.