Skip to content

Commit ed85a5d

Browse files
committed
refactor one function, rename get_current_span, more span nesting in tests
1 parent 3dca2c4 commit ed85a5d

File tree

4 files changed

+199
-159
lines changed

4 files changed

+199
-159
lines changed

src/lmnr/opentelemetry_lib/decorators/__init__.py

Lines changed: 3 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -7,29 +7,22 @@
77

88
from lmnr.opentelemetry_lib.tracing.context import (
99
CONTEXT_METADATA_KEY,
10-
CONTEXT_SESSION_ID_KEY,
11-
CONTEXT_TRACE_TYPE_KEY,
12-
CONTEXT_USER_ID_KEY,
1310
attach_context,
1411
detach_context,
15-
get_current_context,
1612
get_event_attributes_from_context,
1713
)
1814
from lmnr.opentelemetry_lib.tracing.span import LaminarSpan
15+
from lmnr.opentelemetry_lib.tracing.utils import set_association_props_in_context
1916
from lmnr.sdk.utils import get_input_from_func_args, is_method
2017
from lmnr.opentelemetry_lib.tracing.tracer import get_tracer_with_context
2118
from lmnr.opentelemetry_lib.tracing.attributes import (
2219
ASSOCIATION_PROPERTIES,
2320
METADATA,
2421
SPAN_TYPE,
25-
USER_ID,
26-
SESSION_ID,
27-
TRACE_TYPE,
2822
)
2923
from lmnr.opentelemetry_lib.tracing import TracerWrapper
3024
from lmnr.sdk.log import get_default_logger
3125
from lmnr.sdk.utils import is_otel_attribute_value_type, json_dumps
32-
from opentelemetry.context import set_value
3326

3427
logger = get_default_logger(__name__)
3528

@@ -145,51 +138,6 @@ def _cleanup_span(span: Span, wrapper: TracerWrapper):
145138
wrapper.pop_span_context()
146139

147140

