Repository: livekit/agents
File: livekit-agents/livekit/agents/telemetry/traces.py (Python)

Code before:
            )
            self._auth_header = f"Bearer {access_token.to_jwt()}"
            self._expires_at = datetime.now(timezone.utc) + token_ttl

        def __call__(self) -> dict[str, str]:
            now = datetime.now(timezone.utc)
            if now >= self._expires_at - refresh_margin:
                with self._lock:
                    if now >= self._expires_at - refresh_margin:
                        self._refresh()
            return {"Authorization": self._auth_header}

    header_provider = _AuthHeaderProvider()
    session = _AuthRefreshingSession(header_provider)
    otlp_compression = Compression.Gzip
    metadata: dict[str, AttributeValue] = {"room_id": room_id, "job_id": job_id}

    resource = Resource.create(
        {
            SERVICE_NAME: "livekit-agents",
            "room_id": room_id,
            "job_id": job_id,
        }
    )
    # We check against trace_api.TracerProvider since it is the abstract base class
    if not isinstance(tracer._tracer_provider, trace_api.TracerProvider):
        # ⬇️ This is a sdk TracerProvider which inherits from trace_api.TracerProvider
        tracer_provider = trace_sdk.TracerProvider(resource=resource)
        set_tracer_provider(tracer_provider)
    else:
        # attach the processor to the existing tracer provider
        tracer_provider = tracer._tracer_provider
        if isinstance(tracer_provider, trace_sdk.TracerProvider):
            tracer_provider.resource.merge(resource)

    span_exporter = OTLPSpanExporter(
        endpoint=f"https://{cloud_hostname}/observability/traces/otlp/v0",
        compression=otlp_compression,
        session=session,
    )

    if isinstance(tracer_provider, trace_sdk.TracerProvider):
        tracer_provider.add_span_processor(_MetadataSpanProcessor(metadata))
        tracer_provider.add_span_processor(BatchSpanProcessor(span_exporter))

    logger_provider = get_logger_provider()
    if not isinstance(logger_provider, LoggerProvider):
        logger_provider = LoggerProvider()
        set_logger_provider(logger_provider)

    log_exporter = OTLPLogExporter(

Review comment (bug):
When the default no-op provider is set (which is also a `trace_api.TracerProvider`), the condition is FALSE and execution goes to the else branch.

The code later checks `isinstance(tracer_provider, trace_sdk.TracerProvider)` before adding span processors, which fails, so processors never get added.

`tracer._tracer_provider` should always be `trace_api.TracerProvider`, so maybe we check if it's a no-op provider instead
```suggestion
    if isinstance(
        tracer._tracer_provider, (trace_api.ProxyTracerProvider, trace_api.NoOpTracerProvider)
    ):
```

Code after:
            )
            self._auth_header = f"Bearer {access_token.to_jwt()}"
            self._expires_at = datetime.now(timezone.utc) + token_ttl

        def __call__(self) -> dict[str, str]:
            now = datetime.now(timezone.utc)
            if now >= self._expires_at - refresh_margin:
                with self._lock:
                    if now >= self._expires_at - refresh_margin:
                        self._refresh()
            return {"Authorization": self._auth_header}

    header_provider = _AuthHeaderProvider()
    session = _AuthRefreshingSession(header_provider)
    otlp_compression = Compression.Gzip
    metadata: dict[str, AttributeValue] = {"room_id": room_id, "job_id": job_id}

    resource = Resource.create(
        {
            SERVICE_NAME: "livekit-agents",
            "room_id": room_id,
            "job_id": job_id,
        }
    )

    # Check if a tracer provider is not set and set one up
    # below shows how the ProxyTracerProvider is returned when none have been setup
    # https://github.com/open-telemetry/opentelemetry-python/blob/0018c0030bac9bdce4487fe5fcb3ec6a542ec904/opentelemetry-api/src/opentelemetry/trace/__init__.py#L555
    tracer_provider: trace_api.TracerProvider
    if isinstance(
        tracer._tracer_provider, (trace_api.ProxyTracerProvider, trace_api.NoOpTracerProvider)
    ):
        tracer_provider = trace_sdk.TracerProvider(resource=resource)
        set_tracer_provider(tracer_provider)
    else:
        # attach the processor to the existing tracer provider
        tracer_provider = tracer._tracer_provider
        if isinstance(tracer_provider, trace_sdk.TracerProvider):
            tracer_provider.resource.merge(resource)

    span_exporter = OTLPSpanExporter(
        endpoint=f"https://{cloud_hostname}/observability/traces/otlp/v0",
        compression=otlp_compression,
        session=session,
    )

    if isinstance(tracer_provider, trace_sdk.TracerProvider):
        tracer_provider.add_span_processor(_MetadataSpanProcessor(metadata))
        tracer_provider.add_span_processor(BatchSpanProcessor(span_exporter))

    logger_provider = get_logger_provider()