Adds reusable, secret-safe structured-logging helpers and instruments get_issue so nullable-field parsing (the class of failure behind #13) is diagnosable.
Helpers (logging_utils)
log_event(logger, level, event, **context) — emit a named event with a context mapping; keys in SENSITIVE_CONTEXT_KEYS (token, authorization, password, …) are masked as ***.
log_nullable_field(logger, event, field, value) — record whether a parsed field is None plus its runtime type, without dumping contents.
sanitize_context(...) — shared masking primitive.
The JSON formatter now serializes a record's context into the payload.
Instrumentation
get_issue_tool emits get_issue.start, get_issue.payload_shape, and get_issue.field_check (labels/assignees/user) at DEBUG. Silent unless LOG_LEVEL=DEBUG.
Scope note
log_exception from the issue's suggestion was intentionally omitted: logging an exception message conflicts with the project's "no exception-detail leakage" posture, so only the exception type is ever logged (unchanged behaviour).
Tests & docs
New tests/test_logging_utils.py: helpers, masking, formatter context, and the get_issue instrumentation.
docs/observability.md documents the pattern and its reuse for other parsing-heavy endpoints.
Closes #14.
Adds reusable, secret-safe structured-logging helpers and instruments `get_issue` so nullable-field parsing (the class of failure behind #13) is diagnosable.
## Helpers (`logging_utils`)
- `log_event(logger, level, event, **context)` — emit a named event with a `context` mapping; keys in `SENSITIVE_CONTEXT_KEYS` (`token`, `authorization`, `password`, …) are masked as `***`.
- `log_nullable_field(logger, event, field, value)` — record whether a parsed field is `None` plus its runtime type, without dumping contents.
- `sanitize_context(...)` — shared masking primitive.
- The JSON formatter now serializes a record's `context` into the payload.
## Instrumentation
- `get_issue_tool` emits `get_issue.start`, `get_issue.payload_shape`, and `get_issue.field_check` (labels/assignees/user) at `DEBUG`. Silent unless `LOG_LEVEL=DEBUG`.
## Scope note
`log_exception` from the issue's suggestion was intentionally omitted: logging an exception *message* conflicts with the project's "no exception-detail leakage" posture, so only the exception *type* is ever logged (unchanged behaviour).
## Tests & docs
- New `tests/test_logging_utils.py`: helpers, masking, formatter context, and the `get_issue` instrumentation.
- `docs/observability.md` documents the pattern and its reuse for other parsing-heavy endpoints.
Adds reusable, secret-safe logging helpers to `logging_utils`:
- `log_event(logger, level, event, **context)` emits a named event with a
sanitized `context` mapping (sensitive keys masked as `***`).
- `log_nullable_field(...)` records whether a parsed field is None plus its
runtime type, without dumping its contents.
- `sanitize_context(...)` is the shared masking primitive.
The JSON formatter now serializes a record's `context` into the payload.
`get_issue_tool` is instrumented at DEBUG (`get_issue.start`,
`get_issue.payload_shape`, `get_issue.field_check` for labels/assignees/user)
so the nullable-field parsing that caused #13 is diagnosable going forward.
Adds tests for the helpers, the formatter, and the get_issue instrumentation,
and documents the pattern in docs/observability.md.
Every write tool's `except (Auth...)` re-raise and `except GiteaError ->
RuntimeError` wrapping was previously untested, leaving write_tools at 60%
coverage and the repo below the 80% gate. Adds parametrized error-path tests
for all 15 write tools (backend error wrapping + auth propagation), raising
write_tools coverage to 99% and total coverage above the gate.
Latte
merged commit 10a307ac02 into dev2026-06-22 15:09:59 +00:00
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Closes #14.
Adds reusable, secret-safe structured-logging helpers and instruments
get_issueso nullable-field parsing (the class of failure behind #13) is diagnosable.Helpers (
logging_utils)log_event(logger, level, event, **context)— emit a named event with acontextmapping; keys inSENSITIVE_CONTEXT_KEYS(token,authorization,password, …) are masked as***.log_nullable_field(logger, event, field, value)— record whether a parsed field isNoneplus its runtime type, without dumping contents.sanitize_context(...)— shared masking primitive.contextinto the payload.Instrumentation
get_issue_toolemitsget_issue.start,get_issue.payload_shape, andget_issue.field_check(labels/assignees/user) atDEBUG. Silent unlessLOG_LEVEL=DEBUG.Scope note
log_exceptionfrom the issue's suggestion was intentionally omitted: logging an exception message conflicts with the project's "no exception-detail leakage" posture, so only the exception type is ever logged (unchanged behaviour).Tests & docs
tests/test_logging_utils.py: helpers, masking, formatter context, and theget_issueinstrumentation.docs/observability.mddocuments the pattern and its reuse for other parsing-heavy endpoints.baacd9e9b5tof53e1a3a5a