Coverage for langsmith/_internal/otel/_otel_client.py: 17%

36 statements  

« prev     ^ index     » next       coverage.py v7.10.1, created at 2025-12-11 16:15 -0800

1"""Client configuration for OpenTelemetry integration with LangSmith.""" 

2 

3import os 

4import warnings 

5from typing import TYPE_CHECKING 

6 

7if TYPE_CHECKING: 

8 try: 

9 from opentelemetry.sdk.trace import TracerProvider # type: ignore[import] 

10 except ImportError: 

11 TracerProvider = object # type: ignore[assignment, misc] 

12 

13from langsmith import utils as ls_utils 

14 

15 

16def _import_otel_client(): 

17 """Dynamically import OTEL client modules when needed.""" 

18 try: 

19 from opentelemetry.exporter.otlp.proto.http.trace_exporter import ( # type: ignore[import] 

20 OTLPSpanExporter, 

21 ) 

22 from opentelemetry.sdk.resources import ( # type: ignore[import] 

23 SERVICE_NAME, 

24 Resource, 

25 ) 

26 from opentelemetry.sdk.trace import TracerProvider # type: ignore[import] 

27 from opentelemetry.sdk.trace.export import ( # type: ignore[import] 

28 BatchSpanProcessor, 

29 ) 

30 

31 return ( 

32 OTLPSpanExporter, 

33 SERVICE_NAME, 

34 Resource, 

35 TracerProvider, 

36 BatchSpanProcessor, 

37 ) 

38 except ImportError as e: 

39 warnings.warn( 

40 f"OTEL_ENABLED is set but OpenTelemetry packages are not installed: {e}" 

41 ) 

42 return None 

43 

44 

45def get_otlp_tracer_provider() -> "TracerProvider": 

46 """Get the OTLP tracer provider for LangSmith. 

47 

48 This function creates a tracer provider that exports spans using the OTLP protocol 

49 with LangSmith-specific defaults: 

50 

51 - OTEL_EXPORTER_OTLP_ENDPOINT: https://api.smith.langchain.com/otel 

52 - OTEL_EXPORTER_OTLP_HEADERS: Contains x-api-key from LangSmith API key and 

53 Langsmith-Project header if project is configured 

54 

55 These defaults can be overridden by setting the environment variables before 

56 calling this function. 

57 

58 Returns: 

59 TracerProvider: The OTLP tracer provider. 

60 """ 

61 # Import OTEL modules dynamically 

62 otel_imports = _import_otel_client() 

63 if otel_imports is None: 

64 raise ImportError( 

65 "OpenTelemetry packages are required to use this function. " 

66 "Please install with `pip install langsmith[otel]`" 

67 ) 

68 ( 

69 OTLPSpanExporter, 

70 SERVICE_NAME, 

71 Resource, 

72 TracerProvider, 

73 BatchSpanProcessor, 

74 ) = otel_imports 

75 

76 if "OTEL_EXPORTER_OTLP_ENDPOINT" not in os.environ: 

77 ls_endpoint = ls_utils.get_api_url(None) 

78 os.environ["OTEL_EXPORTER_OTLP_ENDPOINT"] = f"{ls_endpoint}/otel" 

79 

80 # Configure headers with API key and project if available 

81 if "OTEL_EXPORTER_OTLP_HEADERS" not in os.environ: 

82 api_key = ls_utils.get_api_key(None) 

83 headers = f"x-api-key={api_key}" 

84 

85 project = ls_utils.get_tracer_project() 

86 if project: 

87 headers += f",Langsmith-Project={project}" 

88 

89 os.environ["OTEL_EXPORTER_OTLP_HEADERS"] = headers 

90 

91 service_name = os.environ.get("OTEL_SERVICE_NAME", "langsmith") 

92 resource = Resource( 

93 attributes={ 

94 SERVICE_NAME: service_name, 

95 # Marker to identify LangSmith's internal provider 

96 "langsmith.internal_provider": True, 

97 } 

98 ) 

99 

100 tracer_provider = TracerProvider(resource=resource) 

101 

102 otlp_exporter = OTLPSpanExporter() 

103 span_processor = BatchSpanProcessor(otlp_exporter) 

104 tracer_provider.add_span_processor(span_processor) 

105 

106 return tracer_provider