langtrace-python-sdk 2.1.2__py3-none-any.whl → 2.1.4__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -29,7 +29,7 @@ def create_index():
29
29
 
30
30
 
31
31
  @with_langtrace_root_span()
32
- def basic(span_id, trace_id):
32
+ def basic(span_id=None, trace_id=None):
33
33
 
34
34
  result = client.embeddings.create(
35
35
  model="text-embedding-ada-002",
@@ -44,7 +44,6 @@ def basic(span_id, trace_id):
44
44
 
45
45
  index = pinecone.Index(PINECONE_INDEX_NAME)
46
46
  res = index.upsert(vectors=[data_to_upsert], namespace="test-namespace")
47
- print("res", res)
48
47
 
49
48
  resp = index.query(
50
49
  vector=embedding, top_k=1, include_values=False, namespace="test-namespace"
@@ -52,8 +51,7 @@ def basic(span_id, trace_id):
52
51
  send_user_feedback(
53
52
  {"spanId": span_id, "traceId": trace_id, "userScore": 1, "userId": "123"}
54
53
  )
55
- print(resp)
54
+ return [res, resp]
56
55
 
57
56
 
58
57
  # create_index()
59
- basic("span_id", "trace_id")
@@ -9,6 +9,8 @@ from opentelemetry.trace.span import format_trace_id
9
9
  from langtrace_python_sdk.constants.exporter.langtrace_exporter import (
10
10
  LANGTRACE_REMOTE_URL,
11
11
  )
12
+ from colorama import Fore
13
+ from requests.exceptions import RequestException
12
14
 
13
15
 
14
16
  class LangTraceExporter(SpanExporter):
@@ -55,9 +57,6 @@ class LangTraceExporter(SpanExporter):
55
57
  self.api_key = api_key or os.environ.get("LANGTRACE_API_KEY")
56
58
  self.api_host: str = api_host or LANGTRACE_REMOTE_URL
57
59
 
58
- if not self.api_key:
59
- raise ValueError("No API key provided")
60
-
61
60
  def export(self, spans: typing.Sequence[ReadableSpan]) -> SpanExportResult:
62
61
  """
63
62
  Exports a batch of telemetry data.
@@ -68,10 +67,17 @@ class LangTraceExporter(SpanExporter):
68
67
  Returns:
69
68
  The result of the export SUCCESS or FAILURE
70
69
  """
70
+ if not self.api_key:
71
+ print(Fore.RED)
72
+ print(
73
+ "Missing Langtrace API key, proceed to https://langtrace.ai to create one"
74
+ )
75
+ print("Set the API key as an environment variable LANGTRACE_API_KEY")
76
+ print(Fore.RESET)
77
+ return
71
78
  data = [
72
79
  {
73
80
  "traceId": format_trace_id(span.get_span_context().trace_id),
74
- "instrumentationLibrary": span.instrumentation_info.__repr__(),
75
81
  "droppedEventsCount": span.dropped_events,
76
82
  "droppedAttributesCount": span.dropped_attributes,
77
83
  "droppedLinksCount": span.dropped_links,
@@ -83,14 +89,23 @@ class LangTraceExporter(SpanExporter):
83
89
 
84
90
  # Send data to remote URL
85
91
  try:
86
- requests.post(
92
+ response = requests.post(
87
93
  url=f"{self.api_host}/api/trace",
88
94
  data=json.dumps(data),
89
95
  headers={"Content-Type": "application/json", "x-api-key": self.api_key},
96
+ timeout=20,
97
+ )
98
+
99
+ if not response.ok:
100
+ raise RequestException(response.text)
101
+
102
+ print(
103
+ Fore.GREEN + f"Exported {len(spans)} spans successfully." + Fore.RESET
90
104
  )
91
- print(f"sent to {self.api_host}/api/trace with {len(data)} spans")
92
105
  return SpanExportResult.SUCCESS
93
- except Exception as e:
106
+ except RequestException as err:
107
+ print(Fore.RED + "Failed to export spans.")
108
+ print(Fore.RED + f"Error: {err}" + Fore.RESET)
94
109
  return SpanExportResult.FAILURE
95
110
 
96
111
  def shutdown(self) -> None:
@@ -17,7 +17,7 @@ limitations under the License.
17
17
  import importlib.metadata
18
18
  import logging
19
19
  from typing import Collection
20
-
20
+ from opentelemetry.instrumentation.utils import unwrap
21
21
  from opentelemetry.instrumentation.instrumentor import BaseInstrumentor
22
22
  from opentelemetry.trace import get_tracer
23
23
  from wrapt import wrap_function_wrapper
@@ -28,7 +28,7 @@ from langtrace_python_sdk.instrumentation.weaviate.patch import (
28
28
  )
29
29
  from langtrace_python_sdk.constants.instrumentation.weaviate import APIS
30
30
 
31
- logging.basicConfig(level=logging.FATAL)
31
+ logging.basicConfig(level=logging.DEBUG) # Set to DEBUG for detailed logging
32
32
 
33
33
 
34
34
  class WeaviateInstrumentation(BaseInstrumentor):
@@ -47,17 +47,19 @@ class WeaviateInstrumentation(BaseInstrumentor):
47
47
  for api_name, api_config in APIS.items():
48
48
  module_path, function_name = api_name.rsplit(".", 1)
49
49
  if api_config.get("OPERATION") == "query":
50
- wrap_function_wrapper(
51
- api_config["MODULE"],
52
- api_config["METHOD"],
53
- generic_query_patch(api_name, version, tracer),
54
- )
50
+ if getattr(api_config["MODULE"], api_config["METHOD"], None):
51
+ wrap_function_wrapper(
52
+ api_config["MODULE"],
53
+ api_config["METHOD"],
54
+ generic_query_patch(api_name, version, tracer),
55
+ )
55
56
  elif api_config.get("OPERATION") == "create":
56
- wrap_function_wrapper(
57
- api_config["MODULE"],
58
- api_config["METHOD"],
59
- generic_collection_patch(api_name, version, tracer),
60
- )
57
+ if getattr(api_config["MODULE"], api_config["METHOD"], None):
58
+ wrap_function_wrapper(
59
+ api_config["MODULE"],
60
+ api_config["METHOD"],
61
+ generic_collection_patch(api_name, version, tracer),
62
+ )
61
63
 
62
64
  def _instrument_module(self, module_name):
63
65
  pass
@@ -68,6 +68,8 @@ from langtrace_python_sdk.instrumentation.weaviate.instrumentation import (
68
68
  WeaviateInstrumentation,
69
69
  )
70
70
 
71
+ from colorama import Fore
72
+
71
73
 
72
74
  def init(
73
75
  api_key: str = None,
@@ -77,6 +79,7 @@ def init(
77
79
  api_host: Optional[str] = None,
78
80
  disable_instrumentations: Optional[DisableInstrumentations] = None,
79
81
  ):
82
+ print(Fore.GREEN + "Initializing Langtrace SDK.." + Fore.RESET)
80
83
  provider = TracerProvider(resource=Resource.create({"service.name": sys.argv[0]}))
81
84
 
82
85
  remote_write_exporter = (
@@ -90,20 +93,24 @@ def init(
90
93
  simple_processor_console = SimpleSpanProcessor(console_exporter)
91
94
 
92
95
  if write_spans_to_console:
96
+ print(Fore.BLUE + "Writing spans to console" + Fore.RESET)
93
97
  provider.add_span_processor(simple_processor_console)
94
98
 
95
99
  elif custom_remote_exporter is not None:
100
+ print(Fore.BLUE + f"Exporting spans to custom remote exporter.." + Fore.RESET)
96
101
  if batch:
97
102
  provider.add_span_processor(batch_processor_remote)
98
103
  else:
99
104
  provider.add_span_processor(simple_processor_remote)
100
105
 
101
106
  elif api_host is not None:
107
+ print(Fore.BLUE + f"Exporting spans to custom host: {api_host}.." + Fore.RESET)
102
108
  if batch:
103
109
  provider.add_span_processor(batch_processor_remote)
104
110
  else:
105
111
  provider.add_span_processor(simple_processor_remote)
106
112
  else:
113
+ print(Fore.BLUE + "Exporting spans to Langtrace cloud.." + Fore.RESET)
107
114
  provider.add_span_processor(batch_processor_remote)
108
115
 
109
116
  # Initialize tracer
@@ -126,7 +126,6 @@ def send_user_feedback(data: EvaluationAPIData) -> None:
126
126
  timeout=None,
127
127
  )
128
128
  response.raise_for_status()
129
- print("SENDING FEEDBACK PUT", response.status_code, response.text)
130
129
 
131
130
  else:
132
131
  # Make a POST request to create a new evaluation
@@ -137,7 +136,6 @@ def send_user_feedback(data: EvaluationAPIData) -> None:
137
136
  headers=headers,
138
137
  timeout=None,
139
138
  )
140
- print("Response", response.status_code, response.text)
141
139
  response.raise_for_status()
142
140
 
143
141
  except requests.RequestException as err:
@@ -1 +1 @@
1
- __version__ = "2.1.2"
1
+ __version__ = "2.1.4"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: langtrace-python-sdk
3
- Version: 2.1.2
3
+ Version: 2.1.4
4
4
  Summary: Python SDK for LangTrace
5
5
  Project-URL: Homepage, https://github.com/Scale3-Labs/langtrace-python-sdk
6
6
  Author-email: Scale3 Labs <engineering@scale3labs.com>
@@ -10,6 +10,7 @@ Classifier: License :: OSI Approved :: Apache Software License
10
10
  Classifier: Operating System :: OS Independent
11
11
  Classifier: Programming Language :: Python :: 3
12
12
  Requires-Python: >=3.9
13
+ Requires-Dist: colorama>=0.4.6
13
14
  Requires-Dist: opentelemetry-api>=1.24.0
14
15
  Requires-Dist: opentelemetry-exporter-otlp-proto-grpc>=1.24.0
15
16
  Requires-Dist: opentelemetry-exporter-otlp-proto-http>=1.24.0
@@ -32,13 +32,13 @@ examples/openai_example/tool_calling_nonstreaming.py,sha256=Yc848IooZRXNynHL6z0k
32
32
  examples/openai_example/tool_calling_streaming.py,sha256=mV1RbyAoVhumGRPpqPWQ6PMhnJyeifrlELd2-K1qJ_w,7015
33
33
  examples/perplexity_example/basic.py,sha256=bp7n27gaugJkaFVyt8pjaEfi66lYcqP6eFFjPewUShY,668
34
34
  examples/pinecone_example/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
35
- examples/pinecone_example/basic.py,sha256=9iG5Tk8QExe4cFFI6_mt1pgd5BLCZh64tsU1oPBFXTg,1464
35
+ examples/pinecone_example/basic.py,sha256=b-5-cSf3_N6Gk4zGVecGF47mBcFY9ZrC5ztrIZVgTQo,1430
36
36
  examples/qdrant_example/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
37
37
  examples/qdrant_example/basic.py,sha256=DCMjHSuBZKkhEjCkwy5d5La9WMyW0lCWqtcZWiFCEm4,1425
38
38
  examples/weaviate_example/query_text.py,sha256=s3f0hYYi-xdbh_LlTBDHegQiVi-4bW_eACb2EnEj8J4,64533
39
39
  langtrace_python_sdk/__init__.py,sha256=R4dv73QARUw4WRfCdSKkKzZTLDumF9jcSdwtVrzWhb4,962
40
- langtrace_python_sdk/langtrace.py,sha256=2VVVeWX3b20jwDY9iqDTxeE-Zunfgt2gfgRs3SreZLU,6993
41
- langtrace_python_sdk/version.py,sha256=UiuBcRXPtXxPUBDdp0ZDvWl0U9Db1kMNfT3oAfhxqLg,22
40
+ langtrace_python_sdk/langtrace.py,sha256=jWTG9F-vleKkDbC-l22eY6rKH0eHUyJCmgXpoLcPbbY,7409
41
+ langtrace_python_sdk/version.py,sha256=1yR20YsjyDpnFQgDIQmHfutaSsaW0F7mDqjloRVRIG8,22
42
42
  langtrace_python_sdk/constants/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
43
43
  langtrace_python_sdk/constants/exporter/langtrace_exporter.py,sha256=5MNjnAOg-4am78J3gVMH6FSwq5N8TOj72ugkhsw4vi0,46
44
44
  langtrace_python_sdk/constants/instrumentation/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -52,7 +52,7 @@ langtrace_python_sdk/constants/instrumentation/pinecone.py,sha256=Xaqqw-xBO0JJLG
52
52
  langtrace_python_sdk/constants/instrumentation/qdrant.py,sha256=yL7BopNQTXW7L7Z-gVM2PdusKD7r9qqcATvczFd7NtQ,1999
53
53
  langtrace_python_sdk/constants/instrumentation/weaviate.py,sha256=Iytf2OpB_irZYEmvOQ7Pf483EdG5Bh59GxaBlXck0yY,1501
54
54
  langtrace_python_sdk/extensions/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
55
- langtrace_python_sdk/extensions/langtrace_exporter.py,sha256=s-4zc7lba1va_JUReFdLgyBKlvwV1KmBt_OzVmWReQg,3610
55
+ langtrace_python_sdk/extensions/langtrace_exporter.py,sha256=Fj--DzBr4AwTM_iS3lRz0NhqESEyTOZ3SBCA4OevFkE,4127
56
56
  langtrace_python_sdk/instrumentation/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
57
57
  langtrace_python_sdk/instrumentation/anthropic/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
58
58
  langtrace_python_sdk/instrumentation/anthropic/instrumentation.py,sha256=-srgE8qumAn0ulQYZxMa8ch-9IBH0XgBW_rfEnGk6LI,1684
@@ -91,7 +91,7 @@ langtrace_python_sdk/instrumentation/qdrant/__init__.py,sha256=47DEQpj8HBSa-_TIm
91
91
  langtrace_python_sdk/instrumentation/qdrant/instrumentation.py,sha256=vl2eKSP55aqDo1JiRlvOUBrr6kddvG9Z5dCYew2OG08,1816
92
92
  langtrace_python_sdk/instrumentation/qdrant/patch.py,sha256=KcUWmvnS3PgPStzs1oWmlZsyomKBl3dmg8nXuR0T1C0,4654
93
93
  langtrace_python_sdk/instrumentation/weaviate/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
94
- langtrace_python_sdk/instrumentation/weaviate/instrumentation.py,sha256=i5xi0uWY1pPvGWyedFEvOtbRVT7ybFnMia-9TYFigOA,2309
94
+ langtrace_python_sdk/instrumentation/weaviate/instrumentation.py,sha256=4BnHRzXOKEauy2TNTZwpIagDFUp03CUyBZCdE2vinxk,2596
95
95
  langtrace_python_sdk/instrumentation/weaviate/patch.py,sha256=ig2fc33hNydEcH5cJWRycFnMXiXiJr731J-Vg5Ze4No,5634
96
96
  langtrace_python_sdk/types/__init__.py,sha256=-j8cuz3bhUdOqj7N2c0w5y-j3UmcxwEgNh8BWeXwHoI,813
97
97
  langtrace_python_sdk/utils/__init__.py,sha256=MbBqT4NpDCNTqqvZ0lG4tRiFFZ-tlM8Dwophg4xyrRw,148
@@ -100,7 +100,7 @@ langtrace_python_sdk/utils/misc.py,sha256=CD9NWRLxLpFd0YwlHJqzlpFNedXVWtAKGOjQWn
100
100
  langtrace_python_sdk/utils/prompt_registry.py,sha256=7FFB4Pj0414qgf02h5zL5vXBZgNBf74g4Iq7GdFaIO0,2689
101
101
  langtrace_python_sdk/utils/silently_fail.py,sha256=F_9EteXCO9Cyq-8MA1OT2Zy_dx8n06nt31I7t7ui24E,478
102
102
  langtrace_python_sdk/utils/types.py,sha256=l-N6o7cnWUyrD6dBvW7W3Pf5CkPo5QaoT__k1XLbrQg,383
103
- langtrace_python_sdk/utils/with_root_span.py,sha256=H20e-LeRFHHSmdXlZhkWas33ImgEKihlVqAtoYi4iNA,6103
103
+ langtrace_python_sdk/utils/with_root_span.py,sha256=rSPrTnKndJo6cFUWL4907IkJFbtLwqMS87paADUxD6A,5957
104
104
  tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
105
105
  tests/conftest.py,sha256=0Jo6iCZTXbdvyJVhG9UpYGkLabL75378oauCzmt-Sa8,603
106
106
  tests/utils.py,sha256=hP8sTH-M8WO6zlLkSFHPf6483ZcKEcnxul6JIIb1pLM,1396
@@ -119,9 +119,9 @@ tests/cohere/cassettes/test_cohere_chat.yaml,sha256=iQIhJwmWe2AQDmdguL6L0SZOPMD6
119
119
  tests/cohere/cassettes/test_cohere_chat_streaming.yaml,sha256=tMlz7IPZYRCJUeMCwyXrA4O4zpcqIPpQ5hU9I5f352Q,8174
120
120
  tests/cohere/cassettes/test_cohere_embed.yaml,sha256=Svcyw8WkVMVw4cocWQzGOdUVmWi5AM6Gb9t9VLlyOjM,27320
121
121
  tests/cohere/cassettes/test_cohere_rerank.yaml,sha256=RsJ8804lTktI0FKEFCw0M4ztStZbCxb_z_VRmrw8ooQ,2393
122
- tests/langchain/test_langchain.py,sha256=p1YkeL1U23b0E3vhEcXonwMa3QGUswQjKNReMbV0ndA,2576
123
- tests/langchain/test_langchain_community.py,sha256=B7Z7YRx7v9507wEyDnXV1NKVYo4r2XU0YplugfYVsJ0,2615
124
- tests/langchain/test_langchain_core.py,sha256=LBeoK27-uDethSvBGykYAlCVfEwljQrN7sZL91TVCPw,4467
122
+ tests/langchain/conftest.py,sha256=f29apdevxg7AM0mPQ1LoEd-yStGruqGLTQUp29heLJo,1116
123
+ tests/langchain/test_langchain.py,sha256=QP11RdNDX_ztF1ppPnUiui3SsxYYdzVsDgtI-1OGH48,893
124
+ tests/langchain/cassettes/test_langchain.yaml,sha256=KPBTVIYMUPFaSNpwrTDgWzsu4p3hHj_yNDoudDa-Jis,3755
125
125
  tests/openai/conftest.py,sha256=BkehS6heg-O91Nzoc4546OSiAzy8KgSgk7VCO3A11zM,700
126
126
  tests/openai/test_chat_completion.py,sha256=-TwCAF2czsiGZqETQvMOgmIJgdFWycJ9nOeO5q65AJs,5804
127
127
  tests/openai/test_embeddings.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -137,7 +137,7 @@ tests/pinecone/cassettes/test_query.yaml,sha256=b5v9G3ssUy00oG63PlFUR3JErF2Js-5A
137
137
  tests/pinecone/cassettes/test_upsert.yaml,sha256=neWmQ1v3d03V8WoLl8FoFeeCYImb8pxlJBWnFd_lITU,38607
138
138
  tests/qdrant/conftest.py,sha256=9n0uHxxIjWk9fbYc4bx-uP8lSAgLBVx-cV9UjnsyCHM,381
139
139
  tests/qdrant/test_qdrant.py,sha256=pzjAjVY2kmsmGfrI2Gs2xrolfuaNHz7l1fqGQCjp5_o,3353
140
- langtrace_python_sdk-2.1.2.dist-info/METADATA,sha256=4kaLgCo0f7qBqUWa7gRKBEj-_Sl57Iw-MuN1lqCTwAY,11738
141
- langtrace_python_sdk-2.1.2.dist-info/WHEEL,sha256=zEMcRr9Kr03x1ozGwg5v9NQBKn3kndp6LSoSlVg-jhU,87
142
- langtrace_python_sdk-2.1.2.dist-info/licenses/LICENSE,sha256=QwcOLU5TJoTeUhuIXzhdCEEDDvorGiC6-3YTOl4TecE,11356
143
- langtrace_python_sdk-2.1.2.dist-info/RECORD,,
140
+ langtrace_python_sdk-2.1.4.dist-info/METADATA,sha256=ZUsesq7cmXEYg7N5GOkKPYxz2wANwYTwXxfX5McSkdo,11769
141
+ langtrace_python_sdk-2.1.4.dist-info/WHEEL,sha256=zEMcRr9Kr03x1ozGwg5v9NQBKn3kndp6LSoSlVg-jhU,87
142
+ langtrace_python_sdk-2.1.4.dist-info/licenses/LICENSE,sha256=QwcOLU5TJoTeUhuIXzhdCEEDDvorGiC6-3YTOl4TecE,11356
143
+ langtrace_python_sdk-2.1.4.dist-info/RECORD,,
@@ -0,0 +1,106 @@
1
+ interactions:
2
+ - request:
3
+ body: '{"messages": [{"content": "You are world class technical documentation
4
+ writer.", "role": "system"}, {"content": "how can langsmith help with testing?",
5
+ "role": "user"}], "model": "gpt-3.5-turbo", "n": 1, "stream": false, "temperature":
6
+ 0.7}'
7
+ headers:
8
+ accept:
9
+ - application/json
10
+ accept-encoding:
11
+ - gzip, deflate
12
+ connection:
13
+ - keep-alive
14
+ content-length:
15
+ - '240'
16
+ content-type:
17
+ - application/json
18
+ host:
19
+ - api.openai.com
20
+ user-agent:
21
+ - OpenAI/Python 1.30.5
22
+ x-stainless-arch:
23
+ - arm64
24
+ x-stainless-async:
25
+ - 'false'
26
+ x-stainless-lang:
27
+ - python
28
+ x-stainless-os:
29
+ - MacOS
30
+ x-stainless-package-version:
31
+ - 1.30.5
32
+ x-stainless-runtime:
33
+ - CPython
34
+ x-stainless-runtime-version:
35
+ - 3.12.3
36
+ method: POST
37
+ uri: https://api.openai.com/v1/chat/completions
38
+ response:
39
+ body:
40
+ string: !!binary |
41
+ H4sIAAAAAAAAA3xVTW8bOQy9+1cQc7aNfLR16tv2A4tFt9hL9rRdBLSGnlGikVSSsuMt8t8X1Iwd
42
+ pwh6MWxRfHp8fKR/zAAa3zZraFyP6oYcFu//br/s3+271XUeVvfb+0f6cvv4x8MHyjf4tZlbRtrc
43
+ k9Nj1tKlIQdSn+IYdkyoZKiXq8vVxc3NxeqmBobUUrC0Luvievl2oYU3aXFxefV2yuyTdyTNGv6Z
44
+ AQD8qJ/GMbb02KzhYn48GUgEO2rWp0sADadgJw2KeFGM2syfgy5FpVhp/4mxk8FrD14AIac98bYE
45
+ 0JQCaI8KDiP0FDLs7ZaSqI8d+Ag7ZJ+KwB4Psv4Wv8XLJfxWNA1WMtyOF9fw/IIhbQiKUAuaYM9e
46
+ CfCUYdAgjn1WgW1iOKTCIGmre2QCzDl4hyauLOHDAQLtiLGrbFQgohbGAAFjV7AjyJwciVjcYcaN
47
+ D149ydxwK5eRQH3WoZBYUTmgj/A5dsFLP4cBH0Z8IBRPXHnFFBdKro/eYQAlHGCgYUMsVpaJy35T
48
+ DDqB9nTSbCK0NK2ullUh+ISK8DtF4lrZz3J1Y2Ri2drlDZp+KUJmamnrI7XAJZAAxhYyqhJHmdee
49
+ 2atW7ffi3UM4wOjHZzChc6lfKnzbezm2LCOrdyUgh4P1zxxiacfKxFE0N8hoGabvxVvLICB3BDik
50
+ EhXSFlq/Ixaqj1cdricdPqIQfMWIHQ0U9Re2Sdxh9P9RLXeoGWc9fKVl1gVG91B7kTl1TCJG5sge
51
+ nfpd9UbFpCiFCWyWmXqK4nf2q5qNLO8XvrSS3izhU3LFyni1pxgknU1UO901Jud11O9MUoLKvBJL
52
+ 2tNJ8wVTqGPj4zbxUF+qYzENlHkzHI4GMvD2nJR5HUGUi9PC1MII8jwcJxWiLRCK7lA5uIDs9WDp
53
+ VYajhi/Aqwx/mWAhzH+qXpQJh+AjvTYbc/BD5rQ7tnRSfT41psfojFMIuEnjxJi5qnJnU+jjLoVd
54
+ 1eaVJi+baRM+nVZoSF3mtLF1G0sIp/Otj176OyaUFG1diqY8pj/NAP6tq7q82L5N5jRkvdP0QNEA
55
+ r1YjXPP853AWvHw/RTUphrPAm3eziWEjB1Ea7rY+dsSZfd3cxnP2NPsfAAD//wMAt4ZeGbgGAAA=
56
+ headers:
57
+ CF-Cache-Status:
58
+ - DYNAMIC
59
+ CF-RAY:
60
+ - 88c03f46bf3b23c5-LHR
61
+ Connection:
62
+ - keep-alive
63
+ Content-Encoding:
64
+ - gzip
65
+ Content-Type:
66
+ - application/json
67
+ Date:
68
+ - Thu, 30 May 2024 16:54:42 GMT
69
+ Server:
70
+ - cloudflare
71
+ Set-Cookie:
72
+ - __cf_bm=9en.DN2CPQUgM8CubXIqqiVZkm43q.oBCL4n7bXxViw-1717088082-1.0.1.1-nl9dbPbwwGsUORjX1Y8Ta7S2v.MBG3o1JWUgYQU98tFUNcY9hFcmfcXWFu_bcohUX1nun6S55Wg2rg3MX7PHPQ;
73
+ path=/; expires=Thu, 30-May-24 17:24:42 GMT; domain=.api.openai.com; HttpOnly;
74
+ Secure; SameSite=None
75
+ - _cfuvid=bJ_po6.pyb_9JWu27O8yfh1AX1atGjC5_sFN497eMI8-1717088082420-0.0.1.1-604800000;
76
+ path=/; domain=.api.openai.com; HttpOnly; Secure; SameSite=None
77
+ Transfer-Encoding:
78
+ - chunked
79
+ alt-svc:
80
+ - h3=":443"; ma=86400
81
+ openai-organization:
82
+ - scale3-1
83
+ openai-processing-ms:
84
+ - '4295'
85
+ openai-version:
86
+ - '2020-10-01'
87
+ strict-transport-security:
88
+ - max-age=15724800; includeSubDomains
89
+ x-ratelimit-limit-requests:
90
+ - '10000'
91
+ x-ratelimit-limit-tokens:
92
+ - '2000000'
93
+ x-ratelimit-remaining-requests:
94
+ - '9999'
95
+ x-ratelimit-remaining-tokens:
96
+ - '1999960'
97
+ x-ratelimit-reset-requests:
98
+ - 6ms
99
+ x-ratelimit-reset-tokens:
100
+ - 1ms
101
+ x-request-id:
102
+ - req_4b43c2d3cf0dc839647c8b775b75d6f5
103
+ status:
104
+ code: 200
105
+ message: OK
106
+ version: 1
@@ -0,0 +1,42 @@
1
+ """Unit tests configuration module."""
2
+
3
+ import os
4
+ import pytest
5
+
6
+ from langtrace_python_sdk.instrumentation.openai.instrumentation import (
7
+ OpenAIInstrumentation,
8
+ )
9
+ from langtrace_python_sdk.instrumentation.langchain.instrumentation import (
10
+ LangchainInstrumentation,
11
+ )
12
+ from langtrace_python_sdk.instrumentation.langchain_core.instrumentation import (
13
+ LangchainCoreInstrumentation,
14
+ )
15
+
16
+ from langtrace_python_sdk.instrumentation.langchain_community.instrumentation import (
17
+ LangchainCommunityInstrumentation,
18
+ )
19
+
20
+
21
+ @pytest.fixture(autouse=True)
22
+ def clear_exporter(exporter):
23
+ exporter.clear()
24
+
25
+
26
+ @pytest.fixture(autouse=True)
27
+ def environment():
28
+ if not os.environ.get("OPENAI_API_KEY"):
29
+ os.environ["OPENAI_API_KEY"] = "test"
30
+
31
+
32
+ @pytest.fixture(scope="module")
33
+ def vcr_config():
34
+ return {"filter_headers": ["authorization", "x-api-key"]}
35
+
36
+
37
+ @pytest.fixture(scope="session", autouse=True)
38
+ def instrument():
39
+ OpenAIInstrumentation().instrument()
40
+ LangchainInstrumentation().instrument()
41
+ LangchainCoreInstrumentation().instrument()
42
+ LangchainCommunityInstrumentation().instrument()
@@ -1,82 +1,28 @@
1
- import unittest
2
- from unittest.mock import MagicMock, call
3
- from langtrace_python_sdk.instrumentation.langchain.patch import generic_patch
4
- from opentelemetry.trace import SpanKind
5
- from opentelemetry.trace import get_tracer
6
- import importlib.metadata
7
- from langtrace_python_sdk.constants.instrumentation.openai import APIS
8
- from opentelemetry.trace.status import Status, StatusCode
9
- from tests.utils import common_setup
10
- import json
11
-
12
-
13
- class TestGenericPatch(unittest.TestCase):
14
- data = {"key": "value"}
15
-
16
- def setUp(self):
17
- self.langchain_mock, self.tracer, self.span = common_setup(self.data, None)
18
-
19
- def tearDown(self):
20
- # Clean up after each test case
21
- pass
22
-
23
- def test_generic_patch(self):
24
- # Arrange
25
- method_name = "example_method"
26
- trace_output = False
27
- trace_input = False # Change as per your requirement
28
- args = (1, 2, 3)
29
- task = "split_text"
30
- kwargs = {"key": "value"}
31
- version = importlib.metadata.version("langchain")
32
-
33
- # Act
34
- wrapped_function = generic_patch(
35
- "langchain.text_splitter",
36
- task,
37
- self.tracer,
38
- version,
39
- trace_output,
40
- trace_input,
41
- )
42
- result = wrapped_function(self.langchain_mock, MagicMock(), args, kwargs)
43
-
44
- # Assert
45
- self.assertTrue(
46
- self.tracer.start_as_current_span.called_once_with(
47
- method_name, kind=SpanKind.CLIENT
48
- )
49
- )
50
-
51
- service_provider = "Langchain"
52
- expected_attributes = {
53
- "langtrace.sdk.name": "langtrace-python-sdk",
54
- "langtrace.service.name": service_provider,
55
- "langtrace.service.type": "framework",
56
- "langtrace.service.version": version,
57
- "langtrace.version": "1.0.0",
58
- "langchain.task.name": task,
59
- }
60
-
61
- self.assertTrue(
62
- self.span.set_attribute.has_calls(
63
- [call(key, value) for key, value in expected_attributes.items()],
64
- any_order=True,
65
- )
66
- )
67
-
68
- actual_calls = self.span.set_attribute.call_args_list
69
-
70
- for key, value in expected_attributes.items():
71
- self.assertIn(call(key, value), actual_calls)
72
-
73
- self.assertEqual(self.span.set_status.call_count, 1)
74
- self.assertTrue(self.span.set_status.has_calls([call(Status(StatusCode.OK))]))
75
-
76
- expected_result_data = {"key": "value"}
77
-
78
- self.assertEqual(result.key, expected_result_data["key"])
79
-
80
-
81
- if __name__ == "__main__":
82
- unittest.main()
1
+ import pytest
2
+ from langchain_openai import ChatOpenAI
3
+ from langchain_core.prompts.chat import ChatPromptTemplate
4
+ from langchain_core.output_parsers import StrOutputParser
5
+
6
+
7
+ @pytest.mark.vcr()
8
+ def test_langchain(exporter):
9
+ llm = ChatOpenAI()
10
+ prompt = ChatPromptTemplate.from_messages(
11
+ [
12
+ ("system", "You are world class technical documentation writer."),
13
+ ("user", "{input}"),
14
+ ]
15
+ )
16
+ output_parser = StrOutputParser()
17
+ chain = prompt | llm | output_parser
18
+ chain.invoke({"input": "how can langsmith help with testing?"})
19
+ spans = exporter.get_finished_spans()
20
+
21
+ assert [
22
+ "ChatPromptTemplate.invoke",
23
+ "openai.chat.completions.create",
24
+ "StrOutputParser.parse",
25
+ "StrOutputParser.parse_result",
26
+ "StrOutputParser.invoke",
27
+ "RunnableSequence.invoke",
28
+ ] == [span.name for span in spans]
@@ -1,82 +0,0 @@
1
- import unittest
2
- from unittest.mock import MagicMock, Mock, patch, call
3
- from langtrace_python_sdk.instrumentation.langchain_community.patch import generic_patch
4
- from opentelemetry.trace import SpanKind
5
- from opentelemetry.trace import get_tracer
6
- import importlib.metadata
7
- import openai
8
- from langtrace_python_sdk.constants.instrumentation.openai import APIS
9
- from opentelemetry.trace.status import Status, StatusCode
10
- import json
11
- from tests.utils import common_setup
12
-
13
-
14
- class TestGenericPatch(unittest.TestCase):
15
- data = {"key": "value"}
16
-
17
- def setUp(self):
18
- self.langchain_mock, self.tracer, self.span = common_setup(self.data, None)
19
-
20
- def tearDown(self):
21
- # Clean up after each test case
22
- pass
23
-
24
- def test_generic_patch(self):
25
- # Arrange
26
- method_name = "example_method"
27
- trace_output = False
28
- trace_input = False
29
- args = (1, 2, 3)
30
- task = "vector_store"
31
- kwargs = {"key": "value"}
32
- version = importlib.metadata.version("langchain-community")
33
-
34
- # Act
35
- wrapped_function = generic_patch(
36
- "langchain_community.vectorstores.faiss",
37
- task,
38
- self.tracer,
39
- version,
40
- trace_output,
41
- trace_input,
42
- )
43
- result = wrapped_function(self.langchain_mock, MagicMock(), args, kwargs)
44
-
45
- # Assert
46
- self.assertTrue(
47
- self.tracer.start_as_current_span.called_once_with(
48
- method_name, kind=SpanKind.CLIENT
49
- )
50
- )
51
-
52
- service_provider = "Langchain Community"
53
- expected_attributes = {
54
- "langtrace.sdk.name": "langtrace-python-sdk",
55
- "langtrace.service.name": service_provider,
56
- "langtrace.service.type": "framework",
57
- "langtrace.service.version": version,
58
- "langtrace.version": "1.0.0",
59
- "langchain.task.name": task,
60
- }
61
-
62
- self.assertTrue(
63
- self.span.set_attribute.has_calls(
64
- [call(key, value) for key, value in expected_attributes.items()],
65
- any_order=True,
66
- )
67
- )
68
-
69
- actual_calls = self.span.set_attribute.call_args_list
70
-
71
- for key, value in expected_attributes.items():
72
- self.assertIn(call(key, value), actual_calls)
73
-
74
- self.assertEqual(self.span.set_status.call_count, 1)
75
- self.assertTrue(self.span.set_status.has_calls([call(Status(StatusCode.OK))]))
76
-
77
- expected_result_data = {"key": "value"}
78
- self.assertEqual(result.key, expected_result_data["key"])
79
-
80
-
81
- if __name__ == "__main__":
82
- unittest.main()
@@ -1,141 +0,0 @@
1
- import unittest
2
- from unittest.mock import MagicMock, Mock, patch, call
3
- from langtrace_python_sdk.instrumentation.langchain_core.patch import (
4
- generic_patch,
5
- runnable_patch,
6
- )
7
- from opentelemetry.trace import SpanKind
8
- from opentelemetry.trace import get_tracer
9
- import importlib.metadata
10
- import openai
11
- from langtrace_python_sdk.constants.instrumentation.openai import APIS
12
- from opentelemetry.trace.status import Status, StatusCode
13
- import json
14
- from tests.utils import common_setup
15
-
16
-
17
- class TestGenericPatch(unittest.TestCase):
18
- data = {"items": "value"}
19
-
20
- def setUp(self):
21
- self.langchain_mock, self.tracer, self.span = common_setup(self.data, None)
22
-
23
- def tearDown(self):
24
- # Clean up after each test case
25
- pass
26
-
27
- def test_generic_patch(self):
28
- # Arrange
29
- method_name = "example_method"
30
- trace_output = False
31
- trace_input = True
32
- task = "retriever"
33
- args = (1, 2, 3)
34
- kwargs = {"key": "value"}
35
- version = importlib.metadata.version("langchain-core")
36
-
37
- # Act
38
- wrapped_function = generic_patch(
39
- "langchain_core.retrievers",
40
- task,
41
- self.tracer,
42
- version,
43
- trace_output,
44
- trace_input,
45
- )
46
- result = wrapped_function(self.langchain_mock, MagicMock(), args, kwargs)
47
-
48
- # Assert
49
- self.assertTrue(
50
- self.tracer.start_as_current_span.called_once_with(
51
- method_name, kind=SpanKind.CLIENT
52
- )
53
- )
54
-
55
- service_provider = "Langchain Core"
56
- expected_attributes = {
57
- "langtrace.sdk.name": "langtrace-python-sdk",
58
- "langtrace.service.name": service_provider,
59
- "langtrace.service.type": "framework",
60
- "langtrace.service.version": version,
61
- "langtrace.version": "1.0.0",
62
- "langchain.task.name": task,
63
- }
64
-
65
- self.assertTrue(
66
- self.span.set_attribute.has_calls(
67
- [call(key, value) for key, value in expected_attributes.items()],
68
- any_order=True,
69
- )
70
- )
71
-
72
- actual_calls = self.span.set_attribute.call_args_list
73
- for key, value in expected_attributes.items():
74
- self.assertIn(call(key, value), actual_calls)
75
-
76
- self.assertEqual(self.span.set_status.call_count, 1)
77
- self.assertTrue(self.span.set_status.has_calls([call(Status(StatusCode.OK))]))
78
-
79
- expected_result_data = {"items": "value"}
80
- self.assertEqual(result.items, expected_result_data["items"])
81
-
82
- def test_runnable_patch(self):
83
- # Arrange
84
- method_name = "example_method"
85
- trace_output = False
86
- trace_input = True
87
- args = (1, 2, 3)
88
- kwargs = {"key": "value"}
89
- version = importlib.metadata.version("langchain-core")
90
-
91
- # Act
92
- wrapped_function = runnable_patch(
93
- "langchain_core.runnables.passthrough",
94
- "runnablepassthrough",
95
- self.tracer,
96
- version,
97
- trace_output,
98
- trace_input,
99
- )
100
-
101
- result = wrapped_function(self.langchain_mock, MagicMock(), args, kwargs)
102
-
103
- # Assert
104
- self.assertTrue(
105
- self.tracer.start_as_current_span.called_once_with(
106
- method_name, kind=SpanKind.CLIENT
107
- )
108
- )
109
-
110
- service_provider = "Langchain Core"
111
- expected_attributes = {
112
- "langtrace.sdk.name": "langtrace-python-sdk",
113
- "langtrace.service.name": service_provider,
114
- "langtrace.service.type": "framework",
115
- "langtrace.service.version": version,
116
- "langtrace.version": "1.0.0",
117
- "langchain.task.name": "runnablepassthrough",
118
- }
119
-
120
- self.assertTrue(
121
- self.span.set_attribute.has_calls(
122
- [call(key, value) for key, value in expected_attributes.items()],
123
- any_order=True,
124
- )
125
- )
126
-
127
- actual_calls = self.span.set_attribute.call_args_list
128
-
129
- for key, value in expected_attributes.items():
130
- self.assertIn(call(key, value), actual_calls)
131
-
132
- self.assertEqual(self.span.set_status.call_count, 1)
133
- self.assertTrue(self.span.set_status.has_calls([call(Status(StatusCode.OK))]))
134
-
135
- expected_result_data = {"items": "value"}
136
-
137
- self.assertEqual(result.items, expected_result_data["items"])
138
-
139
-
140
- if __name__ == "__main__":
141
- unittest.main()