lmnr 0.4.33__py3-none-any.whl → 0.4.35__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.
- lmnr/sdk/laminar.py +80 -5
- lmnr/traceloop_sdk/tracing/tracing.py +32 -19
- lmnr/traceloop_sdk/utils/package_check.py +3 -5
- {lmnr-0.4.33.dist-info → lmnr-0.4.35.dist-info}/METADATA +1 -1
- {lmnr-0.4.33.dist-info → lmnr-0.4.35.dist-info}/RECORD +8 -8
- {lmnr-0.4.33.dist-info → lmnr-0.4.35.dist-info}/LICENSE +0 -0
- {lmnr-0.4.33.dist-info → lmnr-0.4.35.dist-info}/WHEEL +0 -0
- {lmnr-0.4.33.dist-info → lmnr-0.4.35.dist-info}/entry_points.txt +0 -0
lmnr/sdk/laminar.py
CHANGED
@@ -1,18 +1,19 @@
|
|
1
1
|
from contextlib import contextmanager
|
2
2
|
from contextvars import Context
|
3
|
-
from opentelemetry import context, trace
|
4
|
-
from opentelemetry.util.types import AttributeValue
|
5
|
-
from opentelemetry.context import set_value, attach, detach
|
6
3
|
from lmnr.traceloop_sdk import Traceloop
|
7
4
|
from lmnr.traceloop_sdk.instruments import Instruments
|
8
5
|
from lmnr.traceloop_sdk.tracing import get_tracer
|
9
6
|
from lmnr.traceloop_sdk.tracing.attributes import (
|
7
|
+
ASSOCIATION_PROPERTIES,
|
10
8
|
Attributes,
|
11
9
|
SPAN_TYPE,
|
12
10
|
OVERRIDE_PARENT_SPAN,
|
13
11
|
)
|
14
12
|
from lmnr.traceloop_sdk.decorators.base import json_dumps
|
13
|
+
from opentelemetry import context, trace
|
14
|
+
from opentelemetry.context import attach, detach, set_value
|
15
15
|
from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import OTLPSpanExporter
|
16
|
+
from opentelemetry.util.types import AttributeValue
|
16
17
|
|
17
18
|
from pydantic.alias_generators import to_snake
|
18
19
|
from typing import Any, Literal, Optional, Set, Union
|
@@ -39,6 +40,7 @@ from lmnr.traceloop_sdk.tracing.attributes import (
|
|
39
40
|
)
|
40
41
|
from lmnr.traceloop_sdk.tracing.tracing import (
|
41
42
|
get_span_path,
|
43
|
+
remove_association_properties,
|
42
44
|
set_association_properties,
|
43
45
|
update_association_properties,
|
44
46
|
)
|
@@ -298,6 +300,7 @@ class Laminar:
|
|
298
300
|
span_type: Union[Literal["DEFAULT"], Literal["LLM"]] = "DEFAULT",
|
299
301
|
context: Optional[Context] = None,
|
300
302
|
trace_id: Optional[uuid.UUID] = None,
|
303
|
+
labels: Optional[dict[str, str]] = None,
|
301
304
|
):
|
302
305
|
"""Start a new span as the current span. Useful for manual
|
303
306
|
instrumentation. If `span_type` is set to `"LLM"`, you should report
|
@@ -323,6 +326,8 @@ class Laminar:
|
|
323
326
|
trace_id (Optional[uuid.UUID], optional): [EXPERIMENTAL] override\
|
324
327
|
the trace id for the span. If not provided, use the current\
|
325
328
|
trace id. Defaults to None.
|
329
|
+
labels (Optional[dict[str, str]], optional): labels to set for the\
|
330
|
+
span. Defaults to None.
|
326
331
|
"""
|
327
332
|
|
328
333
|
with get_tracer() as tracer:
|
@@ -345,10 +350,26 @@ class Laminar:
|
|
345
350
|
" is not a valid UUID"
|
346
351
|
)
|
347
352
|
ctx_token = attach(ctx)
|
353
|
+
label_props = {}
|
354
|
+
try:
|
355
|
+
if labels:
|
356
|
+
label_props = dict(
|
357
|
+
(f"{ASSOCIATION_PROPERTIES}.label.{k}", json_dumps(v))
|
358
|
+
for k, v in labels.items() # noqa: F821
|
359
|
+
)
|
360
|
+
except Exception:
|
361
|
+
cls.__logger.warning(
|
362
|
+
f"`start_as_current_span` Could not set labels: {labels}. "
|
363
|
+
"They will be propagated to the next span."
|
364
|
+
)
|
348
365
|
with tracer.start_as_current_span(
|
349
366
|
name,
|
350
367
|
context=ctx,
|
351
|
-
attributes={
|
368
|
+
attributes={
|
369
|
+
SPAN_PATH: span_path,
|
370
|
+
SPAN_TYPE: span_type,
|
371
|
+
**(label_props),
|
372
|
+
},
|
352
373
|
) as span:
|
353
374
|
if trace_id is not None and isinstance(trace_id, uuid.UUID):
|
354
375
|
span.set_attribute(OVERRIDE_PARENT_SPAN, True)
|
@@ -365,6 +386,41 @@ class Laminar:
|
|
365
386
|
except Exception:
|
366
387
|
pass
|
367
388
|
|
389
|
+
@classmethod
|
390
|
+
@contextmanager
|
391
|
+
def with_labels(cls, labels: dict[str, str], context: Optional[Context] = None):
|
392
|
+
"""Set labels for spans within this `with` context. This is useful for
|
393
|
+
adding labels to the spans created in the auto-instrumentations.
|
394
|
+
|
395
|
+
Requirements:
|
396
|
+
- Labels must be created in your project in advance.
|
397
|
+
- Keys must be strings from your label names.
|
398
|
+
- Values must be strings matching the label's allowed values.
|
399
|
+
|
400
|
+
Usage example:
|
401
|
+
```python
|
402
|
+
with Laminar.with_labels({"sentiment": "positive"}):
|
403
|
+
openai_client.chat.completions.create()
|
404
|
+
```
|
405
|
+
"""
|
406
|
+
with get_tracer():
|
407
|
+
label_props = labels.copy()
|
408
|
+
label_props = dict(
|
409
|
+
(f"label.{k}", json_dumps(v)) for k, v in label_props.items()
|
410
|
+
)
|
411
|
+
update_association_properties(
|
412
|
+
label_props, set_on_current_span=False, context=context
|
413
|
+
)
|
414
|
+
yield
|
415
|
+
try:
|
416
|
+
remove_association_properties(label_props)
|
417
|
+
except Exception:
|
418
|
+
cls.__logger.warning(
|
419
|
+
f"`with_labels` Could not remove labels: {labels}. They will be "
|
420
|
+
"propagated to the next span."
|
421
|
+
)
|
422
|
+
pass
|
423
|
+
|
368
424
|
@classmethod
|
369
425
|
def start_span(
|
370
426
|
cls,
|
@@ -373,6 +429,7 @@ class Laminar:
|
|
373
429
|
span_type: Union[Literal["DEFAULT"], Literal["LLM"]] = "DEFAULT",
|
374
430
|
context: Optional[Context] = None,
|
375
431
|
trace_id: Optional[uuid.UUID] = None,
|
432
|
+
labels: Optional[dict[str, str]] = None,
|
376
433
|
):
|
377
434
|
"""Start a new span. Useful for manual instrumentation.
|
378
435
|
If `span_type` is set to `"LLM"`, you should report usage and response
|
@@ -417,6 +474,8 @@ class Laminar:
|
|
417
474
|
trace_id (Optional[uuid.UUID], optional): [EXPERIMENTAL] override\
|
418
475
|
the trace id for the span. If not provided, use the current\
|
419
476
|
trace id. Defaults to None.
|
477
|
+
labels (Optional[dict[str, str]], optional): labels to set for the\
|
478
|
+
span. Defaults to None.
|
420
479
|
"""
|
421
480
|
with get_tracer() as tracer:
|
422
481
|
span_path = get_span_path(name)
|
@@ -437,10 +496,26 @@ class Laminar:
|
|
437
496
|
"trace_id provided to `Laminar.start_span`"
|
438
497
|
" is not a valid UUID"
|
439
498
|
)
|
499
|
+
label_props = {}
|
500
|
+
try:
|
501
|
+
if labels:
|
502
|
+
label_props = dict(
|
503
|
+
(f"{ASSOCIATION_PROPERTIES}.label.{k}", json_dumps(v))
|
504
|
+
for k, v in labels.items() # noqa: F821
|
505
|
+
)
|
506
|
+
except Exception:
|
507
|
+
cls.__logger.warning(
|
508
|
+
f"`start_span` Could not set labels: {labels}. They will be "
|
509
|
+
"propagated to the next span."
|
510
|
+
)
|
440
511
|
span = tracer.start_span(
|
441
512
|
name,
|
442
513
|
context=ctx,
|
443
|
-
attributes={
|
514
|
+
attributes={
|
515
|
+
SPAN_PATH: span_path,
|
516
|
+
SPAN_TYPE: span_type,
|
517
|
+
**(label_props),
|
518
|
+
},
|
444
519
|
)
|
445
520
|
if trace_id is not None and isinstance(trace_id, uuid.UUID):
|
446
521
|
span.set_attribute(OVERRIDE_PARENT_SPAN, True)
|
@@ -1,8 +1,18 @@
|
|
1
1
|
import atexit
|
2
|
+
import copy
|
2
3
|
import logging
|
3
|
-
import os
|
4
4
|
|
5
5
|
|
6
|
+
from contextvars import Context
|
7
|
+
from lmnr.traceloop_sdk.instruments import Instruments
|
8
|
+
from lmnr.traceloop_sdk.tracing.attributes import (
|
9
|
+
ASSOCIATION_PROPERTIES,
|
10
|
+
SPAN_INSTRUMENTATION_SOURCE,
|
11
|
+
SPAN_PATH,
|
12
|
+
)
|
13
|
+
from lmnr.traceloop_sdk.tracing.content_allow_list import ContentAllowList
|
14
|
+
from lmnr.traceloop_sdk.utils import is_notebook
|
15
|
+
from lmnr.traceloop_sdk.utils.package_check import is_package_installed
|
6
16
|
from opentelemetry import trace
|
7
17
|
from opentelemetry.exporter.otlp.proto.http.trace_exporter import (
|
8
18
|
OTLPSpanExporter as HTTPExporter,
|
@@ -10,28 +20,19 @@ from opentelemetry.exporter.otlp.proto.http.trace_exporter import (
|
|
10
20
|
from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import (
|
11
21
|
OTLPSpanExporter as GRPCExporter,
|
12
22
|
)
|
23
|
+
from opentelemetry.instrumentation.threading import ThreadingInstrumentor
|
24
|
+
from opentelemetry.context import get_value, attach, set_value
|
25
|
+
from opentelemetry.propagate import set_global_textmap
|
26
|
+
from opentelemetry.propagators.textmap import TextMapPropagator
|
13
27
|
from opentelemetry.sdk.resources import Resource
|
14
28
|
from opentelemetry.sdk.trace import TracerProvider, SpanProcessor
|
15
|
-
from opentelemetry.propagators.textmap import TextMapPropagator
|
16
|
-
from opentelemetry.propagate import set_global_textmap
|
17
29
|
from opentelemetry.sdk.trace.export import (
|
18
30
|
SpanExporter,
|
19
31
|
SimpleSpanProcessor,
|
20
32
|
BatchSpanProcessor,
|
21
33
|
)
|
22
34
|
from opentelemetry.trace import get_tracer_provider, ProxyTracerProvider
|
23
|
-
from opentelemetry.context import get_value, attach, set_value
|
24
|
-
from opentelemetry.instrumentation.threading import ThreadingInstrumentor
|
25
35
|
|
26
|
-
from lmnr.traceloop_sdk.instruments import Instruments
|
27
|
-
from lmnr.traceloop_sdk.tracing.attributes import (
|
28
|
-
ASSOCIATION_PROPERTIES,
|
29
|
-
SPAN_INSTRUMENTATION_SOURCE,
|
30
|
-
SPAN_PATH,
|
31
|
-
)
|
32
|
-
from lmnr.traceloop_sdk.tracing.content_allow_list import ContentAllowList
|
33
|
-
from lmnr.traceloop_sdk.utils import is_notebook
|
34
|
-
from lmnr.traceloop_sdk.utils.package_check import is_package_installed
|
35
36
|
from typing import Dict, Optional, Set
|
36
37
|
|
37
38
|
|
@@ -188,15 +189,27 @@ def set_association_properties(properties: dict) -> None:
|
|
188
189
|
_set_association_properties_attributes(span, properties)
|
189
190
|
|
190
191
|
|
191
|
-
def update_association_properties(
|
192
|
+
def update_association_properties(
|
193
|
+
properties: dict,
|
194
|
+
set_on_current_span: bool = True,
|
195
|
+
context: Optional[Context] = None,
|
196
|
+
) -> None:
|
192
197
|
"""Only adds or updates properties that are not already present"""
|
193
|
-
association_properties = get_value("association_properties") or {}
|
198
|
+
association_properties = get_value("association_properties", context) or {}
|
194
199
|
association_properties.update(properties)
|
195
200
|
|
196
|
-
attach(set_value("association_properties", association_properties))
|
201
|
+
attach(set_value("association_properties", association_properties, context))
|
197
202
|
|
198
|
-
|
199
|
-
|
203
|
+
if set_on_current_span:
|
204
|
+
span = trace.get_current_span()
|
205
|
+
_set_association_properties_attributes(span, properties)
|
206
|
+
|
207
|
+
|
208
|
+
def remove_association_properties(properties: dict) -> None:
|
209
|
+
props: dict = copy.copy(get_value("association_properties") or {})
|
210
|
+
for k in properties.keys():
|
211
|
+
props.pop(k, None)
|
212
|
+
set_association_properties(props)
|
200
213
|
|
201
214
|
|
202
215
|
def _set_association_properties_attributes(span, properties: dict) -> None:
|
@@ -1,8 +1,6 @@
|
|
1
|
-
import
|
2
|
-
|
3
|
-
installed_packages = {p.key for p in pkg_resources.working_set}
|
1
|
+
from importlib.metadata import distributions
|
4
2
|
|
3
|
+
installed_packages = {dist.metadata["Name"].lower() for dist in distributions()}
|
5
4
|
|
6
5
|
def is_package_installed(package_name: str) -> bool:
|
7
|
-
|
8
|
-
return package_name in installed_packages
|
6
|
+
return package_name.lower() in installed_packages
|
@@ -4,7 +4,7 @@ lmnr/sdk/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
4
4
|
lmnr/sdk/datasets.py,sha256=w8U9E6fvetAo65Cb2CbYzlfhY8CfXAR-VysrakG6-4I,1591
|
5
5
|
lmnr/sdk/decorators.py,sha256=ZSDaEZyjo-RUzRCltsNbe6x0t9SKl2xRQ2q4uaKvXtk,2250
|
6
6
|
lmnr/sdk/evaluations.py,sha256=5Vfyp0aIjuGpqfuM3cqsaaLpcoO7z6lcOOKxnyHCNHk,16264
|
7
|
-
lmnr/sdk/laminar.py,sha256=
|
7
|
+
lmnr/sdk/laminar.py,sha256=DkZQjAwkRzHCQ9V9XUF3fSD76zAaRQBNKQ48GdCscqQ,26382
|
8
8
|
lmnr/sdk/log.py,sha256=cZBeUoSK39LMEV-X4-eEhTWOciULRfHaKfRK8YqIM8I,1532
|
9
9
|
lmnr/sdk/types.py,sha256=qGD1tkGszd-_sZJaZ_Zx9U_CdUYzoDkUeN2g-o48Gls,5588
|
10
10
|
lmnr/sdk/utils.py,sha256=Uk8y15x-sd5tP2ERONahElLDJVEy_3dA_1_5g9A6auY,3358
|
@@ -39,14 +39,14 @@ lmnr/traceloop_sdk/tracing/__init__.py,sha256=Ckq7zCM26VdJVB5tIZv0GTPyMZKyfso_KW
|
|
39
39
|
lmnr/traceloop_sdk/tracing/attributes.py,sha256=h970zmb7yTszzf2oHBfOY3cDYhE6O7LhkiHLqa_7x1k,1261
|
40
40
|
lmnr/traceloop_sdk/tracing/content_allow_list.py,sha256=3feztm6PBWNelc8pAZUcQyEGyeSpNiVKjOaDk65l2ps,846
|
41
41
|
lmnr/traceloop_sdk/tracing/context_manager.py,sha256=csVlB6kDmbgSPsROHwnddvGGblx55v6lJMRj0wsSMQM,304
|
42
|
-
lmnr/traceloop_sdk/tracing/tracing.py,sha256=
|
42
|
+
lmnr/traceloop_sdk/tracing/tracing.py,sha256=enZ6uRH9H9ZShPl4LK9B6ThzOZrBBK1Bap4l3NoqhQ8,29145
|
43
43
|
lmnr/traceloop_sdk/utils/__init__.py,sha256=pNhf0G3vTd5ccoc03i1MXDbricSaiqCbi1DLWhSekK8,604
|
44
44
|
lmnr/traceloop_sdk/utils/in_memory_span_exporter.py,sha256=H_4TRaThMO1H6vUQ0OpQvzJk_fZH0OOsRAM1iZQXsR8,2112
|
45
45
|
lmnr/traceloop_sdk/utils/json_encoder.py,sha256=dK6b_axr70IYL7Vv-bu4wntvDDuyntoqsHaddqX7P58,463
|
46
|
-
lmnr/traceloop_sdk/utils/package_check.py,sha256=
|
46
|
+
lmnr/traceloop_sdk/utils/package_check.py,sha256=Ki74WZME-ASF0fx7RXSIMsULGYUzI86sOINi1EGrc_Y,235
|
47
47
|
lmnr/traceloop_sdk/version.py,sha256=OlatFEFA4ttqSSIiV8jdE-sq3KG5zu2hnC4B4mzWF3s,23
|
48
|
-
lmnr-0.4.
|
49
|
-
lmnr-0.4.
|
50
|
-
lmnr-0.4.
|
51
|
-
lmnr-0.4.
|
52
|
-
lmnr-0.4.
|
48
|
+
lmnr-0.4.35.dist-info/LICENSE,sha256=67b_wJHVV1CBaWkrKFWU1wyqTPSdzH77Ls-59631COg,10411
|
49
|
+
lmnr-0.4.35.dist-info/METADATA,sha256=WRv37EYH3Zoe1ccA9wxGx8Ote0A3mVSKArfi98yb7P4,10322
|
50
|
+
lmnr-0.4.35.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
|
51
|
+
lmnr-0.4.35.dist-info/entry_points.txt,sha256=K1jE20ww4jzHNZLnsfWBvU3YKDGBgbOiYG5Y7ivQcq4,37
|
52
|
+
lmnr-0.4.35.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|