ioa-observe-sdk 1.0.10__py3-none-any.whl → 1.0.12__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/decorators/base.py +37 -15
- ioa_observe/sdk/instrumentations/slim.py +90 -26
- {ioa_observe_sdk-1.0.10.dist-info → ioa_observe_sdk-1.0.12.dist-info}/METADATA +3 -51
- {ioa_observe_sdk-1.0.10.dist-info → ioa_observe_sdk-1.0.12.dist-info}/RECORD +7 -7
- {ioa_observe_sdk-1.0.10.dist-info → ioa_observe_sdk-1.0.12.dist-info}/WHEEL +0 -0
- {ioa_observe_sdk-1.0.10.dist-info → ioa_observe_sdk-1.0.12.dist-info}/licenses/LICENSE.md +0 -0
- {ioa_observe_sdk-1.0.10.dist-info → ioa_observe_sdk-1.0.12.dist-info}/top_level.txt +0 -0
|
@@ -43,7 +43,6 @@ from ioa_observe.sdk.utils.const import (
|
|
|
43
43
|
from ioa_observe.sdk.utils.json_encoder import JSONEncoder
|
|
44
44
|
from ioa_observe.sdk.metrics.agent import topology_dynamism, determinism_score
|
|
45
45
|
|
|
46
|
-
|
|
47
46
|
P = ParamSpec("P")
|
|
48
47
|
|
|
49
48
|
R = TypeVar("R")
|
|
@@ -554,30 +553,53 @@ def entity_class(
|
|
|
554
553
|
# Specific method specified - existing behavior
|
|
555
554
|
methods_to_wrap = [method_name]
|
|
556
555
|
else:
|
|
557
|
-
# No method specified - wrap all public methods
|
|
556
|
+
# No method specified - wrap all public methods defined in this class
|
|
558
557
|
for attr_name in dir(cls):
|
|
559
558
|
if (
|
|
560
559
|
not attr_name.startswith("_") # Skip private/built-in methods
|
|
561
560
|
and attr_name != "mro" # Skip class method
|
|
562
561
|
and hasattr(cls, attr_name)
|
|
563
|
-
and callable(getattr(cls, attr_name))
|
|
564
|
-
and not isinstance(
|
|
565
|
-
getattr(cls, attr_name), (classmethod, staticmethod, property)
|
|
566
|
-
)
|
|
567
562
|
):
|
|
568
|
-
|
|
563
|
+
attr = getattr(cls, attr_name)
|
|
564
|
+
# Only wrap functions defined in this class (not inherited methods or built-ins)
|
|
565
|
+
if (
|
|
566
|
+
inspect.isfunction(attr) # Functions defined in the class
|
|
567
|
+
and not isinstance(attr, (classmethod, staticmethod, property))
|
|
568
|
+
and hasattr(attr, "__qualname__") # Has qualname attribute
|
|
569
|
+
and attr.__qualname__.startswith(
|
|
570
|
+
cls.__name__ + "."
|
|
571
|
+
) # Defined in this class
|
|
572
|
+
):
|
|
573
|
+
# Additional check: ensure the function has a proper signature with 'self' parameter
|
|
574
|
+
try:
|
|
575
|
+
sig = inspect.signature(attr)
|
|
576
|
+
params = list(sig.parameters.keys())
|
|
577
|
+
if params and params[0] == "self":
|
|
578
|
+
methods_to_wrap.append(attr_name)
|
|
579
|
+
except (ValueError, TypeError):
|
|
580
|
+
# Skip methods that can't be inspected
|
|
581
|
+
continue
|
|
569
582
|
|
|
570
583
|
# Wrap all detected methods
|
|
571
584
|
for method_to_wrap in methods_to_wrap:
|
|
572
585
|
if hasattr(cls, method_to_wrap):
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
586
|
+
original_method = getattr(cls, method_to_wrap)
|
|
587
|
+
# Only wrap actual functions defined in this class
|
|
588
|
+
if inspect.isfunction(original_method):
|
|
589
|
+
try:
|
|
590
|
+
# Verify the method has a proper signature
|
|
591
|
+
sig = inspect.signature(original_method)
|
|
592
|
+
wrapped_method = entity_method(
|
|
593
|
+
name=f"{task_name}.{method_to_wrap}",
|
|
594
|
+
description=description,
|
|
595
|
+
version=version,
|
|
596
|
+
tlp_span_kind=tlp_span_kind,
|
|
597
|
+
)(original_method)
|
|
598
|
+
# Set the wrapped method on the class
|
|
599
|
+
setattr(cls, method_to_wrap, wrapped_method)
|
|
600
|
+
except Exception:
|
|
601
|
+
# Don't wrap methods that can't be properly decorated
|
|
602
|
+
continue
|
|
581
603
|
|
|
582
604
|
return cls
|
|
583
605
|
|
|
@@ -66,26 +66,71 @@ class SLIMInstrumentor(BaseInstrumentor):
|
|
|
66
66
|
if traceparent and session_id:
|
|
67
67
|
baggage.set_baggage(f"execution.{traceparent}", session_id)
|
|
68
68
|
|
|
69
|
-
# Process message payload
|
|
69
|
+
# Process message payload and preserve original structure
|
|
70
70
|
if isinstance(message, bytes):
|
|
71
71
|
try:
|
|
72
72
|
decoded_message = message.decode("utf-8")
|
|
73
73
|
try:
|
|
74
|
-
|
|
75
|
-
|
|
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
|
+
}
|
|
76
88
|
except json.JSONDecodeError:
|
|
77
|
-
|
|
89
|
+
# If it's not JSON, treat as raw payload
|
|
90
|
+
wrapped_message = {
|
|
91
|
+
"headers": headers,
|
|
92
|
+
"payload": decoded_message,
|
|
93
|
+
}
|
|
78
94
|
except UnicodeDecodeError:
|
|
79
|
-
|
|
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
|
+
}
|
|
80
100
|
elif isinstance(message, str):
|
|
81
|
-
|
|
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
|
|
110
|
+
else:
|
|
111
|
+
# If it's not a dict, wrap it as payload
|
|
112
|
+
wrapped_message = {
|
|
113
|
+
"headers": headers,
|
|
114
|
+
"payload": original_message,
|
|
115
|
+
}
|
|
116
|
+
except json.JSONDecodeError:
|
|
117
|
+
# If it's not JSON, treat as raw payload
|
|
118
|
+
wrapped_message = {
|
|
119
|
+
"headers": headers,
|
|
120
|
+
"payload": message,
|
|
121
|
+
}
|
|
122
|
+
elif isinstance(message, dict):
|
|
123
|
+
# If it's already a dict, preserve all fields and merge headers
|
|
124
|
+
wrapped_message = message.copy()
|
|
125
|
+
existing_headers = wrapped_message.get("headers", {})
|
|
126
|
+
existing_headers.update(headers)
|
|
127
|
+
wrapped_message["headers"] = existing_headers
|
|
82
128
|
else:
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
}
|
|
129
|
+
# For other types, convert to JSON and wrap as payload
|
|
130
|
+
wrapped_message = {
|
|
131
|
+
"headers": headers,
|
|
132
|
+
"payload": json.dumps(message),
|
|
133
|
+
}
|
|
89
134
|
|
|
90
135
|
message_to_send = json.dumps(wrapped_message).encode("utf-8")
|
|
91
136
|
|
|
@@ -152,20 +197,39 @@ class SLIMInstrumentor(BaseInstrumentor):
|
|
|
152
197
|
session_id = stored_session_id
|
|
153
198
|
set_session_id(session_id, traceparent=traceparent)
|
|
154
199
|
|
|
155
|
-
# Process
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
200
|
+
# Process the complete message structure
|
|
201
|
+
# Remove tracing headers before returning the message
|
|
202
|
+
message_to_return = message_dict.copy()
|
|
203
|
+
if "headers" in message_to_return:
|
|
204
|
+
headers_copy = message_to_return["headers"].copy()
|
|
205
|
+
# Remove tracing-specific headers but keep other headers
|
|
206
|
+
headers_copy.pop("traceparent", None)
|
|
207
|
+
headers_copy.pop("session_id", None)
|
|
208
|
+
if headers_copy:
|
|
209
|
+
message_to_return["headers"] = headers_copy
|
|
210
|
+
else:
|
|
211
|
+
message_to_return.pop("headers", None)
|
|
212
|
+
|
|
213
|
+
# If the message only contains a payload field and no other fields,
|
|
214
|
+
# return just the payload for backward compatibility
|
|
215
|
+
if len(message_to_return) == 1 and "payload" in message_to_return:
|
|
216
|
+
payload = message_to_return["payload"]
|
|
217
|
+
if isinstance(payload, str):
|
|
218
|
+
try:
|
|
219
|
+
payload_dict = json.loads(payload)
|
|
220
|
+
return recv_session, json.dumps(payload_dict).encode(
|
|
221
|
+
"utf-8"
|
|
222
|
+
)
|
|
223
|
+
except json.JSONDecodeError:
|
|
224
|
+
return recv_session, payload.encode("utf-8") if isinstance(
|
|
225
|
+
payload, str
|
|
226
|
+
) else payload
|
|
227
|
+
return recv_session, json.dumps(payload).encode(
|
|
228
|
+
"utf-8"
|
|
229
|
+
) if isinstance(payload, (dict, list)) else payload
|
|
230
|
+
else:
|
|
231
|
+
# Return the complete message structure with all original fields
|
|
232
|
+
return recv_session, json.dumps(message_to_return).encode("utf-8")
|
|
169
233
|
|
|
170
234
|
except Exception as e:
|
|
171
235
|
print(f"Error processing message: {e}")
|
|
@@ -1,38 +1,12 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ioa-observe-sdk
|
|
3
|
-
Version: 1.0.
|
|
3
|
+
Version: 1.0.12
|
|
4
4
|
Summary: IOA Observability SDK
|
|
5
5
|
Requires-Python: >=3.10
|
|
6
6
|
Description-Content-Type: text/markdown
|
|
7
7
|
License-File: LICENSE.md
|
|
8
|
-
Requires-Dist: aiohappyeyeballs>=2.4.8
|
|
9
|
-
Requires-Dist: aiohttp>=3.11.18
|
|
10
|
-
Requires-Dist: aiosignal>=1.3.2
|
|
11
|
-
Requires-Dist: annotated-types>=0.7.0
|
|
12
|
-
Requires-Dist: anyio>=4.8.0
|
|
13
|
-
Requires-Dist: async-timeout>=4.0.3
|
|
14
|
-
Requires-Dist: attrs>=25.1.0
|
|
15
|
-
Requires-Dist: backoff>=2.2.1
|
|
16
|
-
Requires-Dist: certifi>=2025.1.31
|
|
17
|
-
Requires-Dist: charset-normalizer>=3.4.1
|
|
18
8
|
Requires-Dist: colorama==0.4.6
|
|
19
|
-
Requires-Dist:
|
|
20
|
-
Requires-Dist: distro>=1.9.0
|
|
21
|
-
Requires-Dist: exceptiongroup>=1.2.2
|
|
22
|
-
Requires-Dist: frozenlist>=1.5.0
|
|
23
|
-
Requires-Dist: googleapis-common-protos>=1.69.0
|
|
24
|
-
Requires-Dist: grpcio>=1.70.0
|
|
25
|
-
Requires-Dist: h11>=0.16.0
|
|
26
|
-
Requires-Dist: httpcore>=1.0.9
|
|
27
|
-
Requires-Dist: httpx>=0.28.1
|
|
28
|
-
Requires-Dist: idna>=3.10
|
|
29
|
-
Requires-Dist: importlib_metadata>=8.5.0
|
|
30
|
-
Requires-Dist: Jinja2>=3.1.6
|
|
31
|
-
Requires-Dist: jiter>=0.8.2
|
|
32
|
-
Requires-Dist: MarkupSafe>=3.0.2
|
|
33
|
-
Requires-Dist: monotonic>=1.6
|
|
34
|
-
Requires-Dist: multidict>=6.1.0
|
|
35
|
-
Requires-Dist: openai>=1.75.0
|
|
9
|
+
Requires-Dist: requests>=2.32.3
|
|
36
10
|
Requires-Dist: opentelemetry-api==1.33.1
|
|
37
11
|
Requires-Dist: opentelemetry-distro
|
|
38
12
|
Requires-Dist: opentelemetry-exporter-otlp==1.33.1
|
|
@@ -44,6 +18,7 @@ Requires-Dist: opentelemetry-instrumentation-logging==0.54b1
|
|
|
44
18
|
Requires-Dist: opentelemetry-instrumentation-openai==0.40.8
|
|
45
19
|
Requires-Dist: opentelemetry-instrumentation-llamaindex==0.40.8
|
|
46
20
|
Requires-Dist: opentelemetry-instrumentation-ollama==0.40.8
|
|
21
|
+
Requires-Dist: opentelemetry-instrumentation-anthropic==0.40.8
|
|
47
22
|
Requires-Dist: opentelemetry-instrumentation-langchain==0.40.8
|
|
48
23
|
Requires-Dist: opentelemetry-instrumentation-threading==00.54b1
|
|
49
24
|
Requires-Dist: opentelemetry-instrumentation-urllib3==0.54b1
|
|
@@ -52,33 +27,10 @@ Requires-Dist: opentelemetry-sdk==1.33.1
|
|
|
52
27
|
Requires-Dist: opentelemetry-semantic-conventions==0.54b1
|
|
53
28
|
Requires-Dist: opentelemetry-semantic-conventions-ai==0.4.9
|
|
54
29
|
Requires-Dist: opentelemetry-util-http==0.54b1
|
|
55
|
-
Requires-Dist: packaging>=24.2
|
|
56
|
-
Requires-Dist: propcache>=0.3.0
|
|
57
|
-
Requires-Dist: protobuf>=5.29.3
|
|
58
|
-
Requires-Dist: pydantic>=2.10.6
|
|
59
|
-
Requires-Dist: pydantic_core>=2.27.2
|
|
60
|
-
Requires-Dist: python-dateutil>=2.9.0.post0
|
|
61
|
-
Requires-Dist: regex==2024.11.6
|
|
62
|
-
Requires-Dist: requests>=2.32.3
|
|
63
|
-
Requires-Dist: six>=1.17.0
|
|
64
|
-
Requires-Dist: sniffio>=1.3.1
|
|
65
|
-
Requires-Dist: tenacity>=9.0.0
|
|
66
|
-
Requires-Dist: tiktoken>=0.9.0
|
|
67
|
-
Requires-Dist: tqdm>=4.67.1
|
|
68
|
-
Requires-Dist: typing_extensions>=4.12.2
|
|
69
|
-
Requires-Dist: urllib3>=2.3.0
|
|
70
|
-
Requires-Dist: wrapt>=1.17.2
|
|
71
|
-
Requires-Dist: yarl>=1.18.3
|
|
72
|
-
Requires-Dist: zipp>=3.21.0
|
|
73
30
|
Requires-Dist: langgraph>=0.3.2
|
|
74
31
|
Requires-Dist: langchain>=0.3.19
|
|
75
32
|
Requires-Dist: langchain-openai>=0.3.8
|
|
76
|
-
Requires-Dist: langchain-community>=0.3.25
|
|
77
33
|
Requires-Dist: llama-index>=0.12.34
|
|
78
|
-
Requires-Dist: opentelemetry-instrumentation-requests
|
|
79
|
-
Requires-Dist: opentelemetry-instrumentation-transformers>=0.40.8
|
|
80
|
-
Requires-Dist: opentelemetry-instrumentation-crewai>=0.40.8
|
|
81
|
-
Requires-Dist: llama-index-utils-workflow>=0.3.1
|
|
82
34
|
Requires-Dist: pytest
|
|
83
35
|
Requires-Dist: pytest-vcr
|
|
84
36
|
Dynamic: license-file
|
|
@@ -10,11 +10,11 @@ ioa_observe/sdk/config/__init__.py,sha256=8aVNaw0yRNLFPxlf97iOZLlJVcV81ivSDnudH2
|
|
|
10
10
|
ioa_observe/sdk/connectors/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
11
11
|
ioa_observe/sdk/connectors/slim.py,sha256=NwbKEV7d5NIOqmG8zKqtgGigSJl7kf3QJ65z2gxpsY8,8498
|
|
12
12
|
ioa_observe/sdk/decorators/__init__.py,sha256=Lv5EbouBazvWaYB0N82v26pqKtj2FAqlwfLKEh5e8Q0,3251
|
|
13
|
-
ioa_observe/sdk/decorators/base.py,sha256=
|
|
13
|
+
ioa_observe/sdk/decorators/base.py,sha256=kR_0KWMMbOdJ_t9m5EZ9ZUj3pmKWEgkj0-E1F3c-nIE,29969
|
|
14
14
|
ioa_observe/sdk/decorators/util.py,sha256=WMkzmwD7Js0g1BbId9_qR4pwhnaIJdW588zVc5dpqdQ,25399
|
|
15
15
|
ioa_observe/sdk/instrumentations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
16
16
|
ioa_observe/sdk/instrumentations/a2a.py,sha256=ov_9ckkymf_qFXG0iXVWfxlW-3kFcP-knrM_t-Cf72w,4414
|
|
17
|
-
ioa_observe/sdk/instrumentations/slim.py,sha256=
|
|
17
|
+
ioa_observe/sdk/instrumentations/slim.py,sha256=J5e6XeshH55xXaUiT9_j4R_n6VQELzBjgRAU-AgZGOg,11435
|
|
18
18
|
ioa_observe/sdk/logging/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
19
19
|
ioa_observe/sdk/logging/logging.py,sha256=HZxW9s8Due7jgiNkdI38cIjv5rC9D-Flta3RQMOnpow,2891
|
|
20
20
|
ioa_observe/sdk/metrics/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -38,8 +38,8 @@ ioa_observe/sdk/utils/const.py,sha256=GwbHakKPjBL4wLqAVkDrSoKB-8p18EUrbaqPuRuV_x
|
|
|
38
38
|
ioa_observe/sdk/utils/in_memory_span_exporter.py,sha256=H_4TRaThMO1H6vUQ0OpQvzJk_fZH0OOsRAM1iZQXsR8,2112
|
|
39
39
|
ioa_observe/sdk/utils/json_encoder.py,sha256=g4NQ0tTqgWssY6I1D7r4zo0G6PiUo61jhofTAw5-jno,639
|
|
40
40
|
ioa_observe/sdk/utils/package_check.py,sha256=1d1MjxhwoEZIx9dumirT2pRsEWgn-m-SI4npDeEalew,576
|
|
41
|
-
ioa_observe_sdk-1.0.
|
|
42
|
-
ioa_observe_sdk-1.0.
|
|
43
|
-
ioa_observe_sdk-1.0.
|
|
44
|
-
ioa_observe_sdk-1.0.
|
|
45
|
-
ioa_observe_sdk-1.0.
|
|
41
|
+
ioa_observe_sdk-1.0.12.dist-info/licenses/LICENSE.md,sha256=55VjUfgjWOS4vv3Cf55gfq-RxjPgRIO2vlgYPUuC5lA,11362
|
|
42
|
+
ioa_observe_sdk-1.0.12.dist-info/METADATA,sha256=3owAgvI_xgARwMohc3ticBRqKwju2w-poBOu1SILHC4,6109
|
|
43
|
+
ioa_observe_sdk-1.0.12.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
44
|
+
ioa_observe_sdk-1.0.12.dist-info/top_level.txt,sha256=Yt-6Y1olZEDqCs2REeqI30WjYx0pLGQSVqzYmDd67N8,12
|
|
45
|
+
ioa_observe_sdk-1.0.12.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|