codekingpro/portable-devtools
114k
1"""OpenTelemetry integration for LangSmith."""2 3import logging4from typing import Optional, cast5 6from langsmith import utils as ls_utils7 8from .processor import OtelExporter, OtelSpanProcessor9 10logger = logging.getLogger(__name__)11 12__all__ = ["configure", "OtelSpanProcessor", "OtelExporter"]13 14 15def configure(16 api_key: Optional[str] = None,17 project_name: Optional[str] = None,18 SpanProcessor: Optional[type] = None,19) -> bool:20 """Configure OpenTelemetry with LangSmith as the `TracerProvider`.21 22 Initializes OpenTelemetry with LangSmith as the primary and only `TracerProvider`.23 24 Usage:25 >>> from langsmith.integrations.otel import configure26 >>> configure( # doctest: +SKIP27 ... api_key="your-api-key", project_name="your-project"28 ... )29 30 Using environment variables:31 >>> # Set LANGSMITH_API_KEY and LANGSMITH_PROJECT32 >>> configure() # Will use env vars # doctest: +SKIP33 34 !!! warning35 36 This function is only for when LangSmith is your ONLY OpenTelemetry source.37 38 It sets the global TracerProvider, which can only be done once per application.39 40 This function will fail if OpenTelemetry is already initialized with another41 `TracerProvider` (you cannot override an existing `TracerProvider`).42 43 If you already have OpenTelemetry set up with other tools, use `OtelSpanProcessor`44 directly to add LangSmith to your existing setup:45 46 !!! example "Adding LangSmith to existing OTEL setup"47 ```python48 from opentelemetry import trace49 from langsmith.integrations.otel.processor import OtelSpanProcessor50 51 # Use your existing provider (already initialized)52 provider = trace.get_tracer_provider()53 54 # Add LangSmith processor to existing provider55 langsmith_processor = OtelSpanProcessor(56 api_key="your-api-key", project="your-project"57 )58 provider.add_span_processor(langsmith_processor)59 ```60 61 Args:62 api_key: LangSmith API key. Defaults to `LANGSMITH_API_KEY` env var.63 project_name: Project name. Defaults to `LANGSMITH_PROJECT` env var.64 SpanProcessor: Span processor class to use. Defaults to `BatchSpanProcessor`.65 66 Returns:67 `True` if configuration succeeded, `False` if `TracerProvider` already exists.68 """69 try:70 from opentelemetry import trace71 from opentelemetry.sdk.trace import TracerProvider72 from opentelemetry.trace import NoOpTracer, ProxyTracer, ProxyTracerProvider73 74 existing_provider = cast(TracerProvider, trace.get_tracer_provider())75 tracer = existing_provider.get_tracer(__name__)76 77 # Check if OpenTelemetry is in its default uninitialized state78 # (ProxyTracerProvider with NoOpTracer means no real TracerProvider was set)79 if (80 isinstance(existing_provider, ProxyTracerProvider)81 and hasattr(tracer, "_tracer")82 and isinstance(83 cast(84 ProxyTracer, # type: ignore[attr-defined, name-defined]85 tracer,86 )._tracer,87 NoOpTracer,88 )89 ):90 # Safe to set TracerProvider since none exists yet91 provider = TracerProvider()92 trace.set_tracer_provider(provider)93 else:94 logger.warning(95 "OpenTelemetry TracerProvider is already set. "96 "Cannot override existing TracerProvider. Use OtelSpanProcessor "97 "directly to add LangSmith to your existing provider instead."98 )99 return False100 101 api_key = api_key or ls_utils.get_api_key(None)102 if not api_key:103 return False104 105 project_name = project_name or ls_utils.get_tracer_project()106 107 processor = OtelSpanProcessor(108 api_key=api_key, project=project_name, SpanProcessor=SpanProcessor109 )110 provider.add_span_processor(processor) # type: ignore111 return True112 except Exception as e:113 logger.warning("Failed to initialize Otel for LangSmith:", e)114 return False115 