lmnr 0.6.21__tar.gz → 0.7.1__tar.gz
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.
- {lmnr-0.6.21 → lmnr-0.7.1}/PKG-INFO +3 -2
- {lmnr-0.6.21 → lmnr-0.7.1}/pyproject.toml +5 -3
- {lmnr-0.6.21 → lmnr-0.7.1}/src/lmnr/__init__.py +0 -4
- {lmnr-0.6.21 → lmnr-0.7.1}/src/lmnr/opentelemetry_lib/decorators/__init__.py +81 -32
- {lmnr-0.6.21 → lmnr-0.7.1}/src/lmnr/opentelemetry_lib/litellm/__init__.py +5 -2
- {lmnr-0.6.21 → lmnr-0.7.1}/src/lmnr/opentelemetry_lib/opentelemetry/instrumentation/anthropic/__init__.py +6 -2
- {lmnr-0.6.21 → lmnr-0.7.1}/src/lmnr/opentelemetry_lib/opentelemetry/instrumentation/google_genai/__init__.py +11 -2
- {lmnr-0.6.21 → lmnr-0.7.1}/src/lmnr/opentelemetry_lib/opentelemetry/instrumentation/groq/__init__.py +3 -0
- {lmnr-0.6.21 → lmnr-0.7.1}/src/lmnr/opentelemetry_lib/opentelemetry/instrumentation/langgraph/__init__.py +16 -16
- {lmnr-0.6.21 → lmnr-0.7.1}/src/lmnr/opentelemetry_lib/opentelemetry/instrumentation/openai/shared/__init__.py +6 -0
- {lmnr-0.6.21 → lmnr-0.7.1}/src/lmnr/opentelemetry_lib/opentelemetry/instrumentation/openai/shared/chat_wrappers.py +141 -9
- {lmnr-0.6.21 → lmnr-0.7.1}/src/lmnr/opentelemetry_lib/opentelemetry/instrumentation/openai/shared/completion_wrappers.py +10 -2
- {lmnr-0.6.21 → lmnr-0.7.1}/src/lmnr/opentelemetry_lib/opentelemetry/instrumentation/openai/shared/embeddings_wrappers.py +6 -2
- {lmnr-0.6.21 → lmnr-0.7.1}/src/lmnr/opentelemetry_lib/opentelemetry/instrumentation/openai/v1/assistant_wrappers.py +8 -2
- {lmnr-0.6.21 → lmnr-0.7.1}/src/lmnr/opentelemetry_lib/opentelemetry/instrumentation/openai/v1/event_handler_wrapper.py +4 -1
- {lmnr-0.6.21 → lmnr-0.7.1}/src/lmnr/opentelemetry_lib/opentelemetry/instrumentation/openai/v1/responses_wrappers.py +20 -4
- lmnr-0.7.1/src/lmnr/opentelemetry_lib/opentelemetry/instrumentation/threading/__init__.py +190 -0
- {lmnr-0.6.21 → lmnr-0.7.1}/src/lmnr/opentelemetry_lib/tracing/__init__.py +89 -1
- lmnr-0.7.1/src/lmnr/opentelemetry_lib/tracing/context.py +126 -0
- {lmnr-0.6.21 → lmnr-0.7.1}/src/lmnr/opentelemetry_lib/tracing/processor.py +5 -6
- lmnr-0.7.1/src/lmnr/opentelemetry_lib/tracing/tracer.py +47 -0
- {lmnr-0.6.21 → lmnr-0.7.1}/src/lmnr/sdk/browser/browser_use_otel.py +5 -5
- {lmnr-0.6.21 → lmnr-0.7.1}/src/lmnr/sdk/browser/patchright_otel.py +14 -0
- {lmnr-0.6.21 → lmnr-0.7.1}/src/lmnr/sdk/browser/playwright_otel.py +32 -6
- {lmnr-0.6.21 → lmnr-0.7.1}/src/lmnr/sdk/browser/pw_utils.py +119 -112
- lmnr-0.7.1/src/lmnr/sdk/browser/recorder/record.umd.min.cjs +84 -0
- {lmnr-0.6.21 → lmnr-0.7.1}/src/lmnr/sdk/client/asynchronous/resources/browser_events.py +1 -0
- {lmnr-0.6.21 → lmnr-0.7.1}/src/lmnr/sdk/laminar.py +156 -186
- {lmnr-0.6.21 → lmnr-0.7.1}/src/lmnr/sdk/types.py +17 -11
- {lmnr-0.6.21 → lmnr-0.7.1}/src/lmnr/version.py +1 -1
- lmnr-0.6.21/src/lmnr/opentelemetry_lib/tracing/context_properties.py +0 -65
- lmnr-0.6.21/src/lmnr/opentelemetry_lib/tracing/tracer.py +0 -18
- lmnr-0.6.21/src/lmnr/sdk/browser/rrweb/rrweb.umd.min.cjs +0 -98
- {lmnr-0.6.21 → lmnr-0.7.1}/README.md +0 -0
- {lmnr-0.6.21 → lmnr-0.7.1}/src/lmnr/cli.py +0 -0
- {lmnr-0.6.21 → lmnr-0.7.1}/src/lmnr/opentelemetry_lib/.flake8 +0 -0
- {lmnr-0.6.21 → lmnr-0.7.1}/src/lmnr/opentelemetry_lib/__init__.py +0 -0
- {lmnr-0.6.21 → lmnr-0.7.1}/src/lmnr/opentelemetry_lib/litellm/utils.py +0 -0
- {lmnr-0.6.21 → lmnr-0.7.1}/src/lmnr/opentelemetry_lib/opentelemetry/instrumentation/anthropic/config.py +0 -0
- {lmnr-0.6.21 → lmnr-0.7.1}/src/lmnr/opentelemetry_lib/opentelemetry/instrumentation/anthropic/event_emitter.py +0 -0
- {lmnr-0.6.21 → lmnr-0.7.1}/src/lmnr/opentelemetry_lib/opentelemetry/instrumentation/anthropic/event_models.py +0 -0
- {lmnr-0.6.21 → lmnr-0.7.1}/src/lmnr/opentelemetry_lib/opentelemetry/instrumentation/anthropic/span_utils.py +0 -0
- {lmnr-0.6.21 → lmnr-0.7.1}/src/lmnr/opentelemetry_lib/opentelemetry/instrumentation/anthropic/streaming.py +0 -0
- {lmnr-0.6.21 → lmnr-0.7.1}/src/lmnr/opentelemetry_lib/opentelemetry/instrumentation/anthropic/utils.py +0 -0
- {lmnr-0.6.21 → lmnr-0.7.1}/src/lmnr/opentelemetry_lib/opentelemetry/instrumentation/anthropic/version.py +0 -0
- {lmnr-0.6.21 → lmnr-0.7.1}/src/lmnr/opentelemetry_lib/opentelemetry/instrumentation/google_genai/config.py +0 -0
- {lmnr-0.6.21 → lmnr-0.7.1}/src/lmnr/opentelemetry_lib/opentelemetry/instrumentation/google_genai/schema_utils.py +0 -0
- {lmnr-0.6.21 → lmnr-0.7.1}/src/lmnr/opentelemetry_lib/opentelemetry/instrumentation/google_genai/utils.py +0 -0
- {lmnr-0.6.21 → lmnr-0.7.1}/src/lmnr/opentelemetry_lib/opentelemetry/instrumentation/groq/config.py +0 -0
- {lmnr-0.6.21 → lmnr-0.7.1}/src/lmnr/opentelemetry_lib/opentelemetry/instrumentation/groq/event_emitter.py +0 -0
- {lmnr-0.6.21 → lmnr-0.7.1}/src/lmnr/opentelemetry_lib/opentelemetry/instrumentation/groq/event_models.py +0 -0
- {lmnr-0.6.21 → lmnr-0.7.1}/src/lmnr/opentelemetry_lib/opentelemetry/instrumentation/groq/span_utils.py +0 -0
- {lmnr-0.6.21 → lmnr-0.7.1}/src/lmnr/opentelemetry_lib/opentelemetry/instrumentation/groq/utils.py +0 -0
- {lmnr-0.6.21 → lmnr-0.7.1}/src/lmnr/opentelemetry_lib/opentelemetry/instrumentation/groq/version.py +0 -0
- {lmnr-0.6.21 → lmnr-0.7.1}/src/lmnr/opentelemetry_lib/opentelemetry/instrumentation/langgraph/utils.py +0 -0
- {lmnr-0.6.21 → lmnr-0.7.1}/src/lmnr/opentelemetry_lib/opentelemetry/instrumentation/openai/__init__.py +0 -0
- {lmnr-0.6.21 → lmnr-0.7.1}/src/lmnr/opentelemetry_lib/opentelemetry/instrumentation/openai/shared/config.py +0 -0
- {lmnr-0.6.21 → lmnr-0.7.1}/src/lmnr/opentelemetry_lib/opentelemetry/instrumentation/openai/shared/event_emitter.py +0 -0
- {lmnr-0.6.21 → lmnr-0.7.1}/src/lmnr/opentelemetry_lib/opentelemetry/instrumentation/openai/shared/event_models.py +0 -0
- {lmnr-0.6.21 → lmnr-0.7.1}/src/lmnr/opentelemetry_lib/opentelemetry/instrumentation/openai/shared/image_gen_wrappers.py +0 -0
- {lmnr-0.6.21 → lmnr-0.7.1}/src/lmnr/opentelemetry_lib/opentelemetry/instrumentation/openai/utils.py +0 -0
- {lmnr-0.6.21 → lmnr-0.7.1}/src/lmnr/opentelemetry_lib/opentelemetry/instrumentation/openai/v0/__init__.py +0 -0
- {lmnr-0.6.21 → lmnr-0.7.1}/src/lmnr/opentelemetry_lib/opentelemetry/instrumentation/openai/v1/__init__.py +0 -0
- {lmnr-0.6.21 → lmnr-0.7.1}/src/lmnr/opentelemetry_lib/opentelemetry/instrumentation/openai/version.py +0 -0
- {lmnr-0.6.21 → lmnr-0.7.1}/src/lmnr/opentelemetry_lib/opentelemetry/instrumentation/opentelemetry/__init__.py +0 -0
- {lmnr-0.6.21 → lmnr-0.7.1}/src/lmnr/opentelemetry_lib/opentelemetry/instrumentation/skyvern/__init__.py +0 -0
- {lmnr-0.6.21 → lmnr-0.7.1}/src/lmnr/opentelemetry_lib/tracing/_instrument_initializers.py +0 -0
- {lmnr-0.6.21 → lmnr-0.7.1}/src/lmnr/opentelemetry_lib/tracing/attributes.py +0 -0
- {lmnr-0.6.21 → lmnr-0.7.1}/src/lmnr/opentelemetry_lib/tracing/exporter.py +0 -0
- {lmnr-0.6.21 → lmnr-0.7.1}/src/lmnr/opentelemetry_lib/tracing/instruments.py +0 -0
- {lmnr-0.6.21 → lmnr-0.7.1}/src/lmnr/opentelemetry_lib/utils/__init__.py +0 -0
- {lmnr-0.6.21 → lmnr-0.7.1}/src/lmnr/opentelemetry_lib/utils/json_encoder.py +0 -0
- {lmnr-0.6.21 → lmnr-0.7.1}/src/lmnr/opentelemetry_lib/utils/package_check.py +0 -0
- {lmnr-0.6.21 → lmnr-0.7.1}/src/lmnr/py.typed +0 -0
- {lmnr-0.6.21 → lmnr-0.7.1}/src/lmnr/sdk/__init__.py +0 -0
- {lmnr-0.6.21 → lmnr-0.7.1}/src/lmnr/sdk/browser/__init__.py +0 -0
- {lmnr-0.6.21 → lmnr-0.7.1}/src/lmnr/sdk/browser/utils.py +0 -0
- {lmnr-0.6.21 → lmnr-0.7.1}/src/lmnr/sdk/client/asynchronous/async_client.py +0 -0
- {lmnr-0.6.21 → lmnr-0.7.1}/src/lmnr/sdk/client/asynchronous/resources/__init__.py +0 -0
- {lmnr-0.6.21 → lmnr-0.7.1}/src/lmnr/sdk/client/asynchronous/resources/agent.py +0 -0
- {lmnr-0.6.21 → lmnr-0.7.1}/src/lmnr/sdk/client/asynchronous/resources/base.py +0 -0
- {lmnr-0.6.21 → lmnr-0.7.1}/src/lmnr/sdk/client/asynchronous/resources/evals.py +0 -0
- {lmnr-0.6.21 → lmnr-0.7.1}/src/lmnr/sdk/client/asynchronous/resources/evaluators.py +0 -0
- {lmnr-0.6.21 → lmnr-0.7.1}/src/lmnr/sdk/client/asynchronous/resources/tags.py +0 -0
- {lmnr-0.6.21 → lmnr-0.7.1}/src/lmnr/sdk/client/synchronous/resources/__init__.py +0 -0
- {lmnr-0.6.21 → lmnr-0.7.1}/src/lmnr/sdk/client/synchronous/resources/agent.py +0 -0
- {lmnr-0.6.21 → lmnr-0.7.1}/src/lmnr/sdk/client/synchronous/resources/base.py +0 -0
- {lmnr-0.6.21 → lmnr-0.7.1}/src/lmnr/sdk/client/synchronous/resources/browser_events.py +0 -0
- {lmnr-0.6.21 → lmnr-0.7.1}/src/lmnr/sdk/client/synchronous/resources/evals.py +0 -0
- {lmnr-0.6.21 → lmnr-0.7.1}/src/lmnr/sdk/client/synchronous/resources/evaluators.py +0 -0
- {lmnr-0.6.21 → lmnr-0.7.1}/src/lmnr/sdk/client/synchronous/resources/tags.py +0 -0
- {lmnr-0.6.21 → lmnr-0.7.1}/src/lmnr/sdk/client/synchronous/sync_client.py +0 -0
- {lmnr-0.6.21 → lmnr-0.7.1}/src/lmnr/sdk/datasets.py +0 -0
- {lmnr-0.6.21 → lmnr-0.7.1}/src/lmnr/sdk/decorators.py +0 -0
- {lmnr-0.6.21 → lmnr-0.7.1}/src/lmnr/sdk/eval_control.py +0 -0
- {lmnr-0.6.21 → lmnr-0.7.1}/src/lmnr/sdk/evaluations.py +0 -0
- {lmnr-0.6.21 → lmnr-0.7.1}/src/lmnr/sdk/log.py +0 -0
- {lmnr-0.6.21 → lmnr-0.7.1}/src/lmnr/sdk/utils.py +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: lmnr
|
3
|
-
Version: 0.
|
3
|
+
Version: 0.7.1
|
4
4
|
Summary: Python SDK for Laminar
|
5
5
|
Author: lmnr.ai
|
6
6
|
Author-email: lmnr.ai <founders@lmnr.ai>
|
@@ -17,14 +17,15 @@ Requires-Dist: opentelemetry-api>=1.33.0
|
|
17
17
|
Requires-Dist: opentelemetry-sdk>=1.33.0
|
18
18
|
Requires-Dist: opentelemetry-exporter-otlp-proto-http>=1.33.0
|
19
19
|
Requires-Dist: opentelemetry-exporter-otlp-proto-grpc>=1.33.0
|
20
|
+
Requires-Dist: opentelemetry-instrumentation>=0.54b0
|
20
21
|
Requires-Dist: opentelemetry-semantic-conventions>=0.54b0
|
21
22
|
Requires-Dist: opentelemetry-semantic-conventions-ai>=0.4.9
|
22
23
|
Requires-Dist: tqdm>=4.0
|
23
24
|
Requires-Dist: tenacity>=8.0
|
24
25
|
Requires-Dist: grpcio>=1
|
25
26
|
Requires-Dist: httpx>=0.25.0
|
26
|
-
Requires-Dist: opentelemetry-instrumentation-threading>=0.54b0
|
27
27
|
Requires-Dist: orjson>=3.10.18
|
28
|
+
Requires-Dist: packaging>=22.0
|
28
29
|
Requires-Dist: opentelemetry-instrumentation-alephalpha>=0.40.12 ; extra == 'alephalpha'
|
29
30
|
Requires-Dist: opentelemetry-instrumentation-alephalpha>=0.40.12 ; extra == 'all'
|
30
31
|
Requires-Dist: opentelemetry-instrumentation-bedrock>=0.40.12 ; extra == 'all'
|
@@ -6,7 +6,7 @@
|
|
6
6
|
|
7
7
|
[project]
|
8
8
|
name = "lmnr"
|
9
|
-
version = "0.
|
9
|
+
version = "0.7.1"
|
10
10
|
description = "Python SDK for Laminar"
|
11
11
|
authors = [
|
12
12
|
{ name = "lmnr.ai", email = "founders@lmnr.ai" }
|
@@ -21,6 +21,7 @@ dependencies = [
|
|
21
21
|
"opentelemetry-sdk (>=1.33.0)",
|
22
22
|
"opentelemetry-exporter-otlp-proto-http (>=1.33.0)",
|
23
23
|
"opentelemetry-exporter-otlp-proto-grpc (>=1.33.0)",
|
24
|
+
"opentelemetry-instrumentation (>=0.54b0)",
|
24
25
|
"opentelemetry-semantic-conventions (>=0.54b0)",
|
25
26
|
"opentelemetry-semantic-conventions-ai (>=0.4.9)",
|
26
27
|
"tqdm (>=4.0)",
|
@@ -36,8 +37,8 @@ dependencies = [
|
|
36
37
|
# https://github.com/grpc/grpc/issues/38490
|
37
38
|
"grpcio>=1",
|
38
39
|
"httpx>=0.25.0",
|
39
|
-
"opentelemetry-instrumentation-threading>=0.54b0",
|
40
40
|
"orjson>=3.10.18",
|
41
|
+
"packaging>=22.0",
|
41
42
|
]
|
42
43
|
# poetry would auto-generate these based on requires-python, but other build
|
43
44
|
# systems don't, so we need to specify them manually.
|
@@ -132,7 +133,7 @@ dev = [
|
|
132
133
|
"pytest-asyncio>=0.26.0",
|
133
134
|
"playwright>=1.52.0",
|
134
135
|
"vcrpy>=7.0.0",
|
135
|
-
"openai>=1.
|
136
|
+
"openai>=1.98.0",
|
136
137
|
"pytest-recording>=0.13.4",
|
137
138
|
"patchright>=1.52.3",
|
138
139
|
"google-genai>=1.19.0",
|
@@ -142,6 +143,7 @@ dev = [
|
|
142
143
|
"litellm>=1.72.6",
|
143
144
|
"groq>=0.30.0",
|
144
145
|
"anthropic>=0.57.1",
|
146
|
+
"langchain-openai>=0.3.28",
|
145
147
|
]
|
146
148
|
|
147
149
|
[build-system]
|
@@ -9,7 +9,6 @@ from .sdk.types import (
|
|
9
9
|
HumanEvaluator,
|
10
10
|
RunAgentResponseChunk,
|
11
11
|
StepChunkContent,
|
12
|
-
TracingLevel,
|
13
12
|
)
|
14
13
|
from .sdk.decorators import observe
|
15
14
|
from .sdk.types import LaminarSpanContext
|
@@ -18,7 +17,6 @@ from .opentelemetry_lib.tracing.attributes import Attributes
|
|
18
17
|
from .opentelemetry_lib.tracing.instruments import Instruments
|
19
18
|
from .opentelemetry_lib.tracing.processor import LaminarSpanProcessor
|
20
19
|
from .opentelemetry_lib.tracing.tracer import get_laminar_tracer_provider, get_tracer
|
21
|
-
from opentelemetry.trace import use_span
|
22
20
|
|
23
21
|
__all__ = [
|
24
22
|
"AgentOutput",
|
@@ -36,10 +34,8 @@ __all__ = [
|
|
36
34
|
"LaminarSpanProcessor",
|
37
35
|
"RunAgentResponseChunk",
|
38
36
|
"StepChunkContent",
|
39
|
-
"TracingLevel",
|
40
37
|
"get_laminar_tracer_provider",
|
41
38
|
"get_tracer",
|
42
39
|
"evaluate",
|
43
40
|
"observe",
|
44
|
-
"use_span",
|
45
41
|
]
|
@@ -5,13 +5,19 @@ import orjson
|
|
5
5
|
import types
|
6
6
|
from typing import Any, AsyncGenerator, Callable, Generator, Literal
|
7
7
|
|
8
|
-
from opentelemetry import trace
|
9
8
|
from opentelemetry import context as context_api
|
10
|
-
from opentelemetry.trace import Span
|
11
|
-
|
9
|
+
from opentelemetry.trace import Span, Status, StatusCode
|
10
|
+
|
11
|
+
from lmnr.opentelemetry_lib.tracing.context import (
|
12
|
+
CONTEXT_SESSION_ID_KEY,
|
13
|
+
CONTEXT_USER_ID_KEY,
|
14
|
+
attach_context,
|
15
|
+
detach_context,
|
16
|
+
get_event_attributes_from_context,
|
17
|
+
)
|
12
18
|
from lmnr.sdk.utils import get_input_from_func_args, is_method
|
13
19
|
from lmnr.opentelemetry_lib import MAX_MANUAL_SPAN_PAYLOAD_SIZE
|
14
|
-
from lmnr.opentelemetry_lib.tracing.tracer import
|
20
|
+
from lmnr.opentelemetry_lib.tracing.tracer import get_tracer_with_context
|
15
21
|
from lmnr.opentelemetry_lib.tracing.attributes import (
|
16
22
|
ASSOCIATION_PROPERTIES,
|
17
23
|
SPAN_INPUT,
|
@@ -37,6 +43,7 @@ def default_json(o):
|
|
37
43
|
try:
|
38
44
|
return str(o)
|
39
45
|
except Exception:
|
46
|
+
logger.debug("Failed to serialize data to JSON, inner type: %s", type(o))
|
40
47
|
pass
|
41
48
|
return DEFAULT_PLACEHOLDER
|
42
49
|
|
@@ -61,8 +68,13 @@ def _setup_span(
|
|
61
68
|
span_name: str, span_type: str, association_properties: dict[str, Any] | None
|
62
69
|
):
|
63
70
|
"""Set up a span with the given name, type, and association properties."""
|
64
|
-
with
|
65
|
-
span
|
71
|
+
with get_tracer_with_context() as (tracer, isolated_context):
|
72
|
+
# Create span in isolated context
|
73
|
+
span = tracer.start_span(
|
74
|
+
span_name,
|
75
|
+
context=isolated_context,
|
76
|
+
attributes={SPAN_TYPE: span_type},
|
77
|
+
)
|
66
78
|
|
67
79
|
if association_properties is not None:
|
68
80
|
for key, value in association_properties.items():
|
@@ -148,10 +160,10 @@ def _process_output(
|
|
148
160
|
pass
|
149
161
|
|
150
162
|
|
151
|
-
def _cleanup_span(span: Span,
|
163
|
+
def _cleanup_span(span: Span, wrapper: TracerWrapper):
|
152
164
|
"""Clean up span and context."""
|
153
165
|
span.end()
|
154
|
-
|
166
|
+
wrapper.pop_span_context()
|
155
167
|
|
156
168
|
|
157
169
|
def observe_base(
|
@@ -171,10 +183,25 @@ def observe_base(
|
|
171
183
|
return fn(*args, **kwargs)
|
172
184
|
|
173
185
|
span_name = name or fn.__name__
|
186
|
+
wrapper = TracerWrapper()
|
174
187
|
|
175
188
|
span = _setup_span(span_name, span_type, association_properties)
|
176
|
-
|
177
|
-
|
189
|
+
new_context = wrapper.push_span_context(span)
|
190
|
+
if session_id := association_properties.get("session_id"):
|
191
|
+
new_context = context_api.set_value(
|
192
|
+
CONTEXT_SESSION_ID_KEY, session_id, new_context
|
193
|
+
)
|
194
|
+
if user_id := association_properties.get("user_id"):
|
195
|
+
new_context = context_api.set_value(
|
196
|
+
CONTEXT_USER_ID_KEY, user_id, new_context
|
197
|
+
)
|
198
|
+
# Some auto-instrumentations are not under our control, so they
|
199
|
+
# don't have access to our isolated context. We attach the context
|
200
|
+
# to the OTEL global context, so that spans know their parent
|
201
|
+
# span and trace_id.
|
202
|
+
ctx_token = context_api.attach(new_context)
|
203
|
+
# update our isolated context too
|
204
|
+
isolated_ctx_token = attach_context(new_context)
|
178
205
|
|
179
206
|
_process_input(
|
180
207
|
span, fn, args, kwargs, ignore_input, ignore_inputs, input_formatter
|
@@ -184,9 +211,12 @@ def observe_base(
|
|
184
211
|
res = fn(*args, **kwargs)
|
185
212
|
except Exception as e:
|
186
213
|
_process_exception(span, e)
|
187
|
-
_cleanup_span(span,
|
214
|
+
_cleanup_span(span, wrapper)
|
188
215
|
raise e
|
189
|
-
|
216
|
+
finally:
|
217
|
+
# Always restore global context
|
218
|
+
context_api.detach(ctx_token)
|
219
|
+
detach_context(isolated_ctx_token)
|
190
220
|
# span will be ended in the generator
|
191
221
|
if isinstance(res, types.GeneratorType):
|
192
222
|
return _handle_generator(span, ctx_token, res)
|
@@ -201,7 +231,7 @@ def observe_base(
|
|
201
231
|
return _ahandle_generator(span, ctx_token, res)
|
202
232
|
|
203
233
|
_process_output(span, res, ignore_output, output_formatter)
|
204
|
-
_cleanup_span(span,
|
234
|
+
_cleanup_span(span, wrapper)
|
205
235
|
return res
|
206
236
|
|
207
237
|
return wrap
|
@@ -227,10 +257,25 @@ def async_observe_base(
|
|
227
257
|
return await fn(*args, **kwargs)
|
228
258
|
|
229
259
|
span_name = name or fn.__name__
|
260
|
+
wrapper = TracerWrapper()
|
230
261
|
|
231
262
|
span = _setup_span(span_name, span_type, association_properties)
|
232
|
-
|
233
|
-
|
263
|
+
new_context = wrapper.push_span_context(span)
|
264
|
+
if session_id := association_properties.get("session_id"):
|
265
|
+
new_context = context_api.set_value(
|
266
|
+
CONTEXT_SESSION_ID_KEY, session_id, new_context
|
267
|
+
)
|
268
|
+
if user_id := association_properties.get("user_id"):
|
269
|
+
new_context = context_api.set_value(
|
270
|
+
CONTEXT_USER_ID_KEY, user_id, new_context
|
271
|
+
)
|
272
|
+
# Some auto-instrumentations are not under our control, so they
|
273
|
+
# don't have access to our isolated context. We attach the context
|
274
|
+
# to the OTEL global context, so that spans know their parent
|
275
|
+
# span and trace_id.
|
276
|
+
ctx_token = context_api.attach(new_context)
|
277
|
+
# update our isolated context too
|
278
|
+
isolated_ctx_token = attach_context(new_context)
|
234
279
|
|
235
280
|
_process_input(
|
236
281
|
span, fn, args, kwargs, ignore_input, ignore_inputs, input_formatter
|
@@ -240,8 +285,12 @@ def async_observe_base(
|
|
240
285
|
res = await fn(*args, **kwargs)
|
241
286
|
except Exception as e:
|
242
287
|
_process_exception(span, e)
|
243
|
-
_cleanup_span(span,
|
288
|
+
_cleanup_span(span, wrapper)
|
244
289
|
raise e
|
290
|
+
finally:
|
291
|
+
# Always restore global context
|
292
|
+
context_api.detach(ctx_token)
|
293
|
+
detach_context(isolated_ctx_token)
|
245
294
|
|
246
295
|
# span will be ended in the generator
|
247
296
|
if isinstance(res, types.AsyncGeneratorType):
|
@@ -250,7 +299,7 @@ def async_observe_base(
|
|
250
299
|
return await _ahandle_generator(span, ctx_token, res)
|
251
300
|
|
252
301
|
_process_output(span, res, ignore_output, output_formatter)
|
253
|
-
_cleanup_span(span,
|
302
|
+
_cleanup_span(span, wrapper)
|
254
303
|
return res
|
255
304
|
|
256
305
|
return wrap
|
@@ -258,24 +307,24 @@ def async_observe_base(
|
|
258
307
|
return decorate
|
259
308
|
|
260
309
|
|
261
|
-
def _handle_generator(span: Span,
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
context_api.detach(ctx_token)
|
267
|
-
|
310
|
+
def _handle_generator(span: Span, wrapper: TracerWrapper, res: Generator):
|
311
|
+
try:
|
312
|
+
yield from res
|
313
|
+
finally:
|
314
|
+
_cleanup_span(span, wrapper)
|
268
315
|
|
269
|
-
async def _ahandle_generator(span: Span, ctx_token, res: AsyncGenerator[Any, Any]):
|
270
|
-
# async with contextlib.aclosing(res) as closing_gen:
|
271
|
-
async for part in res:
|
272
|
-
yield part
|
273
316
|
|
274
|
-
|
275
|
-
|
276
|
-
|
317
|
+
async def _ahandle_generator(span: Span, wrapper: TracerWrapper, res: AsyncGenerator):
|
318
|
+
try:
|
319
|
+
async for part in res:
|
320
|
+
yield part
|
321
|
+
finally:
|
322
|
+
_cleanup_span(span, wrapper)
|
277
323
|
|
278
324
|
|
279
325
|
def _process_exception(span: Span, e: Exception):
|
280
326
|
# Note that this `escaped` is sent as a StringValue("True"), not a boolean.
|
281
|
-
span.record_exception(
|
327
|
+
span.record_exception(
|
328
|
+
e, attributes=get_event_attributes_from_context(), escaped=True
|
329
|
+
)
|
330
|
+
span.set_status(Status(StatusCode.ERROR, str(e)))
|
@@ -7,6 +7,7 @@ from opentelemetry.trace import SpanKind, Status, StatusCode, Tracer
|
|
7
7
|
from lmnr.opentelemetry_lib.litellm.utils import model_as_dict, set_span_attribute
|
8
8
|
from lmnr.opentelemetry_lib.tracing import TracerWrapper
|
9
9
|
|
10
|
+
from lmnr.opentelemetry_lib.tracing.context import get_event_attributes_from_context
|
10
11
|
from lmnr.opentelemetry_lib.utils.package_check import is_package_installed
|
11
12
|
from lmnr.sdk.log import get_default_logger
|
12
13
|
|
@@ -141,10 +142,12 @@ try:
|
|
141
142
|
else:
|
142
143
|
span.set_status(Status(StatusCode.ERROR))
|
143
144
|
if isinstance(response_obj, Exception):
|
144
|
-
|
145
|
+
attributes = get_event_attributes_from_context()
|
146
|
+
span.record_exception(response_obj, attributes=attributes)
|
145
147
|
|
146
148
|
except Exception as e:
|
147
|
-
|
149
|
+
attributes = get_event_attributes_from_context()
|
150
|
+
span.record_exception(e, attributes=attributes)
|
148
151
|
logger.error(f"Error in Laminar LiteLLM instrumentation: {e}")
|
149
152
|
finally:
|
150
153
|
span.end(int(end_time.timestamp() * 1e9))
|
@@ -30,6 +30,8 @@ from .utils import (
|
|
30
30
|
should_emit_events,
|
31
31
|
)
|
32
32
|
from .version import __version__
|
33
|
+
|
34
|
+
from lmnr.opentelemetry_lib.tracing.context import get_current_context
|
33
35
|
from opentelemetry.instrumentation.instrumentor import BaseInstrumentor
|
34
36
|
from opentelemetry.instrumentation.utils import _SUPPRESS_INSTRUMENTATION_KEY, unwrap
|
35
37
|
from opentelemetry.metrics import Counter, Histogram, Meter, get_meter
|
@@ -396,9 +398,10 @@ def _wrap(
|
|
396
398
|
name,
|
397
399
|
kind=SpanKind.CLIENT,
|
398
400
|
attributes={
|
399
|
-
SpanAttributes.LLM_SYSTEM: "
|
401
|
+
SpanAttributes.LLM_SYSTEM: "anthropic",
|
400
402
|
SpanAttributes.LLM_REQUEST_TYPE: LLMRequestTypeValues.COMPLETION.value,
|
401
403
|
},
|
404
|
+
context=get_current_context(),
|
402
405
|
)
|
403
406
|
|
404
407
|
_handle_input(span, event_logger, kwargs)
|
@@ -493,9 +496,10 @@ async def _awrap(
|
|
493
496
|
name,
|
494
497
|
kind=SpanKind.CLIENT,
|
495
498
|
attributes={
|
496
|
-
SpanAttributes.LLM_SYSTEM: "
|
499
|
+
SpanAttributes.LLM_SYSTEM: "anthropic",
|
497
500
|
SpanAttributes.LLM_REQUEST_TYPE: LLMRequestTypeValues.COMPLETION.value,
|
498
501
|
},
|
502
|
+
context=get_current_context(),
|
499
503
|
)
|
500
504
|
await _ahandle_input(span, event_logger, kwargs)
|
501
505
|
|
@@ -8,6 +8,11 @@ from typing import AsyncGenerator, Callable, Collection, Generator
|
|
8
8
|
|
9
9
|
from google.genai import types
|
10
10
|
|
11
|
+
from lmnr.opentelemetry_lib.tracing.context import (
|
12
|
+
get_current_context,
|
13
|
+
get_event_attributes_from_context,
|
14
|
+
)
|
15
|
+
|
11
16
|
from .config import (
|
12
17
|
Config,
|
13
18
|
)
|
@@ -474,6 +479,7 @@ def _wrap(tracer: Tracer, to_wrap, wrapped, instance, args, kwargs):
|
|
474
479
|
SpanAttributes.LLM_SYSTEM: "gemini",
|
475
480
|
SpanAttributes.LLM_REQUEST_TYPE: LLMRequestTypeValues.COMPLETION.value,
|
476
481
|
},
|
482
|
+
context=get_current_context(),
|
477
483
|
)
|
478
484
|
|
479
485
|
if span.is_recording():
|
@@ -488,8 +494,9 @@ def _wrap(tracer: Tracer, to_wrap, wrapped, instance, args, kwargs):
|
|
488
494
|
span.end()
|
489
495
|
return response
|
490
496
|
except Exception as e:
|
497
|
+
attributes = get_event_attributes_from_context()
|
491
498
|
span.set_attribute(ERROR_TYPE, e.__class__.__name__)
|
492
|
-
span.record_exception(e)
|
499
|
+
span.record_exception(e, attributes=attributes)
|
493
500
|
span.set_status(Status(StatusCode.ERROR, str(e)))
|
494
501
|
span.end()
|
495
502
|
raise e
|
@@ -509,6 +516,7 @@ async def _awrap(tracer: Tracer, to_wrap, wrapped, instance, args, kwargs):
|
|
509
516
|
SpanAttributes.LLM_SYSTEM: "gemini",
|
510
517
|
SpanAttributes.LLM_REQUEST_TYPE: LLMRequestTypeValues.COMPLETION.value,
|
511
518
|
},
|
519
|
+
context=get_current_context(),
|
512
520
|
)
|
513
521
|
|
514
522
|
if span.is_recording():
|
@@ -525,8 +533,9 @@ async def _awrap(tracer: Tracer, to_wrap, wrapped, instance, args, kwargs):
|
|
525
533
|
span.end()
|
526
534
|
return response
|
527
535
|
except Exception as e:
|
536
|
+
attributes = get_event_attributes_from_context()
|
528
537
|
span.set_attribute(ERROR_TYPE, e.__class__.__name__)
|
529
|
-
span.record_exception(e)
|
538
|
+
span.record_exception(e, attributes=attributes)
|
530
539
|
span.set_status(Status(StatusCode.ERROR, str(e)))
|
531
540
|
span.end()
|
532
541
|
raise e
|
{lmnr-0.6.21 → lmnr-0.7.1}/src/lmnr/opentelemetry_lib/opentelemetry/instrumentation/groq/__init__.py
RENAMED
@@ -27,6 +27,7 @@ from .utils import (
|
|
27
27
|
should_emit_events,
|
28
28
|
)
|
29
29
|
from .version import __version__
|
30
|
+
from lmnr.opentelemetry_lib.tracing.context import get_current_context
|
30
31
|
from opentelemetry.instrumentation.instrumentor import BaseInstrumentor
|
31
32
|
from opentelemetry.instrumentation.utils import _SUPPRESS_INSTRUMENTATION_KEY, unwrap
|
32
33
|
from opentelemetry.metrics import Counter, Histogram, Meter, get_meter
|
@@ -245,6 +246,7 @@ def _wrap(
|
|
245
246
|
SpanAttributes.LLM_SYSTEM: "Groq",
|
246
247
|
SpanAttributes.LLM_REQUEST_TYPE: LLMRequestTypeValues.COMPLETION.value,
|
247
248
|
},
|
249
|
+
context=get_current_context(),
|
248
250
|
)
|
249
251
|
|
250
252
|
_handle_input(span, kwargs, event_logger)
|
@@ -327,6 +329,7 @@ async def _awrap(
|
|
327
329
|
SpanAttributes.LLM_SYSTEM: "Groq",
|
328
330
|
SpanAttributes.LLM_REQUEST_TYPE: LLMRequestTypeValues.COMPLETION.value,
|
329
331
|
},
|
332
|
+
context=get_current_context(),
|
330
333
|
)
|
331
334
|
|
332
335
|
_handle_input(span, kwargs, event_logger)
|
@@ -12,10 +12,7 @@ from langchain_core.runnables.graph import Graph
|
|
12
12
|
from opentelemetry.trace import Tracer
|
13
13
|
from wrapt import wrap_function_wrapper
|
14
14
|
from opentelemetry.trace import get_tracer
|
15
|
-
|
16
|
-
from lmnr.opentelemetry_lib.tracing.context_properties import (
|
17
|
-
update_association_properties,
|
18
|
-
)
|
15
|
+
from opentelemetry.context import get_value, attach, set_value
|
19
16
|
|
20
17
|
from opentelemetry.instrumentation.instrumentor import BaseInstrumentor
|
21
18
|
from opentelemetry.instrumentation.utils import unwrap
|
@@ -45,12 +42,13 @@ def wrap_pregel_stream(tracer: Tracer, to_wrap, wrapped, instance, args, kwargs)
|
|
45
42
|
}
|
46
43
|
for edge in graph.edges
|
47
44
|
]
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
)
|
45
|
+
d = {
|
46
|
+
"langgraph.edges": json.dumps(edges),
|
47
|
+
"langgraph.nodes": json.dumps(nodes),
|
48
|
+
}
|
49
|
+
association_properties = get_value("lmnr.langgraph.graph") or {}
|
50
|
+
association_properties.update(d)
|
51
|
+
attach(set_value("lmnr.langgraph.graph", association_properties))
|
54
52
|
return wrapped(*args, **kwargs)
|
55
53
|
|
56
54
|
|
@@ -75,12 +73,14 @@ async def async_wrap_pregel_stream(
|
|
75
73
|
}
|
76
74
|
for edge in graph.edges
|
77
75
|
]
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
)
|
76
|
+
|
77
|
+
d = {
|
78
|
+
"langgraph.edges": json.dumps(edges),
|
79
|
+
"langgraph.nodes": json.dumps(nodes),
|
80
|
+
}
|
81
|
+
association_properties = get_value("lmnr.langgraph.graph") or {}
|
82
|
+
association_properties.update(d)
|
83
|
+
attach(set_value("lmnr.langgraph.graph", association_properties))
|
84
84
|
|
85
85
|
async for item in wrapped(*args, **kwargs):
|
86
86
|
yield item
|
@@ -395,6 +395,12 @@ def get_token_count_from_string(string: str, model_name: str):
|
|
395
395
|
f"Failed to get tiktoken encoding for model_name {model_name}, error: {str(ex)}"
|
396
396
|
)
|
397
397
|
return None
|
398
|
+
except Exception as ex:
|
399
|
+
# Other exceptions in tiktoken
|
400
|
+
logger.warning(
|
401
|
+
f"Failed to get tiktoken encoding for model_name {model_name}, error: {str(ex)}"
|
402
|
+
)
|
403
|
+
return None
|
398
404
|
|
399
405
|
tiktoken_encodings[model_name] = encoding
|
400
406
|
else:
|