{"id":"code-dev-python-regex-warn-error-lines","audience":"developers","category":"coding","track":"coding","technique":"constraints","title":"Write a Python log regex with exact group names","free":false,"task":"Your alerting script needs a compiled regex that matches only WARN and ERROR lines (INFO must not match). Use Python named groups exactly ts, level, worker and msg, anchor it with ^ and $, and write it as one line: LOG_RE = re.compile(r\"...\") with no flags. Exactly 1 code block with that single line, under 30 words of text.","materialLabel":"Sample log lines and the alert script (attached to your prompt automatically)","material":"# sample from /var/log/relay/worker.log (Relaybird job runner)\n2026-11-05T22:14:03Z INFO  worker-3 job=sync started\n2026-11-05T22:14:09Z WARN  worker-3 job=sync slow response from billing (2.3s)\n2026-11-05T22:15:41Z ERROR worker-1 job=export failed: timeout after 30s\n2026-11-05T22:15:42Z INFO  worker-1 job=export retry 1/3 scheduled\n2026-11-05T22:16:10Z ERROR worker-12 job=export failed: timeout after 30s\n2026-11-05T22:17:00Z DEBUG worker-2 heartbeat ok\n\n# alerts/scan.py (Python 3.12)\nimport re\nimport sys\n\nLOG_RE = ...  # TODO\n\ndef scan(lines):\n    for line in lines:\n        m = LOG_RE.match(line.rstrip(\"\\n\"))\n        if m:\n            yield m.group(\"ts\"), m.group(\"level\"), m.group(\"worker\"), m.group(\"msg\")\n\nif __name__ == \"__main__\":\n    for ts, level, worker, msg in scan(sys.stdin):\n        print(f\"[{level}] {worker} at {ts}: {msg}\")\n\n# Notes:\n# - levels are padded to 5 characters with spaces (INFO and WARN get one extra space)\n# - worker numbers go above 9 (worker-12)\n# - the alert must ignore INFO and DEBUG entirely","rules":[{"type":"codeBlocks","count":1},{"type":"maxCodeLines","max":1},{"type":"maxProseWords","max":30}],"mistakes":[{"title":"Matching every level","why":"A generic log regex matches INFO and DEBUG too, so the alert fires constantly.","fix":"Add: \"Only WARN or ERROR may match.\"","checks":["r1"]},{"title":"Wrong group names","why":"scan() reads ts, level, worker and msg by name; the AI picks timestamp or message.","fix":"Add: \"Named groups exactly ts, level, worker, msg.\"","checks":["r0"]},{"title":"A verbose multi-line pattern","why":"The AI likes re.VERBOSE with comments across many lines.","fix":"Add: \"One line: LOG_RE = re.compile(r\\\"...\\\"), no flags.\"","checks":["r2","maxCodeLines"]},{"title":"A tutorial and test code","why":"The AI explains each part and adds a test loop.","fix":"Add: \"One code block with the one line, one short sentence max.\"","checks":["codeBlocks","maxProseWords"]}],"promptHints":[{"label":"Limits the levels","patterns":["warn","error","not info","only (warn|error)"]},{"label":"Names the groups","patterns":["named group","\\?P<","ts, level"]},{"label":"Asks for one line","patterns":["one line","single line","re\\.compile"]},{"label":"Rules out flags","patterns":["no flags","verbose"]},{"label":"Asks for anchoring","patterns":["anchor","\\^"]}],"hint":"The code that uses the regex reads groups by name and only wants some levels. Tell the AI the names, the levels and exactly what line to hand back.","rubricLabels":["Uses Python named groups exactly (?P<ts>...), (?P<level>...), (?P<worker>...) and (?P<msg>...)","The level group only allows WARN or ERROR (e.g. (?P<level>WARN|ERROR)), the pattern handles the padding spaces after the level and worker numbers above 9, and it is anchored with ^ and $","It is a single line LOG_RE = re.compile(r\"...\") using a raw string and no flags or re.VERBOSE"]}