feat(otel): initialize OpenTelemetry tracing and metrics in boot()#96
Draft
fubezz wants to merge 3 commits into
Draft
feat(otel): initialize OpenTelemetry tracing and metrics in boot()#96fubezz wants to merge 3 commits into
fubezz wants to merge 3 commits into
Conversation
Adds otel_initialize(), following the same enabled-flag + graceful-degradation pattern as sentry_initialize(): reads the standard OTEL_* env vars, sets up a process-wide TracerProvider/MeterProvider exporting via OTLP/gRPC, and is a no-op unless both explicitly enabled and OTEL_EXPORTER_OTLP_ENDPOINT is set. Called from boot() so every Foundry service gets it via a core version bump, with no per-service code changes needed for process-level tracing/metrics. Request-level FastAPI tracing needs one additional call once the app exists (instrument_fastapi(app), exported here) since boot() runs before the app is constructed - this still needs wiring into the foundry-python template's Service.api_serve(). Ref: OP-3108
❌ 1 Tests Failed:
View the top 1 failed test(s) by shortest run time
To view more test analytics, go to the Test Analytics Dashboard |
Adds LoggerProvider/BatchLogRecordProcessor(OTLPLogExporter()) setup to otel_initialize(), and a loguru sink that converts each record into a stdlib logging.LogRecord and forwards it to OTel's own LoggingHandler. Loguru has no first-party OTel integration (this project uses loguru, not stdlib logging, throughout), so reusing LoggingHandler's own conversion and trace-correlation logic via a thin bridge is simpler than reimplementing OTLP log export from scratch. Closes the logs gap flagged in PR review against OP-3108's acceptance criteria (traces + metrics + logs).
Splits logs export behind a new logs_enabled setting (default False), independent of the main enabled flag. Traces/metrics behave unchanged; the loguru->OTLP logs bridge only activates when logs_enabled is also set, since log volume/cost characteristics differ from traces/metrics and shouldn't be forced on every service that enables tracing. Ref: OP-3108
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.



Summary
otel_initialize()in a newsrc/aignostics_foundry_core/otel.py, following the exact same pattern assentry_initialize(): pydantic-settings-drivenenabledflag (env-prefixed perFoundryContext), graceful no-op when the SDK isn't available or isn't enabled.TracerProvider/MeterProviderexporting via OTLP/gRPC, using the standard, unprefixed OpenTelemetry env vars (OTEL_EXPORTER_OTLP_ENDPOINT,OTEL_SERVICE_NAME, etc.) rather than reinventing project-specific ones —OTEL_SERVICE_NAMEdefaults to theFoundryContextproject name if not explicitly set.logging— loguru has no first-party OTel integration. Added a loguru sink (_make_otel_log_sink) that converts each loguru record into a stdliblogging.LogRecordand forwards it to OTel's ownLoggingHandler, reusing the SDK's own conversion/trace-correlation logic instead of reimplementing OTLP log export. Gated behind a separatelogs_enabledsetting, off by default even whenenabledis true — log volume/cost characteristics differ from traces/metrics, so it shouldn't be forced on every service that turns on tracing.otel_initialize()intoboot(), right aftersentry_initialize()— every Foundry service gets this via a single core version bump, no per-service code changes for process-level tracing/metrics(/logs, opt-in).instrument_fastapi(app)for request-level tracing, sinceboot()runs before any FastAPIappinstance exists.Related: OP-3108 (expose an OTel endpoint for Foundry Cloud Run services — this is the service-side counterpart, decided against pushing this logic into the
foundry-pythontemplate since it's not an importable runtime dependency there).Known follow-up (not done in this PR)
instrument_fastapi(app)needs to actually be called somewhere — but the FastAPIappinstance is constructed inService.api_serve(), which lives in thefoundry-pythontemplate (not this repo), not inboot(). This PR ships the capability; wiring the one-line call into the template is a separate, small follow-up infoundry-python. Until that lands, request-level FastAPI auto-tracing (spans per HTTP request) isn't automatic — process-level tracing/metrics/logs (manually-created spans, outbound instrumentation, log records) work regardless.Test plan
mise run lint— ruff, pyright, deptry all pass.mise run test_unit— 13 passed,otel.pyat 100% coverage.mise run test_integration— 100 passed,otel.pyat 100% coverage.mise run pre_commit_run_all— all hooks pass.logs_enabledon/off gating.aignx-otel-gateway.aignostics.aifrom the gitops side of OP-3108 is live) — not done here, this PR is unit/integration-tested only.Opened as draft pending review of the design (in particular: the loguru→OTel logs bridge approach and its opt-in gating, and confirmation on the
instrument_fastapifollow-up plan).🤖 Generated with Claude Code