You can't fix what you can't see
The transition from "my pipeline runs" to "my pipeline is observable" is the same as the transition from a script to a system. Observability has three layers, and each one solves a different class of incident:
- Logs — what happened, in order, in human-readable form. Used for debugging.
- Metrics — counts, durations, rates emitted at every stage. Used for trends and alerting.
- The run log — a per-run record (start time, end time, success/failure, row counts in/out per stage, errors). Used for forensics and SLA tracking.
Structured logs are non-negotiable
Plain-text logs ('started extract') are fine for humans staring at a terminal. Production-grade logs are structured (key=value or JSON), so a log aggregator can index them, alert on patterns, and let you query across runs. The Python logging module gets you there with two lines of config and a habit of including the values that matter.