ioa-observe-sdk 1.0.28__py3-none-any.whl → 1.0.30__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/a2a.py +431 -122
- ioa_observe/sdk/instrumentations/slim.py +367 -866
- ioa_observe/sdk/tracing/tracing.py +70 -13
- {ioa_observe_sdk-1.0.28.dist-info → ioa_observe_sdk-1.0.30.dist-info}/METADATA +29 -29
- {ioa_observe_sdk-1.0.28.dist-info → ioa_observe_sdk-1.0.30.dist-info}/RECORD +8 -8
- {ioa_observe_sdk-1.0.28.dist-info → ioa_observe_sdk-1.0.30.dist-info}/WHEEL +0 -0
- {ioa_observe_sdk-1.0.28.dist-info → ioa_observe_sdk-1.0.30.dist-info}/licenses/LICENSE.md +0 -0
- {ioa_observe_sdk-1.0.28.dist-info → ioa_observe_sdk-1.0.30.dist-info}/top_level.txt +0 -0
|
@@ -30,8 +30,15 @@ from opentelemetry.sdk.trace.export import (
|
|
|
30
30
|
SimpleSpanProcessor,
|
|
31
31
|
BatchSpanProcessor,
|
|
32
32
|
)
|
|
33
|
-
from opentelemetry.trace import
|
|
33
|
+
from opentelemetry.trace import (
|
|
34
|
+
get_tracer_provider,
|
|
35
|
+
ProxyTracerProvider,
|
|
36
|
+
SpanContext,
|
|
37
|
+
TraceFlags,
|
|
38
|
+
NonRecordingSpan,
|
|
39
|
+
)
|
|
34
40
|
from opentelemetry.context import get_value, attach, set_value
|
|
41
|
+
from opentelemetry.trace import set_span_in_context
|
|
35
42
|
from opentelemetry.instrumentation.threading import ThreadingInstrumentor
|
|
36
43
|
from opentelemetry.metrics import get_meter
|
|
37
44
|
from ioa_observe.sdk.metrics.agents.agent_connections import connection_reliability
|
|
@@ -137,9 +144,12 @@ class TracerWrapper(object):
|
|
|
137
144
|
if not TracerWrapper.endpoint:
|
|
138
145
|
return obj
|
|
139
146
|
|
|
140
|
-
# session activity tracking
|
|
141
|
-
obj._session_last_activity: dict[str, float] = {}
|
|
147
|
+
# session activity tracking: {session_id: (last_activity_time, trace_id)}
|
|
148
|
+
obj._session_last_activity: dict[str, tuple[float, int]] = {}
|
|
142
149
|
obj._session_lock = threading.Lock()
|
|
150
|
+
# Track sessions that have already been ended to prevent duplicates
|
|
151
|
+
obj._ended_sessions: set[str] = set()
|
|
152
|
+
obj._ended_sessions_lock = threading.Lock()
|
|
143
153
|
obj.__image_uploader = image_uploader
|
|
144
154
|
# {(agent_name): [success_count, total_count]}
|
|
145
155
|
obj._agent_execution_counts = {}
|
|
@@ -300,13 +310,15 @@ class TracerWrapper(object):
|
|
|
300
310
|
while True:
|
|
301
311
|
time.sleep(SESSION_WATCHER_INTERVAL_SECONDS)
|
|
302
312
|
now = time.time()
|
|
303
|
-
expired: dict[str, float] = {}
|
|
313
|
+
expired: dict[str, tuple[float, int]] = {}
|
|
304
314
|
|
|
305
315
|
# Find idle sessions and remove them from _session_last_activity
|
|
306
316
|
with self._session_lock:
|
|
307
|
-
for session_id, last_ts in list(
|
|
317
|
+
for session_id, (last_ts, trace_id) in list(
|
|
318
|
+
self._session_last_activity.items()
|
|
319
|
+
):
|
|
308
320
|
if now - last_ts > SESSION_IDLE_TIMEOUT_SECONDS:
|
|
309
|
-
expired[session_id] = last_ts
|
|
321
|
+
expired[session_id] = (last_ts, trace_id)
|
|
310
322
|
del self._session_last_activity[session_id]
|
|
311
323
|
|
|
312
324
|
# Periodic cleanup of processed spans to prevent unbounded memory growth
|
|
@@ -314,19 +326,42 @@ class TracerWrapper(object):
|
|
|
314
326
|
if len(self._processed_spans) > MAX_PROCESSED_SPANS_SIZE:
|
|
315
327
|
self._processed_spans.clear()
|
|
316
328
|
|
|
329
|
+
# Periodic cleanup of ended sessions to prevent unbounded memory growth
|
|
330
|
+
with self._ended_sessions_lock:
|
|
331
|
+
if len(self._ended_sessions) > MAX_PROCESSED_SPANS_SIZE:
|
|
332
|
+
self._ended_sessions.clear()
|
|
333
|
+
|
|
317
334
|
if not expired:
|
|
318
335
|
continue
|
|
319
336
|
|
|
320
337
|
tracer = self.get_tracer()
|
|
321
338
|
|
|
322
339
|
# Iterate over a snapshot and do *not* modify `expired` in the loop
|
|
323
|
-
for session_id,
|
|
324
|
-
|
|
340
|
+
for session_id, (last_ts, trace_id) in list(expired.items()):
|
|
341
|
+
# Check if this session has already been ended to prevent duplicates
|
|
342
|
+
with self._ended_sessions_lock:
|
|
343
|
+
if session_id in self._ended_sessions:
|
|
344
|
+
continue
|
|
345
|
+
self._ended_sessions.add(session_id)
|
|
346
|
+
|
|
347
|
+
# Create a parent context from the stored trace_id to keep session.end under the same trace
|
|
348
|
+
parent_span_context = SpanContext(
|
|
349
|
+
trace_id=trace_id,
|
|
350
|
+
span_id=0, # Use 0 as we don't have a specific parent span
|
|
351
|
+
is_remote=False,
|
|
352
|
+
trace_flags=TraceFlags(TraceFlags.SAMPLED),
|
|
353
|
+
)
|
|
354
|
+
parent_span = NonRecordingSpan(parent_span_context)
|
|
355
|
+
parent_context = set_span_in_context(parent_span)
|
|
356
|
+
|
|
357
|
+
with tracer.start_as_current_span(
|
|
358
|
+
"session.end", context=parent_context
|
|
359
|
+
) as span:
|
|
325
360
|
span.set_attribute("session.id", session_id)
|
|
326
361
|
workflow_name = get_value("workflow_name")
|
|
327
362
|
if workflow_name:
|
|
328
363
|
span.set_attribute(OBSERVE_WORKFLOW_NAME, workflow_name)
|
|
329
|
-
span.set_attribute("session.ended_at",
|
|
364
|
+
span.set_attribute("session.ended_at", last_ts)
|
|
330
365
|
|
|
331
366
|
# ensure end spans are exported reasonably fast
|
|
332
367
|
self.flush()
|
|
@@ -337,11 +372,29 @@ class TracerWrapper(object):
|
|
|
337
372
|
tracer = self.get_tracer()
|
|
338
373
|
|
|
339
374
|
with self._session_lock:
|
|
340
|
-
|
|
375
|
+
remaining_sessions = dict(self._session_last_activity)
|
|
341
376
|
self._session_last_activity.clear()
|
|
342
377
|
|
|
343
|
-
for session_id in
|
|
344
|
-
|
|
378
|
+
for session_id, (_, trace_id) in remaining_sessions.items():
|
|
379
|
+
# Check if this session has already been ended to prevent duplicates
|
|
380
|
+
with self._ended_sessions_lock:
|
|
381
|
+
if session_id in self._ended_sessions:
|
|
382
|
+
continue
|
|
383
|
+
self._ended_sessions.add(session_id)
|
|
384
|
+
|
|
385
|
+
# Create a parent context from the stored trace_id to keep session.end under the same trace
|
|
386
|
+
parent_span_context = SpanContext(
|
|
387
|
+
trace_id=trace_id,
|
|
388
|
+
span_id=0, # Use 0 as we don't have a specific parent span
|
|
389
|
+
is_remote=False,
|
|
390
|
+
trace_flags=TraceFlags(TraceFlags.SAMPLED),
|
|
391
|
+
)
|
|
392
|
+
parent_span = NonRecordingSpan(parent_span_context)
|
|
393
|
+
parent_context = set_span_in_context(parent_span)
|
|
394
|
+
|
|
395
|
+
with tracer.start_as_current_span(
|
|
396
|
+
"session.end", context=parent_context
|
|
397
|
+
) as span:
|
|
345
398
|
span.set_attribute("session.id", session_id)
|
|
346
399
|
workflow_name = get_value("workflow_name")
|
|
347
400
|
if workflow_name:
|
|
@@ -441,7 +494,11 @@ class TracerWrapper(object):
|
|
|
441
494
|
session_id = span.attributes.get("session.id")
|
|
442
495
|
if session_id and span.name != "session.end":
|
|
443
496
|
with self._session_lock:
|
|
444
|
-
|
|
497
|
+
# Store both the last activity time and the trace_id for this session
|
|
498
|
+
self._session_last_activity[session_id] = (
|
|
499
|
+
time.time(),
|
|
500
|
+
span.context.trace_id,
|
|
501
|
+
)
|
|
445
502
|
|
|
446
503
|
determine_reliability_score(span)
|
|
447
504
|
# start_time = span.attributes.get("ioa_start_time")
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ioa-observe-sdk
|
|
3
|
-
Version: 1.0.
|
|
3
|
+
Version: 1.0.30
|
|
4
4
|
Summary: IOA Observability SDK
|
|
5
5
|
License-Expression: Apache-2.0
|
|
6
6
|
Requires-Python: >=3.10
|
|
@@ -8,37 +8,37 @@ Description-Content-Type: text/markdown
|
|
|
8
8
|
License-File: LICENSE.md
|
|
9
9
|
Requires-Dist: colorama==0.4.6
|
|
10
10
|
Requires-Dist: requests>=2.32.3
|
|
11
|
-
Requires-Dist: opentelemetry-api==1.
|
|
11
|
+
Requires-Dist: opentelemetry-api==1.39.1
|
|
12
12
|
Requires-Dist: opentelemetry-distro
|
|
13
|
-
Requires-Dist: opentelemetry-exporter-otlp==1.
|
|
14
|
-
Requires-Dist: opentelemetry-exporter-otlp-proto-common==1.
|
|
15
|
-
Requires-Dist: opentelemetry-exporter-otlp-proto-grpc==1.
|
|
16
|
-
Requires-Dist: opentelemetry-exporter-otlp-proto-http==1.
|
|
13
|
+
Requires-Dist: opentelemetry-exporter-otlp==1.39.1
|
|
14
|
+
Requires-Dist: opentelemetry-exporter-otlp-proto-common==1.39.1
|
|
15
|
+
Requires-Dist: opentelemetry-exporter-otlp-proto-grpc==1.39.1
|
|
16
|
+
Requires-Dist: opentelemetry-exporter-otlp-proto-http==1.39.1
|
|
17
17
|
Requires-Dist: opentelemetry-instrumentation
|
|
18
|
-
Requires-Dist: opentelemetry-instrumentation-logging==0.
|
|
19
|
-
Requires-Dist: opentelemetry-instrumentation-openai==0.
|
|
20
|
-
Requires-Dist: opentelemetry-instrumentation-llamaindex==0.
|
|
21
|
-
Requires-Dist: opentelemetry-instrumentation-ollama==0.
|
|
22
|
-
Requires-Dist: opentelemetry-instrumentation-anthropic==0.
|
|
23
|
-
Requires-Dist: opentelemetry-instrumentation-langchain==0.
|
|
24
|
-
Requires-Dist: opentelemetry-instrumentation-bedrock==0.
|
|
25
|
-
Requires-Dist: opentelemetry-instrumentation-cohere==0.
|
|
26
|
-
Requires-Dist: opentelemetry-instrumentation-crewai==0.
|
|
27
|
-
Requires-Dist: opentelemetry-instrumentation-google-generativeai==0.
|
|
28
|
-
Requires-Dist: opentelemetry-instrumentation-groq==0.
|
|
29
|
-
Requires-Dist: opentelemetry-instrumentation-mistralai==0.
|
|
30
|
-
Requires-Dist: opentelemetry-instrumentation-requests==0.
|
|
31
|
-
Requires-Dist: opentelemetry-instrumentation-sagemaker==0.
|
|
32
|
-
Requires-Dist: opentelemetry-instrumentation-threading==0.
|
|
33
|
-
Requires-Dist: opentelemetry-instrumentation-together==0.
|
|
34
|
-
Requires-Dist: opentelemetry-instrumentation-transformers==0.
|
|
35
|
-
Requires-Dist: opentelemetry-instrumentation-urllib3==0.
|
|
36
|
-
Requires-Dist: opentelemetry-instrumentation-vertexai==0.
|
|
37
|
-
Requires-Dist: opentelemetry-proto==1.
|
|
38
|
-
Requires-Dist: opentelemetry-sdk==1.
|
|
39
|
-
Requires-Dist: opentelemetry-semantic-conventions==0.
|
|
18
|
+
Requires-Dist: opentelemetry-instrumentation-logging==0.60b1
|
|
19
|
+
Requires-Dist: opentelemetry-instrumentation-openai==0.52.1
|
|
20
|
+
Requires-Dist: opentelemetry-instrumentation-llamaindex==0.52.1
|
|
21
|
+
Requires-Dist: opentelemetry-instrumentation-ollama==0.52.1
|
|
22
|
+
Requires-Dist: opentelemetry-instrumentation-anthropic==0.52.1
|
|
23
|
+
Requires-Dist: opentelemetry-instrumentation-langchain==0.52.1
|
|
24
|
+
Requires-Dist: opentelemetry-instrumentation-bedrock==0.52.1
|
|
25
|
+
Requires-Dist: opentelemetry-instrumentation-cohere==0.52.1
|
|
26
|
+
Requires-Dist: opentelemetry-instrumentation-crewai==0.52.1
|
|
27
|
+
Requires-Dist: opentelemetry-instrumentation-google-generativeai==0.52.1
|
|
28
|
+
Requires-Dist: opentelemetry-instrumentation-groq==0.52.1
|
|
29
|
+
Requires-Dist: opentelemetry-instrumentation-mistralai==0.52.1
|
|
30
|
+
Requires-Dist: opentelemetry-instrumentation-requests==0.60b1
|
|
31
|
+
Requires-Dist: opentelemetry-instrumentation-sagemaker==0.52.1
|
|
32
|
+
Requires-Dist: opentelemetry-instrumentation-threading==0.60b1
|
|
33
|
+
Requires-Dist: opentelemetry-instrumentation-together==0.52.1
|
|
34
|
+
Requires-Dist: opentelemetry-instrumentation-transformers==0.52.1
|
|
35
|
+
Requires-Dist: opentelemetry-instrumentation-urllib3==0.60b1
|
|
36
|
+
Requires-Dist: opentelemetry-instrumentation-vertexai==0.52.1
|
|
37
|
+
Requires-Dist: opentelemetry-proto==1.39.1
|
|
38
|
+
Requires-Dist: opentelemetry-sdk==1.39.1
|
|
39
|
+
Requires-Dist: opentelemetry-semantic-conventions==0.60b1
|
|
40
40
|
Requires-Dist: opentelemetry-semantic-conventions-ai>=0.4.11
|
|
41
|
-
Requires-Dist: opentelemetry-util-http==0.
|
|
41
|
+
Requires-Dist: opentelemetry-util-http==0.60b1
|
|
42
42
|
Requires-Dist: langgraph>=0.3.2
|
|
43
43
|
Requires-Dist: langchain>=0.3.19
|
|
44
44
|
Requires-Dist: langchain-openai>=0.3.8
|
|
@@ -14,10 +14,10 @@ ioa_observe/sdk/decorators/base.py,sha256=gezoLMLOo-CWsxzsXbQMsj5HxmchUEmlhTspbq
|
|
|
14
14
|
ioa_observe/sdk/decorators/helpers.py,sha256=I9HXMBivkZpGDtPe9Ad_UU35p_m_wEPate4r_fU0oOA,2705
|
|
15
15
|
ioa_observe/sdk/decorators/util.py,sha256=IebvH9gwZN1en3LblYJUh4bAV2STl6xmp8WpZzBDH2g,30068
|
|
16
16
|
ioa_observe/sdk/instrumentations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
17
|
-
ioa_observe/sdk/instrumentations/a2a.py,sha256=
|
|
17
|
+
ioa_observe/sdk/instrumentations/a2a.py,sha256=smPMHhFONi9B7r2qVHe-YWoFctjHWehO_MR0kY_DgVI,27897
|
|
18
18
|
ioa_observe/sdk/instrumentations/mcp.py,sha256=UG82fWitFT-K-ecnkTKZa-uFTDAs-j2HymvhUwCBRLY,18721
|
|
19
19
|
ioa_observe/sdk/instrumentations/nats.py,sha256=MEYCFqHyRK5HtkjrbGVV5qIWplZ1ZjJjFCB8vtQl6qE,14736
|
|
20
|
-
ioa_observe/sdk/instrumentations/slim.py,sha256=
|
|
20
|
+
ioa_observe/sdk/instrumentations/slim.py,sha256=CE0wUGlRyxbAgP9oI69kGQ9M2yu9HmufrQNua4L0jTE,19510
|
|
21
21
|
ioa_observe/sdk/logging/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
22
22
|
ioa_observe/sdk/logging/logging.py,sha256=HZxW9s8Due7jgiNkdI38cIjv5rC9D-Flta3RQMOnpow,2891
|
|
23
23
|
ioa_observe/sdk/metrics/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -35,15 +35,15 @@ ioa_observe/sdk/tracing/content_allow_list.py,sha256=1fAkpIwUQ7vDwCTkIVrqeltWQtr
|
|
|
35
35
|
ioa_observe/sdk/tracing/context_manager.py,sha256=O0JEXYa9h8anhW78R8KKBuqS0j4by1E1KXxNIMPnLr8,400
|
|
36
36
|
ioa_observe/sdk/tracing/context_utils.py,sha256=-sYS9vPLI87davV9ubneq5xqbV583CC_c0SmOQS1TAs,2933
|
|
37
37
|
ioa_observe/sdk/tracing/manual.py,sha256=KS6WN-zw9vAACzXYmnMoJm9d1fenYMfvzeK1GrGDPDE,1937
|
|
38
|
-
ioa_observe/sdk/tracing/tracing.py,sha256=
|
|
38
|
+
ioa_observe/sdk/tracing/tracing.py,sha256=pGiIa1S3562QRlTG5mANtU94wkFjKspnX21N_bJ7SfY,53359
|
|
39
39
|
ioa_observe/sdk/tracing/transform_span.py,sha256=XTApi_gJxum7ynvhtcoCfDyK8VVOj91Q1DT6hAeLHA8,8419
|
|
40
40
|
ioa_observe/sdk/utils/__init__.py,sha256=UPn182U-UblF_XwXaFpx8F-TmQTbm1LYf9y89uSp5Hw,704
|
|
41
41
|
ioa_observe/sdk/utils/const.py,sha256=d67dUTAH9UpWvUV9GLBUqn1Sc2knJ55dy-e6YoLrvSo,1318
|
|
42
42
|
ioa_observe/sdk/utils/in_memory_span_exporter.py,sha256=H_4TRaThMO1H6vUQ0OpQvzJk_fZH0OOsRAM1iZQXsR8,2112
|
|
43
43
|
ioa_observe/sdk/utils/json_encoder.py,sha256=g4NQ0tTqgWssY6I1D7r4zo0G6PiUo61jhofTAw5-jno,639
|
|
44
44
|
ioa_observe/sdk/utils/package_check.py,sha256=1d1MjxhwoEZIx9dumirT2pRsEWgn-m-SI4npDeEalew,576
|
|
45
|
-
ioa_observe_sdk-1.0.
|
|
46
|
-
ioa_observe_sdk-1.0.
|
|
47
|
-
ioa_observe_sdk-1.0.
|
|
48
|
-
ioa_observe_sdk-1.0.
|
|
49
|
-
ioa_observe_sdk-1.0.
|
|
45
|
+
ioa_observe_sdk-1.0.30.dist-info/licenses/LICENSE.md,sha256=55VjUfgjWOS4vv3Cf55gfq-RxjPgRIO2vlgYPUuC5lA,11362
|
|
46
|
+
ioa_observe_sdk-1.0.30.dist-info/METADATA,sha256=KxVA9-iwTZF37H5BMdAeRxk_HeJ_uSJXRzVcsbeMc7c,7997
|
|
47
|
+
ioa_observe_sdk-1.0.30.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
|
|
48
|
+
ioa_observe_sdk-1.0.30.dist-info/top_level.txt,sha256=Yt-6Y1olZEDqCs2REeqI30WjYx0pLGQSVqzYmDd67N8,12
|
|
49
|
+
ioa_observe_sdk-1.0.30.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|