ioa-observe-sdk 1.0.16__py3-none-any.whl → 1.0.17__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.
- ioa_observe/sdk/instrumentations/slim.py +376 -128
- {ioa_observe_sdk-1.0.16.dist-info → ioa_observe_sdk-1.0.17.dist-info}/METADATA +1 -1
- {ioa_observe_sdk-1.0.16.dist-info → ioa_observe_sdk-1.0.17.dist-info}/RECORD +6 -6
- {ioa_observe_sdk-1.0.16.dist-info → ioa_observe_sdk-1.0.17.dist-info}/WHEEL +0 -0
- {ioa_observe_sdk-1.0.16.dist-info → ioa_observe_sdk-1.0.17.dist-info}/licenses/LICENSE.md +0 -0
- {ioa_observe_sdk-1.0.16.dist-info → ioa_observe_sdk-1.0.17.dist-info}/top_level.txt +0 -0
|
@@ -7,7 +7,7 @@ import json
|
|
|
7
7
|
import base64
|
|
8
8
|
import threading
|
|
9
9
|
|
|
10
|
-
from opentelemetry import baggage
|
|
10
|
+
from opentelemetry import baggage, context
|
|
11
11
|
from opentelemetry.baggage.propagation import W3CBaggagePropagator
|
|
12
12
|
from opentelemetry.instrumentation.instrumentor import BaseInstrumentor
|
|
13
13
|
from opentelemetry.trace.propagation.tracecontext import TraceContextTextMapPropagator
|
|
@@ -16,7 +16,7 @@ from ioa_observe.sdk import TracerWrapper
|
|
|
16
16
|
from ioa_observe.sdk.client import kv_store
|
|
17
17
|
from ioa_observe.sdk.tracing import set_session_id, get_current_traceparent
|
|
18
18
|
|
|
19
|
-
_instruments = ("slim-bindings >= 0.
|
|
19
|
+
_instruments = ("slim-bindings >= 0.4",)
|
|
20
20
|
_global_tracer = None
|
|
21
21
|
_kv_lock = threading.RLock() # Add thread-safety for kv_store operations
|
|
22
22
|
|
|
@@ -38,123 +38,275 @@ class SLIMInstrumentor(BaseInstrumentor):
|
|
|
38
38
|
"No module named 'slim_bindings'. Please install it first."
|
|
39
39
|
)
|
|
40
40
|
|
|
41
|
-
# Instrument `publish`
|
|
42
|
-
|
|
41
|
+
# Instrument `publish` method - handles multiple signatures
|
|
42
|
+
if hasattr(slim_bindings.Slim, "publish"):
|
|
43
|
+
original_publish = slim_bindings.Slim.publish
|
|
44
|
+
|
|
45
|
+
@functools.wraps(original_publish)
|
|
46
|
+
async def instrumented_publish(self, *args, **kwargs):
|
|
47
|
+
if _global_tracer:
|
|
48
|
+
with _global_tracer.start_as_current_span("slim.publish") as span:
|
|
49
|
+
traceparent = get_current_traceparent()
|
|
50
|
+
|
|
51
|
+
# Handle different publish signatures
|
|
52
|
+
# Definition 1: publish(session, message, topic_name) - v0.4.0+ group chat
|
|
53
|
+
# Definition 2: publish(session, message, organization, namespace, topic) - legacy
|
|
54
|
+
if len(args) >= 3:
|
|
55
|
+
session_arg = args[0] if args else None
|
|
56
|
+
if hasattr(session_arg, "id"):
|
|
57
|
+
span.set_attribute(
|
|
58
|
+
"slim.session.id", str(session_arg.id)
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
# Check if third argument is PyName (new API) or string (legacy API)
|
|
62
|
+
if len(args) >= 3 and hasattr(args[2], "organization"):
|
|
63
|
+
# New API: args[2] is PyName
|
|
64
|
+
topic_name = args[2]
|
|
65
|
+
span.set_attribute(
|
|
66
|
+
"slim.topic.organization", topic_name.organization
|
|
67
|
+
)
|
|
68
|
+
span.set_attribute(
|
|
69
|
+
"slim.topic.namespace", topic_name.namespace
|
|
70
|
+
)
|
|
71
|
+
span.set_attribute("slim.topic.app", topic_name.app)
|
|
72
|
+
else:
|
|
73
|
+
traceparent = get_current_traceparent()
|
|
43
74
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
try:
|
|
72
|
-
decoded_message = message.decode("utf-8")
|
|
73
|
-
try:
|
|
74
|
-
# If it's already a JSON structure, preserve it
|
|
75
|
-
original_message = json.loads(decoded_message)
|
|
76
|
-
if isinstance(original_message, dict):
|
|
77
|
-
# Preserve all original fields and merge/update headers
|
|
78
|
-
wrapped_message = original_message.copy()
|
|
79
|
-
existing_headers = wrapped_message.get("headers", {})
|
|
80
|
-
existing_headers.update(headers)
|
|
81
|
-
wrapped_message["headers"] = existing_headers
|
|
82
|
-
else:
|
|
83
|
-
# If it's not a dict, wrap it as payload
|
|
84
|
-
wrapped_message = {
|
|
85
|
-
"headers": headers,
|
|
86
|
-
"payload": original_message,
|
|
87
|
-
}
|
|
88
|
-
except json.JSONDecodeError:
|
|
89
|
-
# If it's not JSON, treat as raw payload
|
|
90
|
-
wrapped_message = {
|
|
91
|
-
"headers": headers,
|
|
92
|
-
"payload": decoded_message,
|
|
93
|
-
}
|
|
94
|
-
except UnicodeDecodeError:
|
|
95
|
-
# If it can't be decoded, base64 encode it
|
|
96
|
-
wrapped_message = {
|
|
97
|
-
"headers": headers,
|
|
98
|
-
"payload": base64.b64encode(message).decode("utf-8"),
|
|
99
|
-
}
|
|
100
|
-
elif isinstance(message, str):
|
|
101
|
-
try:
|
|
102
|
-
# Try to parse as JSON first
|
|
103
|
-
original_message = json.loads(message)
|
|
104
|
-
if isinstance(original_message, dict):
|
|
105
|
-
# Preserve all original fields and merge/update headers
|
|
106
|
-
wrapped_message = original_message.copy()
|
|
107
|
-
existing_headers = wrapped_message.get("headers", {})
|
|
108
|
-
existing_headers.update(headers)
|
|
109
|
-
wrapped_message["headers"] = existing_headers
|
|
75
|
+
# Thread-safe access to kv_store
|
|
76
|
+
session_id = None
|
|
77
|
+
if traceparent:
|
|
78
|
+
with _kv_lock:
|
|
79
|
+
session_id = kv_store.get(f"execution.{traceparent}")
|
|
80
|
+
if session_id:
|
|
81
|
+
kv_store.set(f"execution.{traceparent}", session_id)
|
|
82
|
+
|
|
83
|
+
headers = {
|
|
84
|
+
"session_id": session_id if session_id else None,
|
|
85
|
+
"traceparent": traceparent,
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
# Set baggage context
|
|
89
|
+
if traceparent and session_id:
|
|
90
|
+
baggage.set_baggage(f"execution.{traceparent}", session_id)
|
|
91
|
+
|
|
92
|
+
# Wrap message with headers - handle different message positions
|
|
93
|
+
message_arg_index = 1 # message will typically be the second argument
|
|
94
|
+
if len(args) > message_arg_index:
|
|
95
|
+
original_args = list(args)
|
|
96
|
+
message = original_args[message_arg_index]
|
|
97
|
+
wrapped_message = self._wrap_message_with_headers(message, headers)
|
|
98
|
+
|
|
99
|
+
# Convert wrapped message back to bytes if needed
|
|
100
|
+
if isinstance(wrapped_message, dict):
|
|
101
|
+
message_to_send = json.dumps(wrapped_message).encode("utf-8")
|
|
110
102
|
else:
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
103
|
+
message_to_send = wrapped_message
|
|
104
|
+
|
|
105
|
+
original_args[message_arg_index] = message_to_send
|
|
106
|
+
args = tuple(original_args)
|
|
107
|
+
|
|
108
|
+
return await original_publish(self, *args, **kwargs)
|
|
109
|
+
|
|
110
|
+
slim_bindings.Slim.publish = instrumented_publish
|
|
111
|
+
|
|
112
|
+
# Instrument `publish_to` (new v0.4.0+ method)
|
|
113
|
+
if hasattr(slim_bindings.Slim, "publish_to"):
|
|
114
|
+
original_publish_to = slim_bindings.Slim.publish_to
|
|
115
|
+
|
|
116
|
+
@functools.wraps(original_publish_to)
|
|
117
|
+
async def instrumented_publish_to(
|
|
118
|
+
self, session_info, message, *args, **kwargs
|
|
119
|
+
):
|
|
120
|
+
if _global_tracer:
|
|
121
|
+
with _global_tracer.start_as_current_span(
|
|
122
|
+
"slim.publish_to"
|
|
123
|
+
) as span:
|
|
124
|
+
traceparent = get_current_traceparent()
|
|
125
|
+
|
|
126
|
+
# Add session context to span
|
|
127
|
+
if hasattr(session_info, "id"):
|
|
128
|
+
span.set_attribute("slim.session.id", str(session_info.id))
|
|
129
|
+
else:
|
|
130
|
+
traceparent = get_current_traceparent()
|
|
131
|
+
|
|
132
|
+
# Thread-safe access to kv_store
|
|
133
|
+
session_id = None
|
|
134
|
+
if traceparent:
|
|
135
|
+
with _kv_lock:
|
|
136
|
+
session_id = kv_store.get(f"execution.{traceparent}")
|
|
137
|
+
if session_id:
|
|
138
|
+
kv_store.set(f"execution.{traceparent}", session_id)
|
|
139
|
+
|
|
140
|
+
headers = {
|
|
141
|
+
"session_id": session_id if session_id else None,
|
|
142
|
+
"traceparent": traceparent,
|
|
143
|
+
"slim_session_id": str(session_info.id)
|
|
144
|
+
if hasattr(session_info, "id")
|
|
145
|
+
else None,
|
|
133
146
|
}
|
|
134
147
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
message_to_send
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
148
|
+
# Set baggage context
|
|
149
|
+
if traceparent and session_id:
|
|
150
|
+
baggage.set_baggage(f"execution.{traceparent}", session_id)
|
|
151
|
+
|
|
152
|
+
wrapped_message = self._wrap_message_with_headers(message, headers)
|
|
153
|
+
message_to_send = (
|
|
154
|
+
json.dumps(wrapped_message).encode("utf-8")
|
|
155
|
+
if isinstance(wrapped_message, dict)
|
|
156
|
+
else wrapped_message
|
|
157
|
+
)
|
|
158
|
+
|
|
159
|
+
return await original_publish_to(
|
|
160
|
+
self, session_info, message_to_send, *args, **kwargs
|
|
161
|
+
)
|
|
162
|
+
|
|
163
|
+
slim_bindings.Slim.publish_to = instrumented_publish_to
|
|
164
|
+
|
|
165
|
+
# Instrument `request_reply` (new v0.4.0+ method)
|
|
166
|
+
if hasattr(slim_bindings.Slim, "request_reply"):
|
|
167
|
+
original_request_reply = slim_bindings.Slim.request_reply
|
|
168
|
+
|
|
169
|
+
@functools.wraps(original_request_reply)
|
|
170
|
+
async def instrumented_request_reply(
|
|
171
|
+
self, session_info, message, remote_name, timeout=None, *args, **kwargs
|
|
172
|
+
):
|
|
173
|
+
if _global_tracer:
|
|
174
|
+
with _global_tracer.start_as_current_span(
|
|
175
|
+
"slim.request_reply"
|
|
176
|
+
) as span:
|
|
177
|
+
traceparent = get_current_traceparent()
|
|
178
|
+
|
|
179
|
+
# Add context to span
|
|
180
|
+
if hasattr(session_info, "id"):
|
|
181
|
+
span.set_attribute("slim.session.id", str(session_info.id))
|
|
182
|
+
if hasattr(remote_name, "organization"):
|
|
183
|
+
span.set_attribute(
|
|
184
|
+
"slim.remote.organization", remote_name.organization
|
|
185
|
+
)
|
|
186
|
+
span.set_attribute(
|
|
187
|
+
"slim.remote.namespace", remote_name.namespace
|
|
188
|
+
)
|
|
189
|
+
span.set_attribute("slim.remote.app", remote_name.app)
|
|
190
|
+
else:
|
|
191
|
+
traceparent = get_current_traceparent()
|
|
147
192
|
|
|
148
|
-
|
|
193
|
+
# Thread-safe access to kv_store
|
|
194
|
+
session_id = None
|
|
195
|
+
if traceparent:
|
|
196
|
+
with _kv_lock:
|
|
197
|
+
session_id = kv_store.get(f"execution.{traceparent}")
|
|
198
|
+
if session_id:
|
|
199
|
+
kv_store.set(f"execution.{traceparent}", session_id)
|
|
200
|
+
|
|
201
|
+
headers = {
|
|
202
|
+
"session_id": session_id if session_id else None,
|
|
203
|
+
"traceparent": traceparent,
|
|
204
|
+
"slim_session_id": str(session_info.id)
|
|
205
|
+
if hasattr(session_info, "id")
|
|
206
|
+
else None,
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
# Set baggage context
|
|
210
|
+
if traceparent and session_id:
|
|
211
|
+
baggage.set_baggage(f"execution.{traceparent}", session_id)
|
|
212
|
+
|
|
213
|
+
wrapped_message = self._wrap_message_with_headers(message, headers)
|
|
214
|
+
message_to_send = (
|
|
215
|
+
json.dumps(wrapped_message).encode("utf-8")
|
|
216
|
+
if isinstance(wrapped_message, dict)
|
|
217
|
+
else wrapped_message
|
|
218
|
+
)
|
|
219
|
+
|
|
220
|
+
kwargs_with_timeout = kwargs.copy()
|
|
221
|
+
if timeout is not None:
|
|
222
|
+
kwargs_with_timeout["timeout"] = timeout
|
|
223
|
+
|
|
224
|
+
return await original_request_reply(
|
|
225
|
+
self,
|
|
226
|
+
session_info,
|
|
227
|
+
message_to_send,
|
|
228
|
+
remote_name,
|
|
229
|
+
**kwargs_with_timeout,
|
|
230
|
+
)
|
|
231
|
+
|
|
232
|
+
slim_bindings.Slim.request_reply = instrumented_request_reply
|
|
233
|
+
|
|
234
|
+
# Instrument `invite` (new v0.4.0+ method for group chat)
|
|
235
|
+
if hasattr(slim_bindings.Slim, "invite"):
|
|
236
|
+
original_invite = slim_bindings.Slim.invite
|
|
237
|
+
|
|
238
|
+
@functools.wraps(original_invite)
|
|
239
|
+
async def instrumented_invite(
|
|
240
|
+
self, session_info, participant_name, *args, **kwargs
|
|
241
|
+
):
|
|
242
|
+
if _global_tracer:
|
|
243
|
+
with _global_tracer.start_as_current_span("slim.invite") as span:
|
|
244
|
+
# Add context to span
|
|
245
|
+
if hasattr(session_info, "id"):
|
|
246
|
+
span.set_attribute("slim.session.id", str(session_info.id))
|
|
247
|
+
if hasattr(participant_name, "organization"):
|
|
248
|
+
span.set_attribute(
|
|
249
|
+
"slim.participant.organization",
|
|
250
|
+
participant_name.organization,
|
|
251
|
+
)
|
|
252
|
+
span.set_attribute(
|
|
253
|
+
"slim.participant.namespace", participant_name.namespace
|
|
254
|
+
)
|
|
255
|
+
span.set_attribute(
|
|
256
|
+
"slim.participant.app", participant_name.app
|
|
257
|
+
)
|
|
258
|
+
|
|
259
|
+
return await original_invite(
|
|
260
|
+
self, session_info, participant_name, *args, **kwargs
|
|
261
|
+
)
|
|
262
|
+
|
|
263
|
+
slim_bindings.Slim.invite = instrumented_invite
|
|
264
|
+
|
|
265
|
+
# Instrument `set_route` (new v0.4.0+ method)
|
|
266
|
+
if hasattr(slim_bindings.Slim, "set_route"):
|
|
267
|
+
original_set_route = slim_bindings.Slim.set_route
|
|
268
|
+
|
|
269
|
+
@functools.wraps(original_set_route)
|
|
270
|
+
async def instrumented_set_route(self, remote_name, *args, **kwargs):
|
|
271
|
+
if _global_tracer:
|
|
272
|
+
with _global_tracer.start_as_current_span("slim.set_route") as span:
|
|
273
|
+
# Add context to span
|
|
274
|
+
if hasattr(remote_name, "organization"):
|
|
275
|
+
span.set_attribute(
|
|
276
|
+
"slim.route.organization", remote_name.organization
|
|
277
|
+
)
|
|
278
|
+
span.set_attribute(
|
|
279
|
+
"slim.route.namespace", remote_name.namespace
|
|
280
|
+
)
|
|
281
|
+
span.set_attribute("slim.route.app", remote_name.app)
|
|
282
|
+
|
|
283
|
+
return await original_set_route(self, remote_name, *args, **kwargs)
|
|
284
|
+
|
|
285
|
+
slim_bindings.Slim.set_route = instrumented_set_route
|
|
149
286
|
|
|
150
287
|
# Instrument `receive`
|
|
151
288
|
original_receive = slim_bindings.Slim.receive
|
|
152
289
|
|
|
153
290
|
@functools.wraps(original_receive)
|
|
154
|
-
async def instrumented_receive(
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
291
|
+
async def instrumented_receive(
|
|
292
|
+
self, session=None, timeout=None, *args, **kwargs
|
|
293
|
+
):
|
|
294
|
+
# Handle both old and new API patterns
|
|
295
|
+
if session is not None or timeout is not None:
|
|
296
|
+
# New API pattern with session parameter
|
|
297
|
+
kwargs_with_params = kwargs.copy()
|
|
298
|
+
if session is not None:
|
|
299
|
+
kwargs_with_params["session"] = session
|
|
300
|
+
if timeout is not None:
|
|
301
|
+
kwargs_with_params["timeout"] = timeout
|
|
302
|
+
recv_session, raw_message = await original_receive(
|
|
303
|
+
self, **kwargs_with_params
|
|
304
|
+
)
|
|
305
|
+
else:
|
|
306
|
+
# Legacy API pattern
|
|
307
|
+
recv_session, raw_message = await original_receive(
|
|
308
|
+
self, *args, **kwargs
|
|
309
|
+
)
|
|
158
310
|
|
|
159
311
|
if raw_message is None:
|
|
160
312
|
return recv_session, raw_message
|
|
@@ -163,11 +315,11 @@ class SLIMInstrumentor(BaseInstrumentor):
|
|
|
163
315
|
message_dict = json.loads(raw_message.decode())
|
|
164
316
|
headers = message_dict.get("headers", {})
|
|
165
317
|
|
|
166
|
-
# Extract traceparent from headers
|
|
318
|
+
# Extract traceparent and session info from headers
|
|
167
319
|
traceparent = headers.get("traceparent")
|
|
168
320
|
session_id = headers.get("session_id")
|
|
169
321
|
|
|
170
|
-
#
|
|
322
|
+
# Create carrier for context propagation
|
|
171
323
|
carrier = {}
|
|
172
324
|
for key in ["traceparent", "Traceparent", "baggage", "Baggage"]:
|
|
173
325
|
if key.lower() in [k.lower() for k in headers.keys()]:
|
|
@@ -175,19 +327,24 @@ class SLIMInstrumentor(BaseInstrumentor):
|
|
|
175
327
|
if k.lower() == key.lower():
|
|
176
328
|
carrier[key.lower()] = headers[k]
|
|
177
329
|
|
|
178
|
-
# Restore
|
|
330
|
+
# Restore trace context
|
|
179
331
|
if carrier and traceparent:
|
|
180
332
|
ctx = TraceContextTextMapPropagator().extract(carrier=carrier)
|
|
181
333
|
ctx = W3CBaggagePropagator().extract(carrier=carrier, context=ctx)
|
|
182
334
|
|
|
183
|
-
#
|
|
184
|
-
|
|
185
|
-
# Pass the traceparent explicitly to prevent new context creation
|
|
186
|
-
set_session_id(session_id, traceparent=traceparent)
|
|
335
|
+
# Activate the restored context
|
|
336
|
+
token = context.attach(ctx)
|
|
187
337
|
|
|
188
|
-
|
|
189
|
-
with
|
|
190
|
-
|
|
338
|
+
try:
|
|
339
|
+
# Set execution ID with the restored context
|
|
340
|
+
if session_id and session_id != "None":
|
|
341
|
+
set_session_id(session_id, traceparent=traceparent)
|
|
342
|
+
|
|
343
|
+
# Store in kv_store with thread safety
|
|
344
|
+
with _kv_lock:
|
|
345
|
+
kv_store.set(f"execution.{traceparent}", session_id)
|
|
346
|
+
finally:
|
|
347
|
+
context.detach(token)
|
|
191
348
|
|
|
192
349
|
# Fallback: check stored execution ID if not found in headers
|
|
193
350
|
if traceparent and (not session_id or session_id == "None"):
|
|
@@ -197,21 +354,20 @@ class SLIMInstrumentor(BaseInstrumentor):
|
|
|
197
354
|
session_id = stored_session_id
|
|
198
355
|
set_session_id(session_id, traceparent=traceparent)
|
|
199
356
|
|
|
200
|
-
# Process the
|
|
201
|
-
# Remove tracing headers before returning the message
|
|
357
|
+
# Process and clean the message
|
|
202
358
|
message_to_return = message_dict.copy()
|
|
203
359
|
if "headers" in message_to_return:
|
|
204
360
|
headers_copy = message_to_return["headers"].copy()
|
|
205
361
|
# Remove tracing-specific headers but keep other headers
|
|
206
362
|
headers_copy.pop("traceparent", None)
|
|
207
363
|
headers_copy.pop("session_id", None)
|
|
364
|
+
headers_copy.pop("slim_session_id", None)
|
|
208
365
|
if headers_copy:
|
|
209
366
|
message_to_return["headers"] = headers_copy
|
|
210
367
|
else:
|
|
211
368
|
message_to_return.pop("headers", None)
|
|
212
369
|
|
|
213
|
-
#
|
|
214
|
-
# return just the payload for backward compatibility
|
|
370
|
+
# Return processed message
|
|
215
371
|
if len(message_to_return) == 1 and "payload" in message_to_return:
|
|
216
372
|
payload = message_to_return["payload"]
|
|
217
373
|
if isinstance(payload, str):
|
|
@@ -228,7 +384,6 @@ class SLIMInstrumentor(BaseInstrumentor):
|
|
|
228
384
|
"utf-8"
|
|
229
385
|
) if isinstance(payload, (dict, list)) else payload
|
|
230
386
|
else:
|
|
231
|
-
# Return the complete message structure with all original fields
|
|
232
387
|
return recv_session, json.dumps(message_to_return).encode("utf-8")
|
|
233
388
|
|
|
234
389
|
except Exception as e:
|
|
@@ -242,10 +397,88 @@ class SLIMInstrumentor(BaseInstrumentor):
|
|
|
242
397
|
|
|
243
398
|
@functools.wraps(original_connect)
|
|
244
399
|
async def instrumented_connect(self, *args, **kwargs):
|
|
245
|
-
|
|
400
|
+
if _global_tracer:
|
|
401
|
+
with _global_tracer.start_as_current_span("slim.connect"):
|
|
402
|
+
return await original_connect(self, *args, **kwargs)
|
|
403
|
+
else:
|
|
404
|
+
return await original_connect(self, *args, **kwargs)
|
|
246
405
|
|
|
247
406
|
slim_bindings.Slim.connect = instrumented_connect
|
|
248
407
|
|
|
408
|
+
# Instrument `create_session` (new v0.4.0+ method)
|
|
409
|
+
if hasattr(slim_bindings.Slim, "create_session"):
|
|
410
|
+
original_create_session = slim_bindings.Slim.create_session
|
|
411
|
+
|
|
412
|
+
@functools.wraps(original_create_session)
|
|
413
|
+
async def instrumented_create_session(self, config, *args, **kwargs):
|
|
414
|
+
if _global_tracer:
|
|
415
|
+
with _global_tracer.start_as_current_span(
|
|
416
|
+
"slim.create_session"
|
|
417
|
+
) as span:
|
|
418
|
+
session_info = await original_create_session(
|
|
419
|
+
self, config, *args, **kwargs
|
|
420
|
+
)
|
|
421
|
+
|
|
422
|
+
# Add session attributes to span
|
|
423
|
+
if hasattr(session_info, "id"):
|
|
424
|
+
span.set_attribute("slim.session.id", str(session_info.id))
|
|
425
|
+
|
|
426
|
+
return session_info
|
|
427
|
+
else:
|
|
428
|
+
return await original_create_session(self, config, *args, **kwargs)
|
|
429
|
+
|
|
430
|
+
slim_bindings.Slim.create_session = instrumented_create_session
|
|
431
|
+
|
|
432
|
+
def _wrap_message_with_headers(self, message, headers):
|
|
433
|
+
"""Helper method to wrap messages with headers consistently"""
|
|
434
|
+
if isinstance(message, bytes):
|
|
435
|
+
try:
|
|
436
|
+
decoded_message = message.decode("utf-8")
|
|
437
|
+
try:
|
|
438
|
+
original_message = json.loads(decoded_message)
|
|
439
|
+
if isinstance(original_message, dict):
|
|
440
|
+
wrapped_message = original_message.copy()
|
|
441
|
+
existing_headers = wrapped_message.get("headers", {})
|
|
442
|
+
existing_headers.update(headers)
|
|
443
|
+
wrapped_message["headers"] = existing_headers
|
|
444
|
+
else:
|
|
445
|
+
wrapped_message = {
|
|
446
|
+
"headers": headers,
|
|
447
|
+
"payload": original_message,
|
|
448
|
+
}
|
|
449
|
+
except json.JSONDecodeError:
|
|
450
|
+
wrapped_message = {"headers": headers, "payload": decoded_message}
|
|
451
|
+
except UnicodeDecodeError:
|
|
452
|
+
# Fix type annotation issue by ensuring message is bytes
|
|
453
|
+
encoded_message = (
|
|
454
|
+
message if isinstance(message, bytes) else message.encode("utf-8")
|
|
455
|
+
)
|
|
456
|
+
wrapped_message = {
|
|
457
|
+
"headers": headers,
|
|
458
|
+
"payload": base64.b64encode(encoded_message).decode("utf-8"),
|
|
459
|
+
}
|
|
460
|
+
elif isinstance(message, str):
|
|
461
|
+
try:
|
|
462
|
+
original_message = json.loads(message)
|
|
463
|
+
if isinstance(original_message, dict):
|
|
464
|
+
wrapped_message = original_message.copy()
|
|
465
|
+
existing_headers = wrapped_message.get("headers", {})
|
|
466
|
+
existing_headers.update(headers)
|
|
467
|
+
wrapped_message["headers"] = existing_headers
|
|
468
|
+
else:
|
|
469
|
+
wrapped_message = {"headers": headers, "payload": original_message}
|
|
470
|
+
except json.JSONDecodeError:
|
|
471
|
+
wrapped_message = {"headers": headers, "payload": message}
|
|
472
|
+
elif isinstance(message, dict):
|
|
473
|
+
wrapped_message = message.copy()
|
|
474
|
+
existing_headers = wrapped_message.get("headers", {})
|
|
475
|
+
existing_headers.update(headers)
|
|
476
|
+
wrapped_message["headers"] = existing_headers
|
|
477
|
+
else:
|
|
478
|
+
wrapped_message = {"headers": headers, "payload": json.dumps(message)}
|
|
479
|
+
|
|
480
|
+
return wrapped_message
|
|
481
|
+
|
|
249
482
|
def _uninstrument(self, **kwargs):
|
|
250
483
|
try:
|
|
251
484
|
import slim_bindings
|
|
@@ -255,6 +488,21 @@ class SLIMInstrumentor(BaseInstrumentor):
|
|
|
255
488
|
)
|
|
256
489
|
|
|
257
490
|
# Restore the original methods
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
491
|
+
methods_to_restore = [
|
|
492
|
+
"publish",
|
|
493
|
+
"publish_to",
|
|
494
|
+
"request_reply",
|
|
495
|
+
"receive",
|
|
496
|
+
"connect",
|
|
497
|
+
"create_session",
|
|
498
|
+
"invite",
|
|
499
|
+
"set_route",
|
|
500
|
+
]
|
|
501
|
+
|
|
502
|
+
for method_name in methods_to_restore:
|
|
503
|
+
if hasattr(slim_bindings.Slim, method_name):
|
|
504
|
+
original_method = getattr(slim_bindings.Slim, method_name)
|
|
505
|
+
if hasattr(original_method, "__wrapped__"):
|
|
506
|
+
setattr(
|
|
507
|
+
slim_bindings.Slim, method_name, original_method.__wrapped__
|
|
508
|
+
)
|
|
@@ -16,7 +16,7 @@ ioa_observe/sdk/decorators/util.py,sha256=IebvH9gwZN1en3LblYJUh4bAV2STl6xmp8WpZz
|
|
|
16
16
|
ioa_observe/sdk/instrumentations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
17
17
|
ioa_observe/sdk/instrumentations/a2a.py,sha256=ZpqvPl4u-yheQzSdBfxnZhWFZ8ntbKni_uaW3IDyjqw,6309
|
|
18
18
|
ioa_observe/sdk/instrumentations/mcp.py,sha256=vRM3ofnn7AMmry2RrfyZnZVPEutLWiDMghx2TSnm0Wk,18569
|
|
19
|
-
ioa_observe/sdk/instrumentations/slim.py,sha256=
|
|
19
|
+
ioa_observe/sdk/instrumentations/slim.py,sha256=9KS9slZKB7-oC-2SH2s2FKB2JHXXHt4_xPhLvxJD-fk,22456
|
|
20
20
|
ioa_observe/sdk/logging/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
21
21
|
ioa_observe/sdk/logging/logging.py,sha256=HZxW9s8Due7jgiNkdI38cIjv5rC9D-Flta3RQMOnpow,2891
|
|
22
22
|
ioa_observe/sdk/metrics/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -41,8 +41,8 @@ ioa_observe/sdk/utils/const.py,sha256=d67dUTAH9UpWvUV9GLBUqn1Sc2knJ55dy-e6YoLrvS
|
|
|
41
41
|
ioa_observe/sdk/utils/in_memory_span_exporter.py,sha256=H_4TRaThMO1H6vUQ0OpQvzJk_fZH0OOsRAM1iZQXsR8,2112
|
|
42
42
|
ioa_observe/sdk/utils/json_encoder.py,sha256=g4NQ0tTqgWssY6I1D7r4zo0G6PiUo61jhofTAw5-jno,639
|
|
43
43
|
ioa_observe/sdk/utils/package_check.py,sha256=1d1MjxhwoEZIx9dumirT2pRsEWgn-m-SI4npDeEalew,576
|
|
44
|
-
ioa_observe_sdk-1.0.
|
|
45
|
-
ioa_observe_sdk-1.0.
|
|
46
|
-
ioa_observe_sdk-1.0.
|
|
47
|
-
ioa_observe_sdk-1.0.
|
|
48
|
-
ioa_observe_sdk-1.0.
|
|
44
|
+
ioa_observe_sdk-1.0.17.dist-info/licenses/LICENSE.md,sha256=55VjUfgjWOS4vv3Cf55gfq-RxjPgRIO2vlgYPUuC5lA,11362
|
|
45
|
+
ioa_observe_sdk-1.0.17.dist-info/METADATA,sha256=jarZLIoRaEz4yKIwUHHKmAwL2e7hkKe_uhTTT6iwyiw,7027
|
|
46
|
+
ioa_observe_sdk-1.0.17.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
47
|
+
ioa_observe_sdk-1.0.17.dist-info/top_level.txt,sha256=Yt-6Y1olZEDqCs2REeqI30WjYx0pLGQSVqzYmDd67N8,12
|
|
48
|
+
ioa_observe_sdk-1.0.17.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|