148-
def _set_association_props_in_context(span: Span):
149-
"""Set association properties from span in context before push_span_context.
150-
151-
Returns the token that needs to be detached when the span ends.
152-
"""
153-
if not isinstance(span, LaminarSpan):
154-
return None
155-
156-
props = span.laminar_association_properties
157-
user_id_key = f"{ASSOCIATION_PROPERTIES}.{USER_ID}"
158-
session_id_key = f"{ASSOCIATION_PROPERTIES}.{SESSION_ID}"
159-
trace_type_key = f"{ASSOCIATION_PROPERTIES}.{TRACE_TYPE}"
160-
161-
# Extract values from props
162-
extracted_user_id = props.get(user_id_key)
163-
extracted_session_id = props.get(session_id_key)
164-
extracted_trace_type = props.get(trace_type_key)
165-
166-
# Extract metadata from props (keys without ASSOCIATION_PROPERTIES prefix)
167-
metadata_dict = {}
168-
for key, value in props.items():
169-
if not key.startswith(f"{ASSOCIATION_PROPERTIES}."):
170-
metadata_dict[key] = value
171-
172-
# Set context with association props
173-
current_ctx = get_current_context()
174-
ctx_with_props = current_ctx
175-
if extracted_user_id:
176-
ctx_with_props = set_value(
177-
CONTEXT_USER_ID_KEY, extracted_user_id, ctx_with_props
178-
)
179-
if extracted_session_id:
180-
ctx_with_props = set_value(
181-
CONTEXT_SESSION_ID_KEY, extracted_session_id, ctx_with_props
182-
)
183-
if extracted_trace_type:
184-
ctx_with_props = set_value(
185-
CONTEXT_TRACE_TYPE_KEY, extracted_trace_type, ctx_with_props
186-
)
187-
if metadata_dict:
188-
ctx_with_props = set_value(CONTEXT_METADATA_KEY, metadata_dict, ctx_with_props)
189-
190-
return attach_context(ctx_with_props)
191-
192-
193141
def observe_base(
194142
*,
195143
name: str | None = None,
@@ -222,7 +170,7 @@ def wrap(*args, **kwargs):
222170

223171
# Set association props in context before push_span_context
224172
# so child spans inherit them
225-
assoc_props_token = _set_association_props_in_context(span)
173+
assoc_props_token = set_association_props_in_context(span)
226174
if assoc_props_token and isinstance(span, LaminarSpan):
227175
span._lmnr_assoc_props_token = assoc_props_token
228176

@@ -304,7 +252,7 @@ async def wrap(*args, **kwargs):
304252

305253
# Set association props in context before push_span_context
306254
# so child spans inherit them
307-
assoc_props_token = _set_association_props_in_context(span)
255+
assoc_props_token = set_association_props_in_context(span)
308256
if assoc_props_token and isinstance(span, LaminarSpan):
309257
span._lmnr_assoc_props_token = assoc_props_token
310258

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
from opentelemetry.trace import Span
2+
from lmnr.opentelemetry_lib.tracing.span import LaminarSpan
3+
from lmnr.opentelemetry_lib.tracing.attributes import (
4+
ASSOCIATION_PROPERTIES,
5+
USER_ID,
6+
SESSION_ID,
7+
TRACE_TYPE,
8+
)
9+
from lmnr.opentelemetry_lib.tracing.context import (
10+
get_current_context,
11+
attach_context,
12+
set_value,
13+
CONTEXT_USER_ID_KEY,
14+
CONTEXT_SESSION_ID_KEY,
15+
CONTEXT_TRACE_TYPE_KEY,
16+
CONTEXT_METADATA_KEY,
17+
)
18+
19+
20+
def set_association_props_in_context(span: Span):
21+
"""Set association properties from span in context before push_span_context.
22+
23+
Returns the token that needs to be detached when the span ends.
24+
"""
25+
if not isinstance(span, LaminarSpan):
26+
return None
27+
28+
props = span.laminar_association_properties
29+
user_id_key = f"{ASSOCIATION_PROPERTIES}.{USER_ID}"
30+
session_id_key = f"{ASSOCIATION_PROPERTIES}.{SESSION_ID}"
31+
trace_type_key = f"{ASSOCIATION_PROPERTIES}.{TRACE_TYPE}"
32+
33+
# Extract values from props
34+
extracted_user_id = props.get(user_id_key)
35+
extracted_session_id = props.get(session_id_key)
36+
extracted_trace_type = props.get(trace_type_key)
37+
38+
# Extract metadata from props (keys without ASSOCIATION_PROPERTIES prefix)
39+
metadata_dict = {}
40+
for key, value in props.items():
41+
if not key.startswith(f"{ASSOCIATION_PROPERTIES}."):
42+
metadata_dict[key] = value
43+
44+
# Set context with association props
45+
current_ctx = get_current_context()
46+
ctx_with_props = current_ctx
47+
if extracted_user_id:
48+
ctx_with_props = set_value(
49+
CONTEXT_USER_ID_KEY, extracted_user_id, ctx_with_props
50+
)
51+
if extracted_session_id:
52+
ctx_with_props = set_value(
53+
CONTEXT_SESSION_ID_KEY, extracted_session_id, ctx_with_props
54+
)
55+
if extracted_trace_type:
56+
ctx_with_props = set_value(
57+
CONTEXT_TRACE_TYPE_KEY, extracted_trace_type, ctx_with_props
58+
)
59+
if metadata_dict:
60+
ctx_with_props = set_value(CONTEXT_METADATA_KEY, metadata_dict, ctx_with_props)
61+
62+
return attach_context(ctx_with_props)

src/lmnr/sdk/laminar.py

Lines changed: 18 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
from contextlib import contextmanager
2-
from contextvars import Context, Token
2+
from contextvars import Context
33
import warnings
44
from lmnr.opentelemetry_lib import TracerManager
55
from lmnr.opentelemetry_lib.tracing import TracerWrapper, get_current_context
@@ -14,11 +14,7 @@
1414
push_span_context,
1515
set_association_prop_context,
1616
)
17-
from opentelemetry.context import get_value, set_value
18-
from lmnr.opentelemetry_lib.tracing.instruments import Instruments
19-
from lmnr.opentelemetry_lib.tracing.processor import LaminarSpanProcessor
20-
from lmnr.opentelemetry_lib.tracing.span import LaminarSpan
21-
from lmnr.opentelemetry_lib.tracing.tracer import get_tracer_with_context
17+
from opentelemetry.context import get_value
2218
from lmnr.opentelemetry_lib.tracing.attributes import (
2319
ASSOCIATION_PROPERTIES,
2420
PARENT_SPAN_IDS_PATH,
@@ -27,6 +23,11 @@
2723
Attributes,
2824
SPAN_TYPE,
2925
)
26+
from lmnr.opentelemetry_lib.tracing.instruments import Instruments
27+
from lmnr.opentelemetry_lib.tracing.processor import LaminarSpanProcessor
28+
from lmnr.opentelemetry_lib.tracing.span import LaminarSpan
29+
from lmnr.opentelemetry_lib.tracing.tracer import get_tracer_with_context
30+
from lmnr.opentelemetry_lib.tracing.utils import set_association_props_in_context
3031
from lmnr.sdk.utils import get_otel_env_var
3132

