aiqa-client 0.3.1__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.
- aiqa/__init__.py +66 -0
- aiqa/aiqa_exporter.py +481 -0
- aiqa/client.py +170 -0
- aiqa/experiment_runner.py +336 -0
- aiqa/object_serialiser.py +361 -0
- aiqa/py.typed +0 -0
- aiqa/test_experiment_runner.py +176 -0
- aiqa/test_tracing.py +230 -0
- aiqa/tracing.py +1256 -0
- aiqa_client-0.3.1.dist-info/METADATA +247 -0
- aiqa_client-0.3.1.dist-info/RECORD +14 -0
- aiqa_client-0.3.1.dist-info/WHEEL +5 -0
- aiqa_client-0.3.1.dist-info/licenses/LICENSE +22 -0
- aiqa_client-0.3.1.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: aiqa-client
|
|
3
|
+
Version: 0.3.1
|
|
4
|
+
Summary: OpenTelemetry-based Python client for tracing functions and sending traces to the AIQA server
|
|
5
|
+
Author-email: AIQA <info@aiqa.dev>
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/winterstein/aiqa
|
|
8
|
+
Project-URL: Documentation, https://github.com/winterstein/aiqa/tree/main/client-python
|
|
9
|
+
Project-URL: Repository, https://github.com/winterstein/aiqa
|
|
10
|
+
Project-URL: Issues, https://github.com/winterstein/aiqa/issues
|
|
11
|
+
Keywords: opentelemetry,tracing,observability,aiqa,monitoring
|
|
12
|
+
Classifier: Development Status :: 4 - Beta
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
21
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
22
|
+
Classifier: Topic :: System :: Monitoring
|
|
23
|
+
Requires-Python: >=3.8
|
|
24
|
+
Description-Content-Type: text/markdown
|
|
25
|
+
License-File: LICENSE
|
|
26
|
+
Requires-Dist: opentelemetry-api>=1.24.0
|
|
27
|
+
Requires-Dist: opentelemetry-sdk>=1.24.0
|
|
28
|
+
Requires-Dist: opentelemetry-semantic-conventions>=0.40b0
|
|
29
|
+
Requires-Dist: aiohttp>=3.9.0
|
|
30
|
+
Requires-Dist: requests>=2.31.0
|
|
31
|
+
Provides-Extra: dev
|
|
32
|
+
Requires-Dist: pytest>=7.0.0; extra == "dev"
|
|
33
|
+
Requires-Dist: pytest-asyncio>=0.21.0; extra == "dev"
|
|
34
|
+
Requires-Dist: black>=23.0.0; extra == "dev"
|
|
35
|
+
Requires-Dist: ruff>=0.1.0; extra == "dev"
|
|
36
|
+
Dynamic: license-file
|
|
37
|
+
|
|
38
|
+
# A Python client for the AIQA server
|
|
39
|
+
|
|
40
|
+
OpenTelemetry-based client for tracing Python functions and sending traces to the AIQA server.
|
|
41
|
+
|
|
42
|
+
## Installation
|
|
43
|
+
|
|
44
|
+
### From PyPI (recommended)
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
pip install aiqa-client
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
### From source
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
python -m venv .venv
|
|
54
|
+
source .venv/bin/activate # On Windows: .venv\Scripts\activate
|
|
55
|
+
pip install -r requirements.txt
|
|
56
|
+
pip install -e .
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
See [TESTING.md](TESTING.md) for detailed testing instructions.
|
|
60
|
+
|
|
61
|
+
## Setup
|
|
62
|
+
|
|
63
|
+
Set the following environment variables:
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
export AIQA_SERVER_URL="http://localhost:3000"
|
|
67
|
+
export AIQA_API_KEY="your-api-key"
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## Usage
|
|
71
|
+
|
|
72
|
+
### Basic Usage
|
|
73
|
+
|
|
74
|
+
```python
|
|
75
|
+
from dotenv import load_dotenv
|
|
76
|
+
from aiqa import get_aiqa_client, WithTracing
|
|
77
|
+
|
|
78
|
+
# Load environment variables from .env file (if using one)
|
|
79
|
+
load_dotenv()
|
|
80
|
+
|
|
81
|
+
# Initialize client (must be called before using WithTracing)
|
|
82
|
+
# This loads environment variables and initializes the tracing system
|
|
83
|
+
get_aiqa_client()
|
|
84
|
+
|
|
85
|
+
@WithTracing
|
|
86
|
+
def my_function(x, y):
|
|
87
|
+
return x + y
|
|
88
|
+
|
|
89
|
+
@WithTracing
|
|
90
|
+
async def my_async_function(x, y):
|
|
91
|
+
await asyncio.sleep(0.1)
|
|
92
|
+
return x * y
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
### Custom Span Name
|
|
96
|
+
|
|
97
|
+
```python
|
|
98
|
+
@WithTracing(name="custom_span_name")
|
|
99
|
+
def my_function():
|
|
100
|
+
pass
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
### Input/Output Filtering
|
|
104
|
+
|
|
105
|
+
```python
|
|
106
|
+
@WithTracing(
|
|
107
|
+
filter_input=lambda x: {"filtered": str(x)},
|
|
108
|
+
filter_output=lambda x: {"result": x}
|
|
109
|
+
)
|
|
110
|
+
def my_function(data):
|
|
111
|
+
return {"processed": data}
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
### Flushing Spans
|
|
115
|
+
|
|
116
|
+
Spans are automatically flushed every 5 seconds. To flush immediately:
|
|
117
|
+
|
|
118
|
+
```python
|
|
119
|
+
from aiqa import flush_tracing
|
|
120
|
+
import asyncio
|
|
121
|
+
|
|
122
|
+
async def main():
|
|
123
|
+
# Your code here
|
|
124
|
+
await flush_tracing()
|
|
125
|
+
|
|
126
|
+
asyncio.run(main())
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
### Shutting Down
|
|
130
|
+
|
|
131
|
+
To ensure all spans are sent before process exit:
|
|
132
|
+
|
|
133
|
+
```python
|
|
134
|
+
from aiqa import shutdown_tracing
|
|
135
|
+
import asyncio
|
|
136
|
+
|
|
137
|
+
async def main():
|
|
138
|
+
# Your code here
|
|
139
|
+
await shutdown_tracing()
|
|
140
|
+
|
|
141
|
+
asyncio.run(main())
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
### Setting Span Attributes and Names
|
|
145
|
+
|
|
146
|
+
```python
|
|
147
|
+
from aiqa import set_span_attribute, set_span_name
|
|
148
|
+
|
|
149
|
+
def my_function():
|
|
150
|
+
set_span_attribute("custom.attribute", "value")
|
|
151
|
+
set_span_name("custom_span_name")
|
|
152
|
+
# ... rest of function
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
### Grouping Traces by Conversation
|
|
156
|
+
|
|
157
|
+
To group multiple traces together that are part of the same conversation or session:
|
|
158
|
+
|
|
159
|
+
```python
|
|
160
|
+
from aiqa import WithTracing, set_conversation_id
|
|
161
|
+
|
|
162
|
+
@WithTracing
|
|
163
|
+
def handle_user_request(user_id: str, session_id: str):
|
|
164
|
+
# Set conversation ID to group all traces for this user session
|
|
165
|
+
set_conversation_id(f"user_{user_id}_session_{session_id}")
|
|
166
|
+
# All spans created in this function and its children will have this gen_ai.conversation.id
|
|
167
|
+
# ... rest of function
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
The `gen_ai.conversation.id` attribute allows you to filter and group traces in the AIQA server by conversation, making it easier to analyze multi-step interactions or user sessions. See the [OpenTelemetry GenAI Events specification](https://opentelemetry.io/docs/specs/semconv/gen-ai/gen-ai-events/) for more details.
|
|
171
|
+
|
|
172
|
+
### Trace ID Propagation Across Services/Agents
|
|
173
|
+
|
|
174
|
+
To link traces across different services or agents, you can extract and propagate trace IDs:
|
|
175
|
+
|
|
176
|
+
#### Getting Current Trace ID
|
|
177
|
+
|
|
178
|
+
```python
|
|
179
|
+
from aiqa import get_trace_id, get_span_id
|
|
180
|
+
|
|
181
|
+
# Get the current trace ID and span ID
|
|
182
|
+
trace_id = get_trace_id() # Returns hex string (32 chars) or None
|
|
183
|
+
span_id = get_span_id() # Returns hex string (16 chars) or None
|
|
184
|
+
|
|
185
|
+
# Pass these to another service (e.g., in HTTP headers, message queue, etc.)
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
#### Continuing a Trace in Another Service
|
|
189
|
+
|
|
190
|
+
```python
|
|
191
|
+
from aiqa import create_span_from_trace_id
|
|
192
|
+
|
|
193
|
+
# Continue a trace from another service/agent
|
|
194
|
+
# trace_id and parent_span_id come from the other service
|
|
195
|
+
with create_span_from_trace_id(
|
|
196
|
+
trace_id="abc123...",
|
|
197
|
+
parent_span_id="def456...",
|
|
198
|
+
span_name="service_b_operation"
|
|
199
|
+
):
|
|
200
|
+
# Your code here - this span will be linked to the original trace
|
|
201
|
+
pass
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
#### Using OpenTelemetry Context Propagation (Recommended)
|
|
205
|
+
|
|
206
|
+
For HTTP requests, use the built-in context propagation:
|
|
207
|
+
|
|
208
|
+
```python
|
|
209
|
+
from aiqa import inject_trace_context, extract_trace_context
|
|
210
|
+
import requests
|
|
211
|
+
from opentelemetry.trace import use_span
|
|
212
|
+
|
|
213
|
+
# In the sending service:
|
|
214
|
+
headers = {}
|
|
215
|
+
inject_trace_context(headers) # Adds trace context to headers
|
|
216
|
+
response = requests.get("http://other-service/api", headers=headers)
|
|
217
|
+
|
|
218
|
+
# In the receiving service:
|
|
219
|
+
# Extract context from incoming request headers
|
|
220
|
+
ctx = extract_trace_context(request.headers)
|
|
221
|
+
|
|
222
|
+
# Use the context to create a span
|
|
223
|
+
from opentelemetry.trace import use_span
|
|
224
|
+
with use_span(ctx):
|
|
225
|
+
# Your code here
|
|
226
|
+
pass
|
|
227
|
+
|
|
228
|
+
# Or create a span with the context
|
|
229
|
+
from opentelemetry import trace
|
|
230
|
+
tracer = trace.get_tracer("aiqa-tracer")
|
|
231
|
+
with tracer.start_as_current_span("operation", context=ctx):
|
|
232
|
+
# Your code here
|
|
233
|
+
pass
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
## Features
|
|
237
|
+
|
|
238
|
+
- Automatic tracing of function calls (sync and async)
|
|
239
|
+
- Records function inputs and outputs as span attributes
|
|
240
|
+
- Automatic error tracking and exception recording
|
|
241
|
+
- Thread-safe span buffering and auto-flushing
|
|
242
|
+
- OpenTelemetry context propagation for nested spans
|
|
243
|
+
- Trace ID propagation utilities for distributed tracing
|
|
244
|
+
|
|
245
|
+
## Example
|
|
246
|
+
|
|
247
|
+
See `example.py` for a complete working example.
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
aiqa/__init__.py,sha256=2a2oN8-X0wFgL0eq5_M7Okss0vdlLOK9hKOfdHc7oc0,1563
|
|
2
|
+
aiqa/aiqa_exporter.py,sha256=Gf1gtVEEAMNrbWhlLp0mn7CdXntqqx-zlruBfB7tS7o,22104
|
|
3
|
+
aiqa/client.py,sha256=wE6EsypbTfp3Cz39IhEycEVT0IZGdJz7yQvtZ15qKJo,6364
|
|
4
|
+
aiqa/experiment_runner.py,sha256=ZEDwECstAv4lWXpcdB9WSxfDQj43iqkGzB_YzoY933M,12053
|
|
5
|
+
aiqa/object_serialiser.py,sha256=iFxVGw-liOFyrkmTWuD5Bm0zCLPTN4QbynR6IPDSVwI,12993
|
|
6
|
+
aiqa/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
7
|
+
aiqa/test_experiment_runner.py,sha256=LM8BuCrzBZL0Wyu_ierK0tNLsOUxxMTAHbAGW2G0qp0,5562
|
|
8
|
+
aiqa/test_tracing.py,sha256=mSVrhRQ6Dz5djlSUkCt097sIr84562w6E0BnuQDpMrI,8347
|
|
9
|
+
aiqa/tracing.py,sha256=akilXthvAz8NfJKl3293cHsdJU_P3z4kpdTDfwHipZ0,50014
|
|
10
|
+
aiqa_client-0.3.1.dist-info/licenses/LICENSE,sha256=kIzkzLuzG0HHaWYm4F4W5FeJ1Yxut3Ec6bhLWyw798A,1062
|
|
11
|
+
aiqa_client-0.3.1.dist-info/METADATA,sha256=Ahw30GgHiSJ_I50OicqG17645k-0F10WgJEdRTN8dLk,6712
|
|
12
|
+
aiqa_client-0.3.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
13
|
+
aiqa_client-0.3.1.dist-info/top_level.txt,sha256=nwcsuVVSuWu27iLxZd4n1evVzv1W6FVTrSnCXCc-NQs,5
|
|
14
|
+
aiqa_client-0.3.1.dist-info/RECORD,,
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 AIQA
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
22
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
aiqa
|