Neural Mastery
← Practice
Read the Logs Before the Codemedium

Read the Logs Before the Code

medium Specify, Verify, Debug 20–25 min

Standard library only · runs in your browser

At 14:03 checkout starts failing. The dashboard is red with checkout errors, and the obvious next step is to open checkout's code. The logs from three services say something else, if you read them in the right order.

Task

Each log line looks like this:

2026-10-20T14:03:12Z level=ERROR svc=checkout req=r-1043 msg=payment_failed status=500

a timestamp, then key=value fields. The lines come from three services, merged as they arrived, so they are not in time order.

Write first_failure(lines). It returns the earliest ERROR by time:

{"service": "payments-db", "request_id": "r-1040", "time": "2026-10-20T14:03:01Z"}
  • time is the timestamp string exactly as it appears in the line.
  • Ignore lines whose timestamp doesn't parse, and lines without level=ERROR or without svc.
  • If two errors share the earliest time, return the one that appears first in lines.
  • Return None when there are no errors.

Function Signature

first_failure(lines: list[str]) -> dict | None

Examples

Example 1: The 14:03 checkout incident
Input: lines = ['2026-10-20T14:03:12Z level=ERROR svc=checkout req=r-1043 msg=payment_failed status=500', '2026-10-20T14:03:12Z level=ERROR svc=checkout req=r-1044 msg=payment_failed status=500', '2026-10-20T14:02:58Z level=WARN svc=payments-db req=- msg=slow_query ms=2400', '2026-10-20T14:03:05Z level=ERROR svc=payments req=r-1041 msg=db_timeout after_ms=3000', '2026-10-20T14:03:01Z level=ERROR svc=payments-db req=r-1040 msg=connection_pool_exhausted', '2026-10-20T14:03:13Z level=ERROR svc=checkout req=r-1045 msg=payment_failed status=500', '2026-10-20T14:03:06Z level=INFO svc=payments req=r-1046 msg=retrying attempt=2', 'payments-db: pool size 20, in use 20', '2026-10-20T14:03:14Z level=ERROR svc=checkout req=r-1046 msg=payment_failed status=500']
Output: {'service': 'payments-db', 'request_id': 'r-1040', 'time': '2026-10-20T14:03:01Z'}
Explanation: Checkout logs the most errors. payments-db failed first.
Example 2: A quiet minute: warnings only
Input: lines = ['2026-10-20T09:00:00Z level=WARN svc=search req=r-1 msg=slow', '2026-10-20T09:00:01Z level=INFO svc=search req=r-2 msg=ok']
Output: None
Example 3: Two services, delivered out of order
Input: lines = ['2026-10-20T10:00:09Z level=ERROR svc=api req=r-9 msg=upstream_error', '2026-10-20T10:00:02Z level=ERROR svc=cache req=r-7 msg=evicted_during_read']
Output: {'service': 'cache', 'request_id': 'r-7', 'time': '2026-10-20T10:00:02Z'}

Constraints

  • Compare times as times, not strings: some services log with a UTC offset (+02:00) instead of Z.
  • A line that doesn't parse must be skipped, not crash the function.
  • Standard library only: `datetime` is imported.
Python3Saved ✓
import json
import math
import re
from datetime import date, datetime, timedelta


def first_failure(lines):
"""The earliest ERROR by time: {"service", "request_id", "time"}, or None."""
# Your code here
pass

Case 1: The 14:03 checkout incident
Input: lines = ['2026-10-20T14:03:12Z level=ERROR svc=checkout req=r-1043 msg=payment_failed status=500', '2026-10-20T14:03:12Z level=ERROR svc=checkout req=r-1044 msg=payment_failed status=500', '2026-10-20T14:02:58Z level=WARN svc=payments-db req=- msg=slow_query ms=2400', '2026-10-20T14:03:05Z level=ERROR svc=payments req=r-1041 msg=db_timeout after_ms=3000', '2026-10-20T14:03:01Z level=ERROR svc=payments-db req=r-1040 msg=connection_pool_exhausted', '2026-10-20T14:03:13Z level=ERROR svc=checkout req=r-1045 msg=payment_failed status=500', '2026-10-20T14:03:06Z level=INFO svc=payments req=r-1046 msg=retrying attempt=2', 'payments-db: pool size 20, in use 20', '2026-10-20T14:03:14Z level=ERROR svc=checkout req=r-1046 msg=payment_failed status=500']
Expected: {'service': 'payments-db', 'request_id': 'r-1040', 'time': '2026-10-20T14:03:01Z'}
Case 2: A quiet minute: warnings only
Input: lines = ['2026-10-20T09:00:00Z level=WARN svc=search req=r-1 msg=slow', '2026-10-20T09:00:01Z level=INFO svc=search req=r-2 msg=ok']
Expected: None
Case 3: Two services, delivered out of order
Input: lines = ['2026-10-20T10:00:09Z level=ERROR svc=api req=r-9 msg=upstream_error', '2026-10-20T10:00:02Z level=ERROR svc=cache req=r-7 msg=evicted_during_read']
Expected: {'service': 'cache', 'request_id': 'r-7', 'time': '2026-10-20T10:00:02Z'}