[Observability]

Health endpoints, gunicorn process model, Cloud Logging, coverage artifacts, and operational signals for PYNE.

Observability

Abstract

PYNE’s production surface today optimizes for simple, hostable signals rather than a full OpenTelemetry mesh: HTTP health checks, process managers (gunicorn), cloud platform logs, CI artifacts (coverage, Playwright reports), and application-level API key usage counters. Treat this page as the map of what exists in-repo, not a claim of enterprise APM parity.

Conceptual model

Interface surface

Health

backend/app.py exposes:

GET /
→ { "status": "healthy", "service": "pynescript-pro-api", … }

Used by:

  • Dockerfile target api HEALTHCHECK (curl -fsS http://127.0.0.1:8080/)
  • docker-compose.yml api healthcheck
  • Load balancers / Cloud Run startup-ish probes (platform-dependent)

Process model (production)

gunicorn --bind :8080 --workers 2 --threads 4 --timeout 60 backend.app:app
KnobEffect on signals
workersProcess isolation; multiplies memory
threadsConcurrent requests within worker
timeout 60sAligns with Cloud Run --timeout=60s — long evals die predictably

Logs

EnvironmentWhere logs go
Local make runProcess stdout/stderr
DockerContainer logs (docker logs, compose)
Cloud Buildlogging: CLOUD_LOGGING_ONLY
Cloud RunCloud Logging (request + container)

Application modules use standard library / Flask logging patterns; there is no mandatory structured-log schema enforced repo-wide. �SLOT0� if a future branch introduces OpenTelemetry exporters.

CI / quality signals

SignalSource
Ruff / mypyci.yml lint job
Pytest resultsLSP + backend jobs
Codecov (optional)Python 3.13 matrix cell
AXIS coverage lcovaxis-coverage-lcov artifact
Playwright reportUploaded on nightly/e2e failure
Security testsbun run test:security (PWA job + nightly)

Usage metering (app-layer)

backend/middleware/auth.py tracks per-key:

  • calls_used / calls_limit / tier
  • last_used timestamps

These are business metrics for rate limits, not Prometheus time series — export them if you need dashboards.

Internals

PathRole
backend/app.pyHealth route, CORS, MAX_CONTENT_LENGTH
backend/middleware/auth.pyKey store, rate limit counters
backend/services/backtest.pyBacktest metrics objects for API responses
Dockerfile (api target)HEALTHCHECK + gunicorn entrypoint
cloudbuild.yamlCloud Logging-only build logs
logs/ (repo)Local combined/error log files if generated by tools — not the production contract

Invariants & edge cases

  1. Health ≠ readiness of evaluator warm caches. A 200 on / does not mean the first /run will be fast (cold import / JIT / numba).
  2. Timeouts double-bind. Gunicorn 60s and Cloud Run 60s — the tighter effective limit is still 60s.
  3. Scale-to-zero hides idle metrics. No traffic ⇒ no samples; use synthetic uptime checks if SLOs matter.
  4. Coverage artifacts expire (7–14 days retention on Actions uploads).
  5. Do not scrape secrets from logs. API keys and admin tokens must never be logged at info level.

Worked examples

Local health loop

make run
curl -s http://127.0.0.1:5002/ | python -m json.tool

Docker health

docker inspect --format='{{json .State.Health}}' CONTAINER

Tail Cloud Run (gcloud)

gcloud run services logs read pynescript-pro-api --region us-central1 --limit 50

Failure modes

SymptomCauseFix
Health green, /run 500Exception in evaluator pathInspect request logs; reproduce with payload
Worker killsSoft timeoutOptimize script / raise timeout consistently
Missing CI artifactPath wrong / tests passedif-no-files-found: ignore hides absence
Rate limit false positivesShared key / limit too lowAdjust tier limits; multi-key
Silent deploy failureBuild logging-only + unreadCheck Cloud Build history UI

See also