langtrace-python-sdk 2.1.16__py3-none-any.whl → 2.1.19__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.
- examples/inspect_ai_example/basic_eval.py +24 -0
- examples/langchain_example/basic.py +23 -8
- examples/llamaindex_example/agent.py +1 -1
- examples/llamaindex_example/basic.py +5 -1
- examples/ollama_example/__init__.py +14 -0
- examples/ollama_example/basic.py +50 -0
- examples/openai_example/chat_completion.py +1 -1
- examples/pinecone_example/basic.py +1 -0
- langtrace_python_sdk/__init__.py +4 -5
- langtrace_python_sdk/constants/instrumentation/common.py +1 -0
- langtrace_python_sdk/constants/instrumentation/ollama.py +7 -0
- langtrace_python_sdk/constants/instrumentation/pinecone.py +1 -1
- langtrace_python_sdk/extensions/langtrace_filesystem.py +194 -0
- langtrace_python_sdk/instrumentation/__init__.py +2 -0
- langtrace_python_sdk/instrumentation/chroma/patch.py +7 -3
- langtrace_python_sdk/instrumentation/groq/patch.py +5 -2
- langtrace_python_sdk/instrumentation/langchain/patch.py +8 -2
- langtrace_python_sdk/instrumentation/langchain_community/patch.py +8 -2
- langtrace_python_sdk/instrumentation/langchain_core/patch.py +13 -3
- langtrace_python_sdk/instrumentation/langgraph/patch.py +7 -2
- langtrace_python_sdk/instrumentation/llamaindex/patch.py +7 -3
- langtrace_python_sdk/instrumentation/ollama/__init__.py +3 -0
- langtrace_python_sdk/instrumentation/ollama/instrumentation.py +58 -0
- langtrace_python_sdk/instrumentation/ollama/patch.py +215 -0
- langtrace_python_sdk/instrumentation/openai/patch.py +20 -8
- langtrace_python_sdk/instrumentation/pinecone/instrumentation.py +0 -1
- langtrace_python_sdk/instrumentation/pinecone/patch.py +7 -3
- langtrace_python_sdk/instrumentation/qdrant/patch.py +7 -2
- langtrace_python_sdk/instrumentation/weaviate/patch.py +7 -3
- langtrace_python_sdk/langtrace.py +14 -2
- langtrace_python_sdk/types/__init__.py +77 -1
- langtrace_python_sdk/utils/langtrace_sampler.py +56 -0
- langtrace_python_sdk/utils/with_root_span.py +11 -2
- langtrace_python_sdk/version.py +1 -1
- {langtrace_python_sdk-2.1.16.dist-info → langtrace_python_sdk-2.1.19.dist-info}/METADATA +3 -1
- {langtrace_python_sdk-2.1.16.dist-info → langtrace_python_sdk-2.1.19.dist-info}/RECORD +39 -29
- langtrace_python_sdk-2.1.19.dist-info/entry_points.txt +2 -0
- {langtrace_python_sdk-2.1.16.dist-info → langtrace_python_sdk-2.1.19.dist-info}/WHEEL +0 -0
- {langtrace_python_sdk-2.1.16.dist-info → langtrace_python_sdk-2.1.19.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Copyright (c) 2024 Scale3 Labs
|
|
3
|
+
|
|
4
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
you may not use this file except in compliance with the License.
|
|
6
|
+
You may obtain a copy of the License at
|
|
7
|
+
|
|
8
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
|
|
10
|
+
Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
See the License for the specific language governing permissions and
|
|
14
|
+
limitations under the License.
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
from opentelemetry.instrumentation.instrumentor import BaseInstrumentor
|
|
18
|
+
from opentelemetry.trace import get_tracer
|
|
19
|
+
from wrapt import wrap_function_wrapper as _W
|
|
20
|
+
from typing import Collection
|
|
21
|
+
from importlib_metadata import version as v
|
|
22
|
+
from langtrace_python_sdk.constants.instrumentation.ollama import APIS
|
|
23
|
+
from .patch import generic_patch, ageneric_patch
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class OllamaInstrumentor(BaseInstrumentor):
|
|
27
|
+
"""
|
|
28
|
+
The OllamaInstrumentor class represents the Ollama instrumentation"""
|
|
29
|
+
|
|
30
|
+
def instrumentation_dependencies(self) -> Collection[str]:
|
|
31
|
+
return ["ollama >= 0.2.0, < 1"]
|
|
32
|
+
|
|
33
|
+
def _instrument(self, **kwargs):
|
|
34
|
+
tracer_provider = kwargs.get("tracer_provider")
|
|
35
|
+
tracer = get_tracer(__name__, "", tracer_provider)
|
|
36
|
+
version = v("ollama")
|
|
37
|
+
for operation_name, details in APIS.items():
|
|
38
|
+
operation = details["METHOD"]
|
|
39
|
+
# Dynamically creating the patching call
|
|
40
|
+
_W(
|
|
41
|
+
"ollama._client",
|
|
42
|
+
f"Client.{operation}",
|
|
43
|
+
generic_patch(operation_name, version, tracer),
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
_W(
|
|
47
|
+
"ollama._client",
|
|
48
|
+
f"AsyncClient.{operation}",
|
|
49
|
+
ageneric_patch(operation_name, version, tracer),
|
|
50
|
+
)
|
|
51
|
+
_W(
|
|
52
|
+
"ollama",
|
|
53
|
+
f"{operation}",
|
|
54
|
+
generic_patch(operation_name, version, tracer),
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
def _uninstrument(self, **kwargs):
|
|
58
|
+
pass
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
from langtrace_python_sdk.constants.instrumentation.ollama import APIS
|
|
2
|
+
from importlib_metadata import version as v
|
|
3
|
+
from langtrace_python_sdk.constants import LANGTRACE_SDK_NAME
|
|
4
|
+
from langtrace_python_sdk.utils import set_span_attribute
|
|
5
|
+
from langtrace_python_sdk.utils.silently_fail import silently_fail
|
|
6
|
+
from langtrace_python_sdk.constants.instrumentation.common import (
|
|
7
|
+
LANGTRACE_ADDITIONAL_SPAN_ATTRIBUTES_KEY,
|
|
8
|
+
SERVICE_PROVIDERS,
|
|
9
|
+
)
|
|
10
|
+
from opentelemetry import baggage
|
|
11
|
+
from langtrace.trace_attributes import LLMSpanAttributes, Event
|
|
12
|
+
from opentelemetry.trace import SpanKind
|
|
13
|
+
import json
|
|
14
|
+
from opentelemetry.trace.status import Status, StatusCode
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def generic_patch(operation_name, version, tracer):
|
|
18
|
+
def traced_method(wrapped, instance, args, kwargs):
|
|
19
|
+
base_url = (
|
|
20
|
+
str(instance._client._base_url)
|
|
21
|
+
if hasattr(instance, "_client") and hasattr(instance._client, "_base_url")
|
|
22
|
+
else ""
|
|
23
|
+
)
|
|
24
|
+
api = APIS[operation_name]
|
|
25
|
+
service_provider = SERVICE_PROVIDERS["OLLAMA"]
|
|
26
|
+
extra_attributes = baggage.get_baggage(LANGTRACE_ADDITIONAL_SPAN_ATTRIBUTES_KEY)
|
|
27
|
+
span_attributes = {
|
|
28
|
+
"langtrace.sdk.name": "langtrace-python-sdk",
|
|
29
|
+
"langtrace.service.name": service_provider,
|
|
30
|
+
"langtrace.service.type": "llm",
|
|
31
|
+
"langtrace.service.version": version,
|
|
32
|
+
"langtrace.version": v(LANGTRACE_SDK_NAME),
|
|
33
|
+
"llm.model": kwargs.get("model"),
|
|
34
|
+
"llm.stream": kwargs.get("stream"),
|
|
35
|
+
"url.full": base_url,
|
|
36
|
+
"llm.api": api["METHOD"],
|
|
37
|
+
**(extra_attributes if extra_attributes is not None else {}),
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
attributes = LLMSpanAttributes(**span_attributes)
|
|
41
|
+
with tracer.start_as_current_span(
|
|
42
|
+
f'ollama.{api["METHOD"]}', kind=SpanKind.CLIENT
|
|
43
|
+
) as span:
|
|
44
|
+
_set_input_attributes(span, kwargs, attributes)
|
|
45
|
+
|
|
46
|
+
try:
|
|
47
|
+
result = wrapped(*args, **kwargs)
|
|
48
|
+
if result:
|
|
49
|
+
if span.is_recording():
|
|
50
|
+
|
|
51
|
+
if kwargs.get("stream"):
|
|
52
|
+
return _handle_streaming_response(
|
|
53
|
+
span, result, api["METHOD"]
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
_set_response_attributes(span, result)
|
|
57
|
+
span.set_status(Status(StatusCode.OK))
|
|
58
|
+
|
|
59
|
+
span.end()
|
|
60
|
+
return result
|
|
61
|
+
|
|
62
|
+
except Exception as err:
|
|
63
|
+
# Record the exception in the span
|
|
64
|
+
span.record_exception(err)
|
|
65
|
+
|
|
66
|
+
# Set the span status to indicate an error
|
|
67
|
+
span.set_status(Status(StatusCode.ERROR, str(err)))
|
|
68
|
+
|
|
69
|
+
# Reraise the exception to ensure it's not swallowed
|
|
70
|
+
raise
|
|
71
|
+
|
|
72
|
+
return traced_method
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def ageneric_patch(operation_name, version, tracer):
|
|
76
|
+
async def traced_method(wrapped, instance, args, kwargs):
|
|
77
|
+
api = APIS[operation_name]
|
|
78
|
+
service_provider = SERVICE_PROVIDERS["OLLAMA"]
|
|
79
|
+
extra_attributes = baggage.get_baggage(LANGTRACE_ADDITIONAL_SPAN_ATTRIBUTES_KEY)
|
|
80
|
+
span_attributes = {
|
|
81
|
+
"langtrace.sdk.name": "langtrace-python-sdk",
|
|
82
|
+
"langtrace.service.name": service_provider,
|
|
83
|
+
"url.full": "",
|
|
84
|
+
"llm.api": "",
|
|
85
|
+
"langtrace.service.type": "llm",
|
|
86
|
+
"langtrace.service.version": version,
|
|
87
|
+
"langtrace.version": v(LANGTRACE_SDK_NAME),
|
|
88
|
+
"llm.model": kwargs.get("model"),
|
|
89
|
+
"llm.stream": kwargs.get("stream"),
|
|
90
|
+
**(extra_attributes if extra_attributes is not None else {}),
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
attributes = LLMSpanAttributes(**span_attributes)
|
|
94
|
+
with tracer.start_as_current_span(api["METHOD"], kind=SpanKind.CLIENT) as span:
|
|
95
|
+
_set_input_attributes(span, kwargs, attributes)
|
|
96
|
+
try:
|
|
97
|
+
result = await wrapped(*args, **kwargs)
|
|
98
|
+
if result:
|
|
99
|
+
if span.is_recording():
|
|
100
|
+
if kwargs.get("stream"):
|
|
101
|
+
return _ahandle_streaming_response(
|
|
102
|
+
span, result, api["METHOD"]
|
|
103
|
+
)
|
|
104
|
+
|
|
105
|
+
_set_response_attributes(span, result)
|
|
106
|
+
span.set_status(Status(StatusCode.OK))
|
|
107
|
+
span.end()
|
|
108
|
+
return result
|
|
109
|
+
except Exception as err:
|
|
110
|
+
# Record the exception in the span
|
|
111
|
+
span.record_exception(err)
|
|
112
|
+
|
|
113
|
+
# Set the span status to indicate an error
|
|
114
|
+
span.set_status(Status(StatusCode.ERROR, str(err)))
|
|
115
|
+
|
|
116
|
+
# Reraise the exception to ensure it's not swallowed
|
|
117
|
+
raise
|
|
118
|
+
|
|
119
|
+
return traced_method
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
@silently_fail
|
|
123
|
+
def _set_response_attributes(span, response):
|
|
124
|
+
|
|
125
|
+
input_tokens = response.get("prompt_eval_count") or 0
|
|
126
|
+
output_tokens = response.get("eval_count") or 0
|
|
127
|
+
total_tokens = input_tokens + output_tokens
|
|
128
|
+
usage_dict = {
|
|
129
|
+
"input_tokens": input_tokens,
|
|
130
|
+
"output_tokens": output_tokens,
|
|
131
|
+
"total_tokens": total_tokens,
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
if total_tokens > 0:
|
|
135
|
+
set_span_attribute(span, "llm.token.counts", json.dumps(usage_dict))
|
|
136
|
+
set_span_attribute(span, "llm.finish_reason", response.get("done_reason"))
|
|
137
|
+
|
|
138
|
+
if "message" in response:
|
|
139
|
+
set_span_attribute(span, "llm.responses", json.dumps([response.get("message")]))
|
|
140
|
+
|
|
141
|
+
if "response" in response:
|
|
142
|
+
set_span_attribute(
|
|
143
|
+
span, "llm.responses", json.dumps([response.get("response")])
|
|
144
|
+
)
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
@silently_fail
|
|
148
|
+
def _set_input_attributes(span, kwargs, attributes):
|
|
149
|
+
for field, value in attributes.model_dump(by_alias=True).items():
|
|
150
|
+
set_span_attribute(span, field, value)
|
|
151
|
+
|
|
152
|
+
if "messages" in kwargs:
|
|
153
|
+
set_span_attribute(
|
|
154
|
+
span,
|
|
155
|
+
"llm.prompts",
|
|
156
|
+
json.dumps([kwargs.get("messages", [])]),
|
|
157
|
+
)
|
|
158
|
+
if "prompt" in kwargs:
|
|
159
|
+
set_span_attribute(
|
|
160
|
+
span,
|
|
161
|
+
"llm.prompts",
|
|
162
|
+
json.dumps([{"role": "user", "content": kwargs.get("prompt", [])}]),
|
|
163
|
+
)
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
def _handle_streaming_response(span, response, api):
|
|
167
|
+
accumulated_tokens = None
|
|
168
|
+
if api == "chat":
|
|
169
|
+
accumulated_tokens = {"message": {"content": "", "role": ""}}
|
|
170
|
+
if api == "completion":
|
|
171
|
+
accumulated_tokens = {"response": ""}
|
|
172
|
+
|
|
173
|
+
span.add_event(Event.STREAM_START.value)
|
|
174
|
+
try:
|
|
175
|
+
for chunk in response:
|
|
176
|
+
if api == "chat":
|
|
177
|
+
accumulated_tokens["message"]["content"] += chunk["message"]["content"]
|
|
178
|
+
accumulated_tokens["message"]["role"] = chunk["message"]["role"]
|
|
179
|
+
if api == "generate":
|
|
180
|
+
accumulated_tokens["response"] += chunk["response"]
|
|
181
|
+
|
|
182
|
+
_set_response_attributes(span, chunk | accumulated_tokens)
|
|
183
|
+
finally:
|
|
184
|
+
# Finalize span after processing all chunks
|
|
185
|
+
span.add_event(Event.STREAM_END.value)
|
|
186
|
+
span.set_status(StatusCode.OK)
|
|
187
|
+
span.end()
|
|
188
|
+
|
|
189
|
+
return response
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
async def _ahandle_streaming_response(span, response, api):
|
|
193
|
+
accumulated_tokens = None
|
|
194
|
+
if api == "chat":
|
|
195
|
+
accumulated_tokens = {"message": {"content": "", "role": ""}}
|
|
196
|
+
if api == "completion":
|
|
197
|
+
accumulated_tokens = {"response": ""}
|
|
198
|
+
|
|
199
|
+
span.add_event(Event.STREAM_START.value)
|
|
200
|
+
try:
|
|
201
|
+
async for chunk in response:
|
|
202
|
+
if api == "chat":
|
|
203
|
+
accumulated_tokens["message"]["content"] += chunk["message"]["content"]
|
|
204
|
+
accumulated_tokens["message"]["role"] = chunk["message"]["role"]
|
|
205
|
+
if api == "generate":
|
|
206
|
+
accumulated_tokens["response"] += chunk["response"]
|
|
207
|
+
|
|
208
|
+
_set_response_attributes(span, chunk | accumulated_tokens)
|
|
209
|
+
finally:
|
|
210
|
+
# Finalize span after processing all chunks
|
|
211
|
+
span.add_event(Event.STREAM_END.value)
|
|
212
|
+
span.set_status(StatusCode.OK)
|
|
213
|
+
span.end()
|
|
214
|
+
|
|
215
|
+
return response
|
|
@@ -18,10 +18,10 @@ import json
|
|
|
18
18
|
|
|
19
19
|
from importlib_metadata import version as v
|
|
20
20
|
from langtrace.trace_attributes import Event, LLMSpanAttributes
|
|
21
|
-
from opentelemetry import baggage
|
|
21
|
+
from opentelemetry import baggage, trace
|
|
22
22
|
from opentelemetry.trace import SpanKind
|
|
23
23
|
from opentelemetry.trace.status import Status, StatusCode
|
|
24
|
-
|
|
24
|
+
from opentelemetry.trace.propagation import set_span_in_context
|
|
25
25
|
from langtrace_python_sdk.constants import LANGTRACE_SDK_NAME
|
|
26
26
|
from langtrace_python_sdk.constants.instrumentation.common import (
|
|
27
27
|
LANGTRACE_ADDITIONAL_SPAN_ATTRIBUTES_KEY,
|
|
@@ -64,7 +64,9 @@ def images_generate(original_method, version, tracer):
|
|
|
64
64
|
attributes = LLMSpanAttributes(**span_attributes)
|
|
65
65
|
|
|
66
66
|
with tracer.start_as_current_span(
|
|
67
|
-
APIS["IMAGES_GENERATION"]["METHOD"],
|
|
67
|
+
APIS["IMAGES_GENERATION"]["METHOD"],
|
|
68
|
+
kind=SpanKind.CLIENT,
|
|
69
|
+
context=set_span_in_context(trace.get_current_span()),
|
|
68
70
|
) as span:
|
|
69
71
|
for field, value in attributes.model_dump(by_alias=True).items():
|
|
70
72
|
if value is not None:
|
|
@@ -141,7 +143,9 @@ def async_images_generate(original_method, version, tracer):
|
|
|
141
143
|
attributes = LLMSpanAttributes(**span_attributes)
|
|
142
144
|
|
|
143
145
|
with tracer.start_as_current_span(
|
|
144
|
-
APIS["IMAGES_GENERATION"]["METHOD"],
|
|
146
|
+
APIS["IMAGES_GENERATION"]["METHOD"],
|
|
147
|
+
kind=SpanKind.CLIENT,
|
|
148
|
+
context=set_span_in_context(trace.get_current_span()),
|
|
145
149
|
) as span:
|
|
146
150
|
items = attributes.model_dump(by_alias=True).items()
|
|
147
151
|
for field, value in items:
|
|
@@ -226,7 +230,9 @@ def images_edit(original_method, version, tracer):
|
|
|
226
230
|
attributes = LLMSpanAttributes(**span_attributes)
|
|
227
231
|
|
|
228
232
|
with tracer.start_as_current_span(
|
|
229
|
-
APIS["IMAGES_EDIT"]["METHOD"],
|
|
233
|
+
APIS["IMAGES_EDIT"]["METHOD"],
|
|
234
|
+
kind=SpanKind.CLIENT,
|
|
235
|
+
context=set_span_in_context(trace.get_current_span()),
|
|
230
236
|
) as span:
|
|
231
237
|
for field, value in attributes.model_dump(by_alias=True).items():
|
|
232
238
|
if value is not None:
|
|
@@ -349,7 +355,9 @@ def chat_completions_create(original_method, version, tracer):
|
|
|
349
355
|
# with tracer.start_as_current_span(APIS["CHAT_COMPLETION"]["METHOD"],
|
|
350
356
|
# kind=SpanKind.CLIENT) as span:
|
|
351
357
|
span = tracer.start_span(
|
|
352
|
-
APIS["CHAT_COMPLETION"]["METHOD"],
|
|
358
|
+
APIS["CHAT_COMPLETION"]["METHOD"],
|
|
359
|
+
kind=SpanKind.CLIENT,
|
|
360
|
+
context=set_span_in_context(trace.get_current_span()),
|
|
353
361
|
)
|
|
354
362
|
for field, value in attributes.model_dump(by_alias=True).items():
|
|
355
363
|
if value is not None:
|
|
@@ -833,7 +841,9 @@ def embeddings_create(original_method, version, tracer):
|
|
|
833
841
|
attributes["llm.user"] = kwargs.get("user")
|
|
834
842
|
|
|
835
843
|
with tracer.start_as_current_span(
|
|
836
|
-
APIS["EMBEDDINGS_CREATE"]["METHOD"],
|
|
844
|
+
APIS["EMBEDDINGS_CREATE"]["METHOD"],
|
|
845
|
+
kind=SpanKind.CLIENT,
|
|
846
|
+
context=set_span_in_context(trace.get_current_span()),
|
|
837
847
|
) as span:
|
|
838
848
|
|
|
839
849
|
for field, value in attributes.model_dump(by_alias=True).items():
|
|
@@ -898,7 +908,9 @@ def async_embeddings_create(original_method, version, tracer):
|
|
|
898
908
|
attributes["llm.user"] = kwargs.get("user")
|
|
899
909
|
|
|
900
910
|
with tracer.start_as_current_span(
|
|
901
|
-
APIS["EMBEDDINGS_CREATE"]["METHOD"],
|
|
911
|
+
APIS["EMBEDDINGS_CREATE"]["METHOD"],
|
|
912
|
+
kind=SpanKind.CLIENT,
|
|
913
|
+
context=set_span_in_context(trace.get_current_span()),
|
|
902
914
|
) as span:
|
|
903
915
|
|
|
904
916
|
async for field, value in attributes.model_dump(by_alias=True).items():
|
|
@@ -18,7 +18,6 @@ import importlib.metadata
|
|
|
18
18
|
import logging
|
|
19
19
|
from typing import Collection
|
|
20
20
|
|
|
21
|
-
from langtrace.trace_attributes import PineconeMethods
|
|
22
21
|
from opentelemetry.instrumentation.instrumentor import BaseInstrumentor
|
|
23
22
|
from opentelemetry.trace import get_tracer
|
|
24
23
|
from wrapt import wrap_function_wrapper
|
|
@@ -17,10 +17,10 @@ limitations under the License.
|
|
|
17
17
|
import json
|
|
18
18
|
|
|
19
19
|
from langtrace.trace_attributes import DatabaseSpanAttributes
|
|
20
|
-
from opentelemetry import baggage
|
|
20
|
+
from opentelemetry import baggage, trace
|
|
21
21
|
from opentelemetry.trace import SpanKind
|
|
22
22
|
from opentelemetry.trace.status import Status, StatusCode
|
|
23
|
-
|
|
23
|
+
from opentelemetry.trace.propagation import set_span_in_context
|
|
24
24
|
from langtrace_python_sdk.constants.instrumentation.common import (
|
|
25
25
|
LANGTRACE_ADDITIONAL_SPAN_ATTRIBUTES_KEY,
|
|
26
26
|
SERVICE_PROVIDERS,
|
|
@@ -56,7 +56,11 @@ def generic_patch(operation_name, version, tracer):
|
|
|
56
56
|
|
|
57
57
|
attributes = DatabaseSpanAttributes(**span_attributes)
|
|
58
58
|
|
|
59
|
-
with tracer.start_as_current_span(
|
|
59
|
+
with tracer.start_as_current_span(
|
|
60
|
+
api["METHOD"],
|
|
61
|
+
kind=SpanKind.CLIENT,
|
|
62
|
+
context=set_span_in_context(trace.get_current_span()),
|
|
63
|
+
) as span:
|
|
60
64
|
|
|
61
65
|
if span.is_recording():
|
|
62
66
|
set_span_attribute(span, "server.address", instance._config.host)
|
|
@@ -18,9 +18,10 @@ import json
|
|
|
18
18
|
from langtrace.trace_attributes import DatabaseSpanAttributes
|
|
19
19
|
from langtrace_python_sdk.utils.silently_fail import silently_fail
|
|
20
20
|
from langtrace_python_sdk.utils.llm import set_span_attributes
|
|
21
|
-
from opentelemetry import baggage
|
|
21
|
+
from opentelemetry import baggage, trace
|
|
22
22
|
from opentelemetry.trace import SpanKind
|
|
23
23
|
from opentelemetry.trace.status import Status, StatusCode
|
|
24
|
+
from opentelemetry.trace.propagation import set_span_in_context
|
|
24
25
|
|
|
25
26
|
from langtrace_python_sdk.constants.instrumentation.common import (
|
|
26
27
|
LANGTRACE_ADDITIONAL_SPAN_ATTRIBUTES_KEY,
|
|
@@ -56,7 +57,11 @@ def collection_patch(method, version, tracer):
|
|
|
56
57
|
|
|
57
58
|
attributes = DatabaseSpanAttributes(**span_attributes)
|
|
58
59
|
|
|
59
|
-
with tracer.start_as_current_span(
|
|
60
|
+
with tracer.start_as_current_span(
|
|
61
|
+
api["METHOD"],
|
|
62
|
+
kind=SpanKind.CLIENT,
|
|
63
|
+
context=set_span_in_context(trace.get_current_span()),
|
|
64
|
+
) as span:
|
|
60
65
|
collection_name = kwargs.get("collection_name") or args[0]
|
|
61
66
|
operation = api["OPERATION"]
|
|
62
67
|
set_span_attributes(span, "db.collection.name", collection_name)
|
|
@@ -17,10 +17,10 @@ limitations under the License.
|
|
|
17
17
|
import json
|
|
18
18
|
|
|
19
19
|
from langtrace.trace_attributes import DatabaseSpanAttributes
|
|
20
|
-
from opentelemetry import baggage
|
|
20
|
+
from opentelemetry import baggage, trace
|
|
21
21
|
from opentelemetry.trace import SpanKind
|
|
22
22
|
from opentelemetry.trace.status import Status, StatusCode
|
|
23
|
-
|
|
23
|
+
from opentelemetry.trace.propagation import set_span_in_context
|
|
24
24
|
from langtrace_python_sdk.constants.instrumentation.common import (
|
|
25
25
|
LANGTRACE_ADDITIONAL_SPAN_ATTRIBUTES_KEY,
|
|
26
26
|
SERVICE_PROVIDERS,
|
|
@@ -131,7 +131,11 @@ def create_traced_method(method_name, version, tracer, get_collection_name=None)
|
|
|
131
131
|
|
|
132
132
|
attributes = DatabaseSpanAttributes(**span_attributes)
|
|
133
133
|
|
|
134
|
-
with tracer.start_as_current_span(
|
|
134
|
+
with tracer.start_as_current_span(
|
|
135
|
+
method_name,
|
|
136
|
+
kind=SpanKind.CLIENT,
|
|
137
|
+
context=set_span_in_context(trace.get_current_span()),
|
|
138
|
+
) as span:
|
|
135
139
|
for field, value in attributes.model_dump(by_alias=True).items():
|
|
136
140
|
if value is not None:
|
|
137
141
|
span.set_attribute(field, value)
|
|
@@ -19,7 +19,12 @@ from typing import Optional
|
|
|
19
19
|
from langtrace_python_sdk.constants.exporter.langtrace_exporter import (
|
|
20
20
|
LANGTRACE_REMOTE_URL,
|
|
21
21
|
)
|
|
22
|
-
from langtrace_python_sdk.types import
|
|
22
|
+
from langtrace_python_sdk.types import (
|
|
23
|
+
DisableInstrumentations,
|
|
24
|
+
InstrumentationType,
|
|
25
|
+
InstrumentationMethods,
|
|
26
|
+
)
|
|
27
|
+
from langtrace_python_sdk.utils.langtrace_sampler import LangtraceSampler
|
|
23
28
|
from opentelemetry import trace
|
|
24
29
|
from opentelemetry.sdk.trace import TracerProvider
|
|
25
30
|
from opentelemetry.sdk.trace.export import (
|
|
@@ -45,6 +50,7 @@ from langtrace_python_sdk.instrumentation import (
|
|
|
45
50
|
PineconeInstrumentation,
|
|
46
51
|
QdrantInstrumentation,
|
|
47
52
|
WeaviateInstrumentation,
|
|
53
|
+
OllamaInstrumentor,
|
|
48
54
|
)
|
|
49
55
|
from opentelemetry.instrumentation.sqlalchemy import SQLAlchemyInstrumentor
|
|
50
56
|
from colorama import Fore
|
|
@@ -59,6 +65,7 @@ def init(
|
|
|
59
65
|
custom_remote_exporter=None,
|
|
60
66
|
api_host: Optional[str] = LANGTRACE_REMOTE_URL,
|
|
61
67
|
disable_instrumentations: Optional[DisableInstrumentations] = None,
|
|
68
|
+
disable_tracing_for_functions: Optional[InstrumentationMethods] = None,
|
|
62
69
|
):
|
|
63
70
|
|
|
64
71
|
host = (
|
|
@@ -66,7 +73,11 @@ def init(
|
|
|
66
73
|
)
|
|
67
74
|
check_if_sdk_is_outdated()
|
|
68
75
|
print(Fore.GREEN + "Initializing Langtrace SDK.." + Fore.RESET)
|
|
69
|
-
|
|
76
|
+
sampler = LangtraceSampler(disabled_methods=disable_tracing_for_functions)
|
|
77
|
+
provider = TracerProvider(
|
|
78
|
+
resource=Resource.create({"service.name": sys.argv[0]}),
|
|
79
|
+
sampler=sampler,
|
|
80
|
+
)
|
|
70
81
|
|
|
71
82
|
remote_write_exporter = (
|
|
72
83
|
LangTraceExporter(api_key=api_key, api_host=host)
|
|
@@ -96,6 +107,7 @@ def init(
|
|
|
96
107
|
"cohere": CohereInstrumentation(),
|
|
97
108
|
"weaviate": WeaviateInstrumentation(),
|
|
98
109
|
"sqlalchemy": SQLAlchemyInstrumentor(),
|
|
110
|
+
"ollama": OllamaInstrumentor(),
|
|
99
111
|
}
|
|
100
112
|
|
|
101
113
|
init_instrumentations(disable_instrumentations, all_instrumentations)
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
from typing import List, TypedDict
|
|
1
|
+
from typing import List, Literal, TypedDict
|
|
2
2
|
from enum import Enum
|
|
3
3
|
|
|
4
4
|
|
|
@@ -16,6 +16,7 @@ class InstrumentationType(Enum):
|
|
|
16
16
|
LANGCHAIN_COMMUNITY = "langchain_community"
|
|
17
17
|
LANGGRAPH = "langgraph"
|
|
18
18
|
WEAVIATE = "weaviate"
|
|
19
|
+
OLLAMA = "ollama"
|
|
19
20
|
|
|
20
21
|
@staticmethod
|
|
21
22
|
def from_string(value: str):
|
|
@@ -28,3 +29,78 @@ class InstrumentationType(Enum):
|
|
|
28
29
|
class DisableInstrumentations(TypedDict, total=False):
|
|
29
30
|
all_except: List[InstrumentationType]
|
|
30
31
|
only: List[InstrumentationType]
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class VendorMethods(TypedDict):
|
|
35
|
+
PineconeMethods = Literal[
|
|
36
|
+
"pinecone.index.upsert", "pinecone.index.query", "pinecone.index.delete"
|
|
37
|
+
]
|
|
38
|
+
AnthropicMethods = Literal["anthropic.messages.create"]
|
|
39
|
+
GroqMethods = Literal["groq.chat.completions.create"]
|
|
40
|
+
OpenaiMethods = Literal[
|
|
41
|
+
"openai.chat.completions.create",
|
|
42
|
+
"openai.embeddings.create",
|
|
43
|
+
"openai.images.generate",
|
|
44
|
+
"openai.images.edit",
|
|
45
|
+
]
|
|
46
|
+
|
|
47
|
+
ChromadbMethods = Literal[
|
|
48
|
+
"chromadb.collection.add",
|
|
49
|
+
"chromadb.collection.query",
|
|
50
|
+
"chromadb.collection.delete",
|
|
51
|
+
"chromadb.collection.peek",
|
|
52
|
+
"chromadb.collection.update",
|
|
53
|
+
"chromadb.collection.upsert",
|
|
54
|
+
"chromadb.collection.modify",
|
|
55
|
+
"chromadb.collection.count",
|
|
56
|
+
]
|
|
57
|
+
QdrantMethods = Literal[
|
|
58
|
+
"qdrantdb.add",
|
|
59
|
+
"qdrantdb.get_collection",
|
|
60
|
+
"qdrantdb.get_collections",
|
|
61
|
+
"qdrantdb.query",
|
|
62
|
+
"qdrantdb.query_batch",
|
|
63
|
+
"qdrantdb.delete",
|
|
64
|
+
"qdrantdb.discover",
|
|
65
|
+
"qdrantdb.discover_batch",
|
|
66
|
+
"qdrantdb.recommend",
|
|
67
|
+
"qdrantdb.recommend_batch",
|
|
68
|
+
"qdrantdb.retrieve",
|
|
69
|
+
"qdrantdb.search",
|
|
70
|
+
"qdrantdb.search_batch",
|
|
71
|
+
"qdrantdb.upsert",
|
|
72
|
+
"qdrantdb.count",
|
|
73
|
+
"qdrantdb.update_collection",
|
|
74
|
+
"qdrantdb.update_vectors",
|
|
75
|
+
]
|
|
76
|
+
|
|
77
|
+
CohereMethods = Literal[
|
|
78
|
+
"cohere.client.chat",
|
|
79
|
+
"cohere.client.embed",
|
|
80
|
+
"cohere.client.rerank",
|
|
81
|
+
"cohere.client.chat_stream",
|
|
82
|
+
]
|
|
83
|
+
|
|
84
|
+
LlamaIndexMethods = Literal[
|
|
85
|
+
"llamaindex.OpenAI.chat",
|
|
86
|
+
"llamaindex.RetrieverQueryEngine.query",
|
|
87
|
+
"llamaindex.VectorIndexRetriever.retrieve",
|
|
88
|
+
"llamaindex.SimpleVectorStore.query",
|
|
89
|
+
"llamaindex.RetrieverQueryEngine.retrieve",
|
|
90
|
+
]
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
class InstrumentationMethods(TypedDict):
|
|
94
|
+
open_ai: List[VendorMethods.OpenaiMethods]
|
|
95
|
+
groq: List[VendorMethods.GroqMethods]
|
|
96
|
+
pinecone: List[VendorMethods.PineconeMethods]
|
|
97
|
+
llamaindex: List[VendorMethods.LlamaIndexMethods]
|
|
98
|
+
chromadb: List[VendorMethods.ChromadbMethods]
|
|
99
|
+
qdrant: List[VendorMethods.QdrantMethods]
|
|
100
|
+
langchain: List[str]
|
|
101
|
+
langchain_core: List[str]
|
|
102
|
+
langchain_community: List[str]
|
|
103
|
+
langgraph: List[str]
|
|
104
|
+
anthropic: List[VendorMethods.AnthropicMethods]
|
|
105
|
+
cohere: List[VendorMethods.CohereMethods]
|
|
106
|
+
weaviate: List[str]
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
from typing import Optional, Sequence
|
|
2
|
+
from opentelemetry.sdk.trace.sampling import (
|
|
3
|
+
Sampler,
|
|
4
|
+
Decision,
|
|
5
|
+
SamplingResult,
|
|
6
|
+
)
|
|
7
|
+
from opentelemetry.trace import SpanKind, Link, TraceState, TraceFlags
|
|
8
|
+
from opentelemetry.util.types import Attributes
|
|
9
|
+
from opentelemetry.context import Context
|
|
10
|
+
from opentelemetry import trace
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class LangtraceSampler(Sampler):
|
|
14
|
+
_disabled_methods_names: set
|
|
15
|
+
|
|
16
|
+
def __init__(
|
|
17
|
+
self,
|
|
18
|
+
disabled_methods: dict,
|
|
19
|
+
):
|
|
20
|
+
self._disabled_methods_names = set()
|
|
21
|
+
if disabled_methods:
|
|
22
|
+
for _, methods in disabled_methods.items():
|
|
23
|
+
for method in methods:
|
|
24
|
+
self._disabled_methods_names.add(method)
|
|
25
|
+
|
|
26
|
+
def should_sample(
|
|
27
|
+
self,
|
|
28
|
+
parent_context: Optional[Context],
|
|
29
|
+
trace_id: int,
|
|
30
|
+
name: str,
|
|
31
|
+
kind: Optional[SpanKind] = None,
|
|
32
|
+
attributes: Attributes = None,
|
|
33
|
+
links: Optional[Sequence[Link]] = None,
|
|
34
|
+
trace_state: Optional["TraceState"] = None,
|
|
35
|
+
) -> SamplingResult:
|
|
36
|
+
|
|
37
|
+
parent_span = trace.get_current_span(parent_context)
|
|
38
|
+
parent_span_context = parent_span.get_span_context()
|
|
39
|
+
|
|
40
|
+
if not self._disabled_methods_names:
|
|
41
|
+
return SamplingResult(decision=Decision.RECORD_AND_SAMPLE)
|
|
42
|
+
|
|
43
|
+
if parent_context:
|
|
44
|
+
if (
|
|
45
|
+
parent_span_context.span_id != 0
|
|
46
|
+
and parent_span_context.trace_flags != TraceFlags.SAMPLED
|
|
47
|
+
):
|
|
48
|
+
return SamplingResult(decision=Decision.DROP)
|
|
49
|
+
|
|
50
|
+
if name in self._disabled_methods_names:
|
|
51
|
+
return SamplingResult(decision=Decision.DROP)
|
|
52
|
+
|
|
53
|
+
return SamplingResult(decision=Decision.RECORD_AND_SAMPLE)
|
|
54
|
+
|
|
55
|
+
def get_description(self):
|
|
56
|
+
return "Langtrace Sampler"
|
|
@@ -23,6 +23,7 @@ from typing import Optional
|
|
|
23
23
|
import requests
|
|
24
24
|
from opentelemetry import baggage, context, trace
|
|
25
25
|
from opentelemetry.trace import SpanKind
|
|
26
|
+
from opentelemetry.trace.propagation import set_span_in_context
|
|
26
27
|
|
|
27
28
|
from langtrace_python_sdk.constants.instrumentation.common import (
|
|
28
29
|
LANGTRACE_ADDITIONAL_SPAN_ATTRIBUTES_KEY,
|
|
@@ -48,7 +49,11 @@ def with_langtrace_root_span(
|
|
|
48
49
|
span_id = None
|
|
49
50
|
trace_id = None
|
|
50
51
|
|
|
51
|
-
with tracer.start_as_current_span(
|
|
52
|
+
with tracer.start_as_current_span(
|
|
53
|
+
operation_name,
|
|
54
|
+
kind=kind,
|
|
55
|
+
context=set_span_in_context(trace.get_current_span()),
|
|
56
|
+
) as span:
|
|
52
57
|
span_id = str(span.get_span_context().span_id)
|
|
53
58
|
trace_id = str(span.get_span_context().trace_id)
|
|
54
59
|
|
|
@@ -66,7 +71,11 @@ def with_langtrace_root_span(
|
|
|
66
71
|
trace_id = None
|
|
67
72
|
tracer = trace.get_tracer(__name__)
|
|
68
73
|
operation_name = name if name else func.__name__
|
|
69
|
-
with tracer.start_as_current_span(
|
|
74
|
+
with tracer.start_as_current_span(
|
|
75
|
+
operation_name,
|
|
76
|
+
kind=kind,
|
|
77
|
+
context=set_span_in_context(trace.get_current_span()),
|
|
78
|
+
) as span:
|
|
70
79
|
span_id = span.get_span_context().span_id
|
|
71
80
|
trace_id = span.get_span_context().trace_id
|
|
72
81
|
if (
|
langtrace_python_sdk/version.py
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
__version__ = "2.1.
|
|
1
|
+
__version__ = "2.1.19"
|