3233
from opentelemetry import trace
@@ -69,54 +70,6 @@ class ParsedParentSpanContext(TypedDict):
6970
metadata: dict[str, Any] | None
7071

7172

72-
def _set_span_association_props_in_context(span: Span) -> Token[Context] | None:
73-
"""Set association properties from span in context.
74-
75-
Extracts association properties from span attributes and sets them in the
76-
isolated context so child spans can inherit them.
77-
78-
Returns the token that needs to be stored on the span for cleanup.
79-
"""
80-
if not isinstance(span, LaminarSpan):
81-
return None
82-
83-
props = span.laminar_association_properties
84-
user_id_key = f"{ASSOCIATION_PROPERTIES}.{USER_ID}"
85-
session_id_key = f"{ASSOCIATION_PROPERTIES}.{SESSION_ID}"
86-
trace_type_key = f"{ASSOCIATION_PROPERTIES}.{TRACE_TYPE}"
87-
88-
# Extract values from props
89-
extracted_user_id = props.get(user_id_key)
90-
extracted_session_id = props.get(session_id_key)
91-
extracted_trace_type = props.get(trace_type_key)
92-
93-
# Extract metadata from props (keys without ASSOCIATION_PROPERTIES prefix)
94-
metadata_dict = {}
95-
for key, value in props.items():
96-
if not key.startswith(f"{ASSOCIATION_PROPERTIES}."):
97-
metadata_dict[key] = value
98-
99-
# Set context with association props
100-
current_ctx = get_current_context()
101-
ctx_with_props = current_ctx
102-
if extracted_user_id:
103-
ctx_with_props = set_value(
104-
CONTEXT_USER_ID_KEY, extracted_user_id, ctx_with_props
105-
)
106-
if extracted_session_id:
107-
ctx_with_props = set_value(
108-
CONTEXT_SESSION_ID_KEY, extracted_session_id, ctx_with_props
109-
)
110-
if extracted_trace_type:
111-
ctx_with_props = set_value(
112-
CONTEXT_TRACE_TYPE_KEY, extracted_trace_type, ctx_with_props
113-
)
114-
if metadata_dict:
115-
ctx_with_props = set_value(CONTEXT_METADATA_KEY, metadata_dict, ctx_with_props)
116-
117-
return attach_context(ctx_with_props)
118-
119-
12073
def _parse_parent_span_context(
12174
parent_span_context: LaminarSpanContext | dict | str | None,
12275
logger: logging.Logger,
@@ -883,7 +836,7 @@ def use_span(
883836
try:
884837
# Set association props in context before push_span_context
885838
# so child spans inherit them
886-
assoc_props_token = _set_span_association_props_in_context(span)
839+
assoc_props_token = set_association_props_in_context(span)
887840
if assoc_props_token and isinstance(span, LaminarSpan):
888841
span._lmnr_assoc_props_token = assoc_props_token
889842

@@ -1039,7 +992,7 @@ def bar():
1039992

1040993
# Set association props in context before push_span_context
1041994
# so child spans inherit them
1042-
assoc_props_token = _set_span_association_props_in_context(span)
995+
assoc_props_token = set_association_props_in_context(span)
1043996
if assoc_props_token and isinstance(span, LaminarSpan):
1044997
span._lmnr_assoc_props_token = assoc_props_token
1045998

@@ -1062,7 +1015,7 @@ def set_span_output(cls, output: Any = None):
10621015
output (Any, optional): output of the span. Will be sent as an\
10631016
attribute, so must be json serializable. Defaults to None.
10641017
"""
1065-
span = cls.current_span()
1018+
span = cls.get_current_span()
10661019
if span is None:
10671020
return
10681021
span.set_output(output)
@@ -1094,7 +1047,7 @@ def set_span_attributes(
10941047
Args:
10951048
attributes (dict[Attributes | str, Any]): attributes to set for the span
10961049
"""
1097-
span = cls.current_span()
1050+
span = cls.get_current_span()
10981051
if span == trace.INVALID_SPAN or span is None:
10991052
return
11001053

@@ -1116,7 +1069,7 @@ def get_laminar_span_context(
11161069
if not cls.is_initialized():
11171070
return None
11181071

1119-
span = span or cls.current_span()
1072+
span = span or cls.get_current_span()
11201073
if span == trace.INVALID_SPAN or span is None:
11211074
return None
11221075
if not isinstance(span, LaminarSpan):
@@ -1171,7 +1124,7 @@ def deserialize_span_context(cls, span_context: dict | str) -> LaminarSpanContex
11711124
return LaminarSpanContext.deserialize(span_context)
11721125

11731126
@classmethod
1174-
def current_span(cls, context: Context | None = None) -> LaminarSpan | None:
1127+
def get_current_span(cls, context: Context | None = None) -> LaminarSpan | None:
11751128
"""Get the current active span. If a context is provided, the span will
11761129
be retrieved from that context.
11771130
@@ -1237,15 +1190,15 @@ def set_span_tags(cls, tags: list[str]):
12371190
if not cls.is_initialized():
12381191
return
12391192

1240-
span = cls.current_span()
1193+
span = cls.get_current_span()
12411194
if span is None:
12421195
return
12431196
span.set_tags(tags)
12441197

12451198
@classmethod
12461199
def add_span_tags(cls, tags: list[str]):
12471200
"""Add tags to the current span."""
1248-
span = cls.current_span()
1201+
span = cls.get_current_span()
12491202
if span is None:
12501203
return
12511204
span.add_tags(tags)
@@ -1263,7 +1216,7 @@ def set_trace_session_id(cls, session_id: str | None = None):
12631216

12641217
context = set_association_prop_context(session_id=session_id, attach=True)
12651218

1266-
span = cls.current_span(context=context)
1219+
span = cls.get_current_span(context=context)
12671220
if span is None:
12681221
cls.__logger.warning("No active span to set session id on")
12691222
return
@@ -1282,7 +1235,7 @@ def set_trace_user_id(cls, user_id: str | None = None):
12821235

12831236
context = set_association_prop_context(user_id=user_id, attach=True)
12841237

1285-
span = cls.current_span(context=context)
1238+
span = cls.get_current_span(context=context)
12861239
if span is None:
12871240
cls.__logger.warning("No active span to set user id on")
12881241
return
@@ -1300,7 +1253,7 @@ def set_trace_metadata(cls, metadata: dict[str, AttributeValue]):
13001253

13011254
merged_metadata = {**cls.__global_metadata, **(metadata or {})}
13021255

1303-
span = cls.current_span()
1256+
span = cls.get_current_span()
13041257
if span is None:
13051258
cls.__logger.warning("No active span to set metadata on")
13061259
return

0 commit comments

Comments
 (0)