Skip to content

Conversation

@cofin
Copy link
Member

@cofin cofin commented Nov 18, 2025

Since we rely on the upstream ASGI open telemetry integration, some of the Litestar specific concepts did not always get wrapped inside the correct span.

This change allows the Open Telemetry plugin to instrument guards, events, and the CLI commands in Litestar.

Properly wrap guards, CLI, and events with OTEL spans
Properly wrap guards, CLI, and events with OTEL spans
@github-actions github-actions bot added area/dependencies This PR involves changes to the dependencies area/docs This PR involves changes to the documentation size: small type/feat pr/internal labels Nov 18, 2025
Copy link
Member

@provinzkraut provinzkraut left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Generally a good idea, but I don't think this is the right approach.

Specifically, we shouldn't resort to patching, as it is extremely brittle. The only reason naive instrumentations do this is because frameworks do not provide the necessary hooks. Since we're doing a first party integration though, we can use all the hooks and, if needed, add additional ones.

Comment on lines +29 to +58
_OTEL_AVAILABLE: bool | None = None
try: # pragma: no cover - optional dependency
from opentelemetry.trace import TracerProvider as _RuntimeTracerProvider
except ImportError: # pragma: no cover
_RuntimeTracerProvider = object # type: ignore[misc,assignment]

_CUSTOM_TRACER_PROVIDER: _RuntimeTracerProvider | None = None # pyright: ignore


def _get_tracer(name: str) -> Any:
from opentelemetry import trace

tracer_provider = _CUSTOM_TRACER_PROVIDER or trace.get_tracer_provider()
return tracer_provider.get_tracer(name)


def _is_otel_available() -> bool:
"""Check if OpenTelemetry is installed and available."""
global _OTEL_AVAILABLE
if _OTEL_AVAILABLE is not None:
return _OTEL_AVAILABLE

try:
import opentelemetry # noqa: F401

_OTEL_AVAILABLE = True
except ImportError:
_OTEL_AVAILABLE = False

return _OTEL_AVAILABLE
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand this part. Importing the otel module doesn't make any sense if otel isn't available



@asynccontextmanager
async def create_span_async(name: str, attributes: dict[str, Any] | None = None) -> AsyncGenerator[Any, None]:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the purpose of this? It doesn't do anything async as far as I can tell?

yield None
return

from opentelemetry.trace import Status, StatusCode
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There really shouldn't be an import in a hot path


try:
yield span
except Exception as exc:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this necessary? I was under the impression that the active span already records exceptions

Comment on lines +212 to +218
result = provider_func(*args, **kwargs)
if inspect.isawaitable(result):
result = await result

# Add result type as attribute
if span and span.is_recording():
span.set_attribute("litestar.dependency.result_type", type(result).__name__)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this might break for generator dependencies

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/dependencies This PR involves changes to the dependencies area/docs This PR involves changes to the documentation pr/internal size: small type/feat

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants