|
2 | 2 |
|
3 | 3 | This repository now hosts two related projects: |
4 | 4 |
|
5 | | -- codetracer-pure-python-recorder — the existing pure-Python prototype that records [CodeTracer](https://github.com/metacraft-labs/CodeTracer) traces using sys.settrace. |
6 | | -- codetracer-python-recorder — a new, Rust-backed Python extension module (PyO3) intended to provide a faster and more featureful recorder. |
| 5 | +- codetracer-pure-python-recorder — a pure-Python tracer that still mirrors the early prototype. |
| 6 | +- codetracer-python-recorder — a Rust-backed Python extension (PyO3 + maturin) with structured errors and tighter tooling. |
7 | 7 |
|
8 | | -> [!WARNING] |
9 | | -> Both projects are early-stage prototypes. Contributions and discussion are welcome! |
| 8 | +Both projects are still in motion. Expect breaking changes while we finish the error-handling rollout. |
| 9 | + |
| 10 | +### Structured errors (Rust-backed recorder) |
| 11 | + |
| 12 | +The Rust module wraps every failure in a `RecorderError` hierarchy that reaches Python with a stable `code`, a readable `kind`, and a `context` dict. |
| 13 | + |
| 14 | +- `UsageError` → bad input or calling pattern. Codes like `ERR_ALREADY_TRACING`. |
| 15 | +- `EnvironmentError` → IO or OS problems. Codes like `ERR_IO`. |
| 16 | +- `TargetError` → the traced program raised or refused inspection. Codes like `ERR_TRACE_INCOMPLETE`. |
| 17 | +- `InternalError` → a recorder bug or panic. Codes default to `ERR_UNKNOWN` unless classified. |
| 18 | + |
| 19 | +Quick catch example: |
| 20 | + |
| 21 | +```python |
| 22 | +from codetracer_python_recorder import RecorderError, start, stop |
| 23 | + |
| 24 | +try: |
| 25 | + session = start("/tmp/trace", format="json") |
| 26 | +except RecorderError as err: |
| 27 | + print(f"Recorder failed: {err.code}") |
| 28 | + for key, value in err.context.items(): |
| 29 | + print(f" {key}: {value}") |
| 30 | +else: |
| 31 | + try: |
| 32 | + ... # run work here |
| 33 | + finally: |
| 34 | + session.flush() |
| 35 | + stop() |
| 36 | +``` |
| 37 | + |
| 38 | +All subclasses carry the same attributes, so existing handlers can migrate by catching `RecorderError` once and branching on `err.code` if needed. |
| 39 | + |
| 40 | +### CLI exit behaviour and JSON trailers |
| 41 | + |
| 42 | +`python -m codetracer_python_recorder` returns: |
| 43 | + |
| 44 | +- `0` when tracing and the target script succeed. |
| 45 | +- The script's own exit code when it calls `sys.exit()`. |
| 46 | +- `1` when a `RecorderError` bubbles out of startup or shutdown. |
| 47 | +- `2` when the CLI arguments are incomplete. |
| 48 | + |
| 49 | +Pass `--codetracer-json-errors` (or set the policy via `configure_policy(json_errors=True)`) to stream a one-line JSON trailer on stderr. The payload includes `run_id`, `trace_id`, `error_code`, `error_kind`, `message`, and the `context` map so downstream tooling can log failures without scraping text. |
| 50 | + |
| 51 | +### Migration checklist for downstream tools |
| 52 | + |
| 53 | +- Catch `RecorderError` (or a subclass) instead of `RuntimeError`. |
| 54 | +- Switch any string matching over to `err.code` values like `ERR_TRACE_DIR_CONFLICT`. |
| 55 | +- Expect structured log lines (JSON) on stderr. Use the `error_code` field instead of parsing text. |
| 56 | +- Opt in to JSON trailers for machine parsing and keep human output short. |
| 57 | +- Update policy wiring to use `configure_policy` / `policy_snapshot()` rather than hand-rolled env parsing. |
| 58 | +- Read `docs/onboarding/error-handling.md` for detailed migration steps and assertion rules. |
| 59 | + |
| 60 | +### Logging defaults |
| 61 | + |
| 62 | +The recorder now installs a JSON logger on first import. Logs include `run_id`, optional `trace_id`, and an `error_code` field when set. |
| 63 | + |
| 64 | +- Control the log filter with `RUST_LOG=target=level` (standard env syntax). |
| 65 | +- Override from Python with `configure_policy(log_level="info")` or `log_file=...` for file output. |
| 66 | +- Metrics counters record dropped events, detach reasons, and caught panics; plug your own sink via the Rust API when embedding. |
10 | 67 |
|
11 | 68 | ### codetracer-pure-python-recorder |
12 | 69 |
|
@@ -64,7 +121,7 @@ RUST_LOG=codetracer_python_recorder=debug pytest \ |
64 | 121 | codetracer-python-recorder/tests/python/unit/test_backend_exceptions.py -q |
65 | 122 | ``` |
66 | 123 |
|
67 | | -Any filter accepted by `env_logger` works, so you can switch to |
| 124 | +Any filter accepted by `env_logger` still works, so you can switch to |
68 | 125 | `RUST_LOG=codetracer_python_recorder=info` or silence everything with |
69 | 126 | `RUST_LOG=off`. |
70 | 127 |
|
|
0 commit comments