🔧
Code Snippet — August 1, 2026Named-Capture Regex for Parsing Log FormatsStop using numbered backreferences that break when formats change. Named captures
(?P...) give you
match.group("ip") instead of counting groups.
import re
# Apache Combined Log
COMBINED = re.compile(
r'(?P<ip>\S+)\s+(?P<ident>\S+)\s+(?P<user>\S+)\s+'
r'\[(?P<time>[^\]]+)\]\s+'
r'"(?P<method>\S+)\s+(?P<path>\S+)\s+(?P<proto>\S+)"\s+'
r'(?P<status>\d{3})\s+(?P<size>\S+)'
r'(?:\s+"(?P<referer>[^"]*)"\s+"(?P<ua>[^"]*)")?'
)
# Syslog RFC 3164
SYSLOG = re.compile(
r'(?P<month>\w{3})\s+(?P<day>\d{1,2})\s+(?P<time>\d{2}:\d{2}:\d{2})\s+'
r'(?P<host>\S+)\s+(?P<program>\S+?)(?:\[(?P<pid>\d+)\])?:\s+(?P<message>.*)'
)
# Kubernetes logs
K8S = re.compile(
r'(?P<ts>\d{4}-\d{2}-\d{2}T\S+Z)\s+(?P<stream>stdout|stderr)\s+(?P<flag>F|P)\s+(?P<message>.*)'
)
# Parse helper
def parse_line(pat, line):
m = pat.match(line)
return m.groupdict() if m else None
# Usage
r = parse_line(COMBINED, '10.0.0.1 - - [01/Aug/2026:12:00:00 +0000] "GET /api HTTP/1.1" 200 1234')
print(r["ip"], r["status"], r["path"])
# → 10.0.0.1 200 /api
Also in full snippet: Apache Common Log, Syslog RFC 5424 (with priority), Nginx upstream (with response time & host), JSON lines via
json.loads.
Pro tips:- Compile once with
re.compile(), reuse across millions of lines
- Use
match.groupdict() for a clean dict output
- Pipe to
csv.DictWriter for instant analysis
- Use
re.finditer() for multiple matches
- Use
re.VERBOSE for multi-line, commented patterns
💡
Bookmark this — when awk and cut can't handle the log format, named-capture regex gives you self-documenting patterns. These 7 patterns cover the most common log formats in production.