Follow-up review fixes for #9419:
- _is_prefork_worker() only read argv, so a pool selected through
CELERY_WORKER_POOL (notably `threads`, which runs tasks in the main process
and never dispatches worker_process_init) was misclassified as prefork. The
providers were then deferred to a signal that never fires and the worker
exported nothing. _effective_pool() now applies Celery's own precedence:
-P/--pool flag, then worker_pool from settings, then the prefork default.
- Pass OTEL_EXPORTER_OTLP_TRACES_ENDPOINT / _METRICS_ENDPOINT through
x-otel-env. is_otel_active() and the exporters both honor them, so an
operator setting only those had telemetry silently disabled in every
container.
- Guard the collector's second json_parser with an `if` on attributes.log:
filelog.include matches every container on the host, so plaintext logs from
postgres/redis/rabbitmq logged a parse error per line.
- Cover the pool detection with unit tests, including the settings-configured
and CLI-overrides-settings cases.
Claude-Session: https://claude.ai/code/session_01BpGkdpVLNQ3Ziqcd6zK2qV
Review fixes for #9419:
- Pin headers on the license telemetry exporter so it can no longer inherit
OTEL_EXPORTER_OTLP_HEADERS and ship an operator's APM credential to
telemetry.plane.so. An empty dict is falsy and does not suppress the
exporters' env fallback, so the value has to be non-empty.
- manage.py: apply --settings before the first plane.* import, which otherwise
materializes LazySettings from the default module and silently ignored the
flag (breaking the local runserver entrypoint).
- Defer OTLP exporter creation to worker_process_init on the Celery prefork
pool; the gRPC channel is created eagerly and is not fork-safe.
- Bound interpreter-exit flushing: shutdown_on_exit=False on both providers plus
an atexit hook on the existing bounded flush_otel(). With an unreachable
collector a manage.py command now exits in ~3.5s instead of ~63s.
- Stamp a per-process service.instance.id so gunicorn workers and prefork
children stop exporting colliding cumulative http.server.* streams.
- Resolve instrumentors lazily and isolate each import, and take
opentelemetry-instrumentation-httpx[instruments] so a missing httpx cannot
crash every entrypoint with OTEL_ENABLED=0.
- Add a shared is_otel_active() (enabled AND any endpoint var, signal-specific
included) used by setup, both settings modules and celery, so the log schema
never changes in a process that exports nothing.
- Emit the boot banner through an explicit stderr handler and name the
observability loggers in LOGGING so disable_existing_loggers stops silencing
export errors.
- Strip whitespace in _protocol(); treat blank env values as unset so compose's
${VAR:-} interpolation no longer defeats the sampler defaults.
- Deployments: give migrator the OTel env, spell out the sampler defaults, and
ship OTEL_ENABLED commented out on AIO, where plane.env is exported after
container env and clobbered it.
- Docs: correct the emitted-metrics list, the log-schema gate, and the filelog
pipeline (Docker envelope needs a second json_parser; trace context needs
trace_parser, not move).
- Tests: fix the conftest env leak (monkeypatch.delenv, delete-only teardown)
and cover the new gating, defaults, deferred providers and logging config.
Claude-Session: https://claude.ai/code/session_01BpGkdpVLNQ3Ziqcd6zK2qV