Affected: Python SDK (with Observability plugin)
When using the Python SDK with the Observability plugin in a Django application, you may run into one or more of the following issues.
Issue 1: Traces not reaching LaunchDarkly (StatusCode.UNAVAILABLE, wrong endpoint or resource)
Symptoms
You may see one or more of the following:
- Telemetry (traces) does not appear in the LaunchDarkly Observability dashboard.
- Exports fail with StatusCode.UNAVAILABLE when sending to the default OTLP endpoint (localhost:4318).
- Exports fail with StatusCode.DEADLINE_EXCEEDED (often when compression is not enabled).
- The LaunchDarkly backend discards telemetry because the resource is missing required attributes (e.g. highlight.project_id).
- The resource shows resource.service.name=unknown_service:... because OTEL_SERVICE_NAME was not set when the OTLP providers were created.
Cause
The SDK’s auto-instrumentation runs before the Observability plugin’s OTEL configuration. The auto-instrumentation creates OTLP exporters and providers using whatever OTEL environment variables are set at that moment. If the plugin’s endpoint and resource attributes are applied later, the override can fail and the wrong configuration remains in use (default endpoint, missing service name, or missing highlight.project_id).
Solution
- Set the OTEL environment variables before creating the Observability plugin (and before auto_instrumentation.initialize() runs), so the auto-instrumentation picks them up from the start.
In settings.py (or wherever you configure the SDK), set at least:
- OTEL_EXPORTER_OTLP_ENDPOINT — LaunchDarkly’s OTLP endpoint (e.g. https://otel.observability.app.launchdarkly.com:4318)
- OTEL_SERVICE_NAME — your service name (e.g. your app name)
- OTEL_RESOURCE_ATTRIBUTES — must include highlight.project_id=<sdk_key> so LaunchDarkly can route data to your project; you can also set deployment.environment, telemetry.distro.name=launchdarkly-observability, etc.
- OTEL_EXPORTER_OTLP_COMPRESSION — e.g. gzip (without it, exports may fail with StatusCode.DEADLINE_EXCEEDED)
- OTEL_EXPORTER_OTLP_TIMEOUT — e.g. 30000 (milliseconds)
Example (adjust endpoint and attributes to match your project and environment):
class="language-auto"import os
os.environ.setdefault("OTEL_EXPORTER_OTLP_ENDPOINT", "https://otel.observability.app.launchdarkly.com:4317")
os.environ.setdefault("OTEL_EXPORTER_OTLP_COMPRESSION", "gzip")
os.environ.setdefault("OTEL_EXPORTER_OTLP_TIMEOUT", "30000")
os.environ.setdefault("OTEL_SERVICE_NAME", "my-django-app")
os.environ.setdefault(
"OTEL_RESOURCE_ATTRIBUTES",
f"highlight.project_id={LAUNCHDARKLY_SDK_KEY},"
f"deployment.environment={ENVIRONMENT},"
"telemetry.distro.name=launchdarkly-observability",
)
# Then create the ObservabilityPlugin / ld_client, etc.- Ensure the block above runs before you instantiate the Observability plugin or call auto_instrumentation.initialize(). Restart the application after making changes.
Issue 2: "Overriding of current TracerProvider is not allowed" (and similar for LoggerProvider / MeterProvider)
Symptoms
You may see one or more of the following:
- A warning that overriding the current TracerProvider (or LoggerProvider / MeterProvider) is not allowed.
- In Django’s development server (runserver), the message appears twice because the auto-reloader loads settings.py in both the main process and the child process.
Cause
The Observability plugin tries to set the global OTEL providers after auto-instrumentation has already set them. The OpenTelemetry API does not allow replacing the current providers once they are set, so the warning is emitted. The providers created by auto-instrumentation remain in use.
Solution
With the environment variables from Issue 1 set before the plugin is created, the providers created by auto-instrumentation already use the correct endpoint and resource. The override warning is then cosmetic: the active providers are the right ones.
- No code change is required beyond fixing Issue 1.
- In production with a server like gunicorn (no auto-reloader), the duplicate warning from the reloader is also eliminated.
Issue 3: Django application logs not appearing in Observability
Symptoms
You may see one or more of the following:
- Startup logs (emitted during settings.py load, before Django finishes setup) appear in the LaunchDarkly Observability dashboard, but logs from views, middleware, or other application code do not.
- No error is raised; the log handler is removed silently.
- You have log instrumentation enabled (instrument_logging=True) and use Django’s LOGGING dict configuration.
Cause
When instrument_logging=True, the SDK adds a LoggingHandler to the root logger while settings.py loads. Later, during django.setup(), Django runs logging.config.dictConfig(settings.LOGGING), which replaces the root logger’s handlers with only those defined in LOGGING. The LaunchDarkly handler was attached earlier and is not in LOGGING, so it is removed. Subsequent application logs are not sent to LaunchDarkly.
Solution
Integrate the SDK’s log handler into Django’s LOGGING configuration so that dictConfig applies it instead of removing it.
- In your Observability configuration, set instrument_logging=False. This prevents the SDK from attaching its handler to the root logger during settings.py load, so you can register the handler through Django’s LOGGING dict instead.
- After you define your LOGGING dictionary and after the LaunchDarkly SDK key and client are available (e.g., where you initialize the SDK in settings.py), add the SDK’s log handler to LOGGING and attach it to your loggers:
class="language-auto"import logging
# After LOGGING is defined and ld_client is available (e.g. in settings.py):
if LAUNCHDARKLY_SDK_KEY and ld_client:
import ldobserve.observe as ld_observe
_ld_log_handler = ld_observe.logging_handler()
if not isinstance(_ld_log_handler, logging.NullHandler):
LOGGING.setdefault("handlers", {})
LOGGING.setdefault("loggers", {})
LOGGING["handlers"]["launchdarkly"] = {"()": lambda: _ld_log_handler}
for _logger_name, _logger_cfg in LOGGING["loggers"].items():
_logger_cfg.setdefault("handlers", []).append("launchdarkly")- This registers the LaunchDarkly handler in LOGGING["handlers"] and adds it to each logger in LOGGING["loggers"]. When Django runs dictConfig(settings.LOGGING), the handler is part of the configuration and continues to receive your application logs. The setdefault calls ensure handlers and loggers exist before use.
- Restart your Django application (or runserver) so the updated LOGGING configuration is loaded. Application logs should then appear in the LaunchDarkly Observability dashboard.
If application logs still do not appear, confirm that LAUNCHDARKLY_SDK_KEY and ld_client are set when the block above runs, that LOGGING["handlers"] and LOGGING["loggers"] exist (or are created by the snippet), and that your application code uses those loggers. If the issue persists, contact LaunchDarkly Support with your Django and Observability SDK versions and a description of your LOGGING setup (without secrets).