Project: web log parser
From: Wei Zhang, Operations
"Payments had a rough morning. Can you go through access.log and tell me which endpoints are failing and when? Each line is a timestamp, method, path, status code and duration. Some lines are broken (the rotation cut one, and one has no duration), so skip those but tell me how many.
Treat /api/orders/1043 and /api/orders/1077 as the same endpoint, and ignore query strings. A failure is any status of 500 or above."
Done looks like: a report dictionary with the two worst endpoints and the error rate per hour.
Logs are text, one event per line, and parsing them is a staple analyst task. This project uses a regular expression with groups to read each line, then the dictionary and sorting patterns from earlier units to summarize.
Real logs are messy. Some lines don't match the format; count and skip them rather than letting one bad line stop the run. Paths carry ids and query strings that make every request look unique until you normalize them.
Your variables carry from step to step. If a later step depends on a name from an earlier one, run the earlier step first, or use Show answer to catch up.
import re
LINE = re.compile(r"^(\S+) (GET|POST|PUT|DELETE) (\S+) (\d{3}) (\d+)ms$")
m = LINE.match("2026-03-02T10:05:03Z POST /api/payments 500 1530ms")
m.groups()
Out: ('2026-03-02T10:05:03Z', 'POST', '/api/payments', '500', '1530'). One group per field; numbers are still text.