Add sentry error reporting - #89
Conversation
Adds sentry-sdk ~=2.35 to pyproject.toml ahead of wiring up Sentry error reporting. It was previously present only transitively, via fastapi[standard] -> fastapi-cli -> fastapi-cloud-cli (sentry-sdk>=2.20.0), which resolved to 2.34.1; declaring it directly moves it to the latest 2.x (2.68.1). The <3.0 bound is deliberate: a break in error reporting is silent, so a 3.x migration should be a conscious change rather than something a routine lockfile refresh can do. Regenerates requirements.txt and requirements_dev.txt in a linux/amd64 container matching the Dockerfile base. Regenerating on macOS drops greenlet, because SQLAlchemy requires it on x86_64 and aarch64 but not on Apple Silicon's arm64, which loses the pin for the deployment platform. Corrects the pip-compile invocation recorded in the README for requirements.txt, notes that the two lockfiles take different flags, and documents that regeneration must happen on Linux.
Initialises the SDK in src/main.py before the application object is created. Optional by design: no DSN, a malformed DSN, or a test run leaves it uninitialised and the API unaffected. sentry.py is the only module importing sentry_sdk; application code reports errors by logging them, so the service can be replaced by editing one file. Withholds what the SDK would otherwise transmit: frame locals and request bodies (both carry bearer tokens, and bodies are sent on successful requests too), outgoing query strings (SuiteCRM record IDs), and the audit log entirely (its CRITICAL records contain the Authorization header). A failed startup is now logged rather than printed, so the failure that stops the service is reported too.
simon-20
left a comment
There was a problem hiding this comment.
Hi @arobson-ods,
This looks good.
I've marked as Request changes, but I really just have a question:
given that we're blanking outgoing query strings on the requests to SuiteCRM, should we also scrub the query strings from incoming requests? If so, then once that is added, it's ready to Approve.
|
Many thanks, @simon-20. You're right that the inconsistency is a problem. But I wonder whether the core issue is that blanking outbound query strings doesn't actually buys us anything. Looking at it again I realised record IDs are already in |
Yes, that makes sense. Sounds good to me. |
Refs #27 — the API should stream errors to Sentry using the standard hooks.
What changed
src/register_your_data_api/sentry.py, the only module importingsentry_sdk. Initialised inmain.pyimmediately before the application object is created.ERRORor above (including from third-party libraries; the audit logger is excluded), and request traces.SENTRY_DSN,SENTRY_ENVIRONMENT,SENTRY_TRACES_SAMPLE_RATE, all optional. Documented inREADME.md,.env.exampleandCHANGELOG.md.Architecture / scope decisions
sentry.pyis the only importer of the SDK; everything else reports errors by logging them, which Sentry's logging and Starlette integrations pick up. The existingapp_logger.error(..., exc_info=True)inunhandled_exception_handleralready did this, soexception_handlers.pyneeded no change at all. Replacing the service means editing one file.Context.Contextisn't created until the application lifespan runs, which is after the Sentry SDK must be initialised.get_environment_config()reproducesContext's precedence:.envfirst, overridden by real environment variables.SENTRY_DSNis deliberately not inContext._REQUIRED_ENV_VARS. Error reporting should not be the reason the API fails to start.Testing
flake8,black,isort,mypy --strict,banditall clean.tests/unit/test_sentry.py, plustests/unit/test_main.pyfor startup reporting.0b6f4e8036be471096c100dc38db8659.tests/conftest.pyempties SENTRY_DSN for the session, so the suite cannot report to a real project.Notes for reviewer
(bytes, bytes)tuples the scrubber cannot match by name), and audit-logCRITICALrecords carry theAuthorizationheader contents. Both pinned by regression tests.SENTRY_TRACES_SAMPLE_RATEdefaults to1.0in code, so every request sends a transaction; it is overridable per deployment, and0stops transactions entirely while leaving error reporting untouched. It is enabled because Sentry's own setup guidance treats errors plus tracing as the recommended defaultinitfor a new project — it says to take that default "as written" and not to "pare it back to errors-only", and recommends tracing specifically when an HTTP framework such as FastAPI is detected. Its sample-rate guidance is1.0, "lower to 0.1–0.2 in high-traffic production".send_default_pii=Falseis weaker than its name suggests; it does not cover request headers or bodies. Bodies in particular were being sent on successful requests via the transaction event.max_request_body_size="never"is what withholds them. The README documents this.TODO before merge