ragaai-catalyst 2.2.4.1b4__py3-none-any.whl → 2.2.4.1b5__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.
- ragaai_catalyst/tracers/agentic_tracing/upload/session_manager.py +124 -0
- ragaai_catalyst/tracers/agentic_tracing/upload/trace_uploader.py +122 -34
- ragaai_catalyst/tracers/agentic_tracing/upload/upload_agentic_traces.py +45 -48
- ragaai_catalyst/tracers/agentic_tracing/upload/upload_code.py +79 -42
- ragaai_catalyst/tracers/exporters/ragaai_trace_exporter.py +25 -50
- ragaai_catalyst/tracers/tracer.py +1 -23
- {ragaai_catalyst-2.2.4.1b4.dist-info → ragaai_catalyst-2.2.4.1b5.dist-info}/METADATA +1 -1
- {ragaai_catalyst-2.2.4.1b4.dist-info → ragaai_catalyst-2.2.4.1b5.dist-info}/RECORD +11 -10
- {ragaai_catalyst-2.2.4.1b4.dist-info → ragaai_catalyst-2.2.4.1b5.dist-info}/WHEEL +0 -0
- {ragaai_catalyst-2.2.4.1b4.dist-info → ragaai_catalyst-2.2.4.1b5.dist-info}/licenses/LICENSE +0 -0
- {ragaai_catalyst-2.2.4.1b4.dist-info → ragaai_catalyst-2.2.4.1b5.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,124 @@
|
|
1
|
+
import logging
|
2
|
+
import os
|
3
|
+
import threading
|
4
|
+
|
5
|
+
from requests.adapters import HTTPAdapter
|
6
|
+
from urllib3.util.retry import Retry
|
7
|
+
from urllib3.exceptions import PoolError, MaxRetryError, NewConnectionError
|
8
|
+
from requests.exceptions import ConnectionError, Timeout
|
9
|
+
from ragaai_catalyst import RagaAICatalyst
|
10
|
+
import requests
|
11
|
+
|
12
|
+
logger = logging.getLogger(__name__)
|
13
|
+
|
14
|
+
|
15
|
+
class SessionManager:
|
16
|
+
"""Shared session manager with connection pooling for HTTP requests"""
|
17
|
+
_instance = None
|
18
|
+
_session = None
|
19
|
+
_lock = threading.Lock()
|
20
|
+
|
21
|
+
def __new__(cls):
|
22
|
+
if cls._instance is None:
|
23
|
+
with cls._lock: # Thread-safe singleton
|
24
|
+
if cls._instance is None: # Double-check locking
|
25
|
+
logger.info("Creating new SessionManager singleton instance")
|
26
|
+
cls._instance = super(SessionManager, cls).__new__(cls)
|
27
|
+
cls._instance._initialize_session()
|
28
|
+
else:
|
29
|
+
logger.debug("SessionManager instance already exists, returning existing instance")
|
30
|
+
else:
|
31
|
+
logger.debug("SessionManager instance exists, returning existing instance")
|
32
|
+
return cls._instance
|
33
|
+
|
34
|
+
def _initialize_session(self):
|
35
|
+
"""Initialize session with connection pooling and retry strategy"""
|
36
|
+
logger.info("Initializing HTTP session with connection pooling and retry strategy")
|
37
|
+
self._session = requests.Session()
|
38
|
+
|
39
|
+
retry_strategy = Retry(
|
40
|
+
total=3, # number of retries
|
41
|
+
backoff_factor=0.5, # wait 0.5, 1, 2... seconds between retries
|
42
|
+
status_forcelist=[500, 502, 503, 504] # HTTP status codes to retry on
|
43
|
+
)
|
44
|
+
|
45
|
+
adapter = HTTPAdapter(
|
46
|
+
max_retries=retry_strategy,
|
47
|
+
pool_connections=5, # number of connection pools to cache (per host)
|
48
|
+
pool_maxsize=50, # maximum number of connections in each pool
|
49
|
+
pool_block=True # Block/wait when pool is full rather than raising error
|
50
|
+
)
|
51
|
+
|
52
|
+
self._session.mount("http://", adapter)
|
53
|
+
self._session.mount("https://", adapter)
|
54
|
+
|
55
|
+
logger.info("HTTP session initialized successfully with adapters mounted for http:// and https://")
|
56
|
+
|
57
|
+
# Warm up connection pool using RagaAICatalyst.BASE_URL
|
58
|
+
if os.getenv("RAGAAI_CATALYST_BASE_URL") is not None:
|
59
|
+
base_url = os.getenv("RAGAAI_CATALYST_BASE_URL")
|
60
|
+
logger.info(f"Warming up connection pool using RagaAICatalyst.BASE_URL: {base_url}")
|
61
|
+
self.warm_up_connections(base_url)
|
62
|
+
else:
|
63
|
+
logger.warning(f"RAGAAI_CATALYST_BASE_URL {base_url} not available, skipping connection warmup")
|
64
|
+
|
65
|
+
@property
|
66
|
+
def session(self):
|
67
|
+
if self._session is None:
|
68
|
+
logger.warning("Session accessed but not initialized, reinitializing...")
|
69
|
+
self._initialize_session()
|
70
|
+
return self._session
|
71
|
+
|
72
|
+
def warm_up_connections(self, base_url, num_connections=3):
|
73
|
+
"""
|
74
|
+
Warm up the connection pool by making lightweight requests to healthcheck endpoint.
|
75
|
+
This can help prevent RemoteDisconnected errors on initial requests.
|
76
|
+
"""
|
77
|
+
if not self._session:
|
78
|
+
return
|
79
|
+
|
80
|
+
# Construct healthcheck URL
|
81
|
+
healthcheck_url = f"{base_url.rstrip('/')}/healthcheck"
|
82
|
+
logger.info(f"Warming up connection pool with {num_connections} connections to {healthcheck_url}")
|
83
|
+
|
84
|
+
for i in range(num_connections):
|
85
|
+
try:
|
86
|
+
# Make a lightweight HEAD request to the healthcheck endpoint to warm up the connection
|
87
|
+
response = self._session.head(healthcheck_url, timeout=5)
|
88
|
+
logger.info(f"Warmup connection {i+1}: Status {response.status_code}")
|
89
|
+
except Exception as e:
|
90
|
+
logger.error(f"Warmup connection {i+1} failed (this is normal): {e}")
|
91
|
+
# Ignore failures during warmup as they're expected
|
92
|
+
continue
|
93
|
+
|
94
|
+
logger.info("Connection pool warmup completed")
|
95
|
+
|
96
|
+
def close(self):
|
97
|
+
"""Close the session"""
|
98
|
+
if self._session:
|
99
|
+
logger.info("Closing HTTP session")
|
100
|
+
self._session.close()
|
101
|
+
self._session = None
|
102
|
+
logger.info("HTTP session closed successfully")
|
103
|
+
else:
|
104
|
+
logger.debug("Close called but session was already None")
|
105
|
+
|
106
|
+
def handle_request_exceptions(self, e, operation_name):
|
107
|
+
"""Handle common request exceptions with appropriate logging"""
|
108
|
+
logger.error(f"Exception occurred during {operation_name}")
|
109
|
+
if isinstance(e, (PoolError, MaxRetryError)):
|
110
|
+
logger.error(f"Connection pool exhausted during {operation_name}: {e}")
|
111
|
+
elif isinstance(e, NewConnectionError):
|
112
|
+
logger.error(f"Failed to establish new connection during {operation_name}: {e}")
|
113
|
+
elif isinstance(e, ConnectionError):
|
114
|
+
logger.error(f"Connection error during {operation_name}: {e}")
|
115
|
+
elif isinstance(e, Timeout):
|
116
|
+
logger.error(f"Request timeout during {operation_name}: {e}")
|
117
|
+
else:
|
118
|
+
logger.error(f"Unexpected error during {operation_name}: {e}")
|
119
|
+
|
120
|
+
|
121
|
+
# Global session manager instance
|
122
|
+
logger.info("Creating global SessionManager instance")
|
123
|
+
session_manager = SessionManager()
|
124
|
+
logger.info(f"Global SessionManager instance created with ID: {id(session_manager)}")
|
@@ -22,6 +22,7 @@ from typing import Dict, Any, Optional
|
|
22
22
|
import threading
|
23
23
|
import uuid
|
24
24
|
|
25
|
+
|
25
26
|
# Set up logging
|
26
27
|
log_dir = os.path.join(tempfile.gettempdir(), "ragaai_logs")
|
27
28
|
os.makedirs(log_dir, exist_ok=True)
|
@@ -49,11 +50,13 @@ try:
|
|
49
50
|
from ragaai_catalyst.tracers.agentic_tracing.upload.upload_code import upload_code
|
50
51
|
# from ragaai_catalyst.tracers.agentic_tracing.upload.upload_trace_metric import upload_trace_metric
|
51
52
|
from ragaai_catalyst.tracers.agentic_tracing.utils.create_dataset_schema import create_dataset_schema_with_trace
|
53
|
+
from ragaai_catalyst.tracers.agentic_tracing.upload.session_manager import session_manager
|
52
54
|
from ragaai_catalyst import RagaAICatalyst
|
53
55
|
IMPORTS_AVAILABLE = True
|
54
56
|
except ImportError:
|
55
57
|
logger.warning("RagaAI Catalyst imports not available - running in test mode")
|
56
58
|
IMPORTS_AVAILABLE = False
|
59
|
+
session_manager = None
|
57
60
|
|
58
61
|
# Define task queue directory
|
59
62
|
QUEUE_DIR = os.path.join(tempfile.gettempdir(), "ragaai_tasks")
|
@@ -72,6 +75,10 @@ _executor_lock = threading.Lock()
|
|
72
75
|
_futures: Dict[str, Any] = {}
|
73
76
|
_futures_lock = threading.Lock()
|
74
77
|
|
78
|
+
# Dataset creation cache to avoid redundant API calls
|
79
|
+
_dataset_cache: Dict[str, Dict[str, Any]] = {}
|
80
|
+
_dataset_cache_lock = threading.Lock()
|
81
|
+
DATASET_CACHE_DURATION = 600 # 10 minutes in seconds
|
75
82
|
|
76
83
|
_cleanup_lock = threading.Lock()
|
77
84
|
_last_cleanup = 0
|
@@ -88,7 +95,7 @@ def get_executor(max_workers=None):
|
|
88
95
|
if _executor is None:
|
89
96
|
# Calculate optimal worker count
|
90
97
|
if max_workers is None:
|
91
|
-
max_workers = min(
|
98
|
+
max_workers = min(8, (os.cpu_count() or 1) * 4)
|
92
99
|
|
93
100
|
logger.info(f"Creating ThreadPoolExecutor with {max_workers} workers")
|
94
101
|
_executor = concurrent.futures.ThreadPoolExecutor(
|
@@ -110,9 +117,57 @@ def generate_unique_task_id():
|
|
110
117
|
unique_id = str(uuid.uuid4())[:8] # Short UUID
|
111
118
|
return f"task_{int(time.time())}_{os.getpid()}_{counter}_{unique_id}"
|
112
119
|
|
120
|
+
def _generate_dataset_cache_key(dataset_name: str, project_name: str, base_url: str) -> str:
|
121
|
+
"""Generate a unique cache key for dataset creation"""
|
122
|
+
return f"{dataset_name}#{project_name}#{base_url}"
|
123
|
+
|
124
|
+
def _is_dataset_cached(cache_key: str) -> bool:
|
125
|
+
"""Check if dataset creation is cached and still valid"""
|
126
|
+
with _dataset_cache_lock:
|
127
|
+
if cache_key not in _dataset_cache:
|
128
|
+
return False
|
129
|
+
|
130
|
+
cache_entry = _dataset_cache[cache_key]
|
131
|
+
cache_time = cache_entry.get('timestamp', 0)
|
132
|
+
current_time = time.time()
|
133
|
+
|
134
|
+
# Check if cache is still valid (within 10 minutes)
|
135
|
+
if current_time - cache_time <= DATASET_CACHE_DURATION:
|
136
|
+
logger.info(f"Dataset creation cache hit for key: {cache_key}")
|
137
|
+
return True
|
138
|
+
else:
|
139
|
+
# Cache expired, remove it
|
140
|
+
logger.info(f"Dataset creation cache expired for key: {cache_key}")
|
141
|
+
del _dataset_cache[cache_key]
|
142
|
+
return False
|
143
|
+
|
144
|
+
def _cache_dataset_creation(cache_key: str, response: Any) -> None:
|
145
|
+
"""Cache successful dataset creation"""
|
146
|
+
with _dataset_cache_lock:
|
147
|
+
_dataset_cache[cache_key] = {
|
148
|
+
'timestamp': time.time(),
|
149
|
+
'response': response
|
150
|
+
}
|
151
|
+
|
152
|
+
def _cleanup_expired_cache_entries() -> None:
|
153
|
+
"""Remove expired cache entries"""
|
154
|
+
current_time = time.time()
|
155
|
+
with _dataset_cache_lock:
|
156
|
+
expired_keys = []
|
157
|
+
for cache_key, cache_entry in _dataset_cache.items():
|
158
|
+
cache_time = cache_entry.get('timestamp', 0)
|
159
|
+
if current_time - cache_time > DATASET_CACHE_DURATION:
|
160
|
+
expired_keys.append(cache_key)
|
161
|
+
|
162
|
+
for key in expired_keys:
|
163
|
+
del _dataset_cache[key]
|
164
|
+
|
165
|
+
if expired_keys:
|
166
|
+
logger.info(f"Cleaned up {len(expired_keys)} expired dataset cache entries")
|
167
|
+
|
113
168
|
def process_upload(task_id: str, filepath: str, hash_id: str, zip_path: str,
|
114
169
|
project_name: str, project_id: str, dataset_name: str,
|
115
|
-
user_details: Dict[str, Any], base_url: str, timeout=120, fail_on_trace_error=True) -> Dict[str, Any]:
|
170
|
+
user_details: Dict[str, Any], base_url: str, tracer_type, timeout=120, fail_on_trace_error=True) -> Dict[str, Any]:
|
116
171
|
"""
|
117
172
|
Process a single upload task
|
118
173
|
|
@@ -165,20 +220,36 @@ def process_upload(task_id: str, filepath: str, hash_id: str, zip_path: str,
|
|
165
220
|
save_task_status(result)
|
166
221
|
return result
|
167
222
|
|
168
|
-
# Step 1: Create dataset schema
|
223
|
+
# Step 1: Create dataset schema (with caching)
|
169
224
|
logger.info(f"Creating dataset schema for {dataset_name} with base_url: {base_url} and timeout: {timeout}")
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
225
|
+
|
226
|
+
# Generate cache key and check if dataset creation is already cached
|
227
|
+
cache_key = _generate_dataset_cache_key(dataset_name, project_name, base_url)
|
228
|
+
|
229
|
+
if _is_dataset_cached(cache_key):
|
230
|
+
logger.info(f"Dataset schema creation skipped (cached) for {dataset_name}")
|
231
|
+
else:
|
232
|
+
try:
|
233
|
+
# Clean up expired cache entries periodically
|
234
|
+
# _cleanup_expired_cache_entries()
|
235
|
+
|
236
|
+
response = create_dataset_schema_with_trace(
|
237
|
+
dataset_name=dataset_name,
|
238
|
+
project_name=project_name,
|
239
|
+
base_url=base_url,
|
240
|
+
user_details=user_details,
|
241
|
+
timeout=timeout
|
242
|
+
)
|
243
|
+
logger.info(f"Dataset schema created: {response}")
|
244
|
+
|
245
|
+
# Cache the response only if status code is 200
|
246
|
+
if response and hasattr(response, 'status_code') and response.status_code in [200, 201]:
|
247
|
+
_cache_dataset_creation(cache_key, response)
|
248
|
+
logger.info(f"Response cached successfully for dataset: {dataset_name} and key: {cache_key}")
|
249
|
+
|
250
|
+
except Exception as e:
|
251
|
+
logger.error(f"Error creating dataset schema: {e}")
|
252
|
+
# Continue with other steps
|
182
253
|
|
183
254
|
# Step 2: Upload trace metrics
|
184
255
|
# if filepath and os.path.exists(filepath):
|
@@ -238,28 +309,34 @@ def process_upload(task_id: str, filepath: str, hash_id: str, zip_path: str,
|
|
238
309
|
logger.error(error_msg)
|
239
310
|
|
240
311
|
# Step 4: Upload code hash
|
241
|
-
if
|
242
|
-
logger.info(f"
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
312
|
+
if tracer_type.startswith("agentic/"):
|
313
|
+
logger.info(f"Tracer type '{tracer_type}' matches agentic pattern, proceeding with code upload")
|
314
|
+
if hash_id and zip_path and os.path.exists(zip_path):
|
315
|
+
logger.info(f"Uploading code hash {hash_id} with base_url: {base_url} and timeout: {timeout}")
|
316
|
+
try:
|
317
|
+
response = upload_code(
|
318
|
+
hash_id=hash_id,
|
319
|
+
zip_path=zip_path,
|
320
|
+
project_name=project_name,
|
321
|
+
dataset_name=dataset_name,
|
322
|
+
base_url=base_url,
|
323
|
+
timeout=timeout
|
324
|
+
)
|
325
|
+
if response is None:
|
326
|
+
error_msg = "Code hash not uploaded"
|
327
|
+
logger.error(error_msg)
|
328
|
+
else:
|
329
|
+
logger.info(f"Code hash uploaded successfully: {response}")
|
330
|
+
except Exception as e:
|
331
|
+
logger.error(f"Error uploading code hash: {e}")
|
332
|
+
else:
|
333
|
+
logger.warning(f"Code zip {zip_path} not found, skipping code upload")
|
334
|
+
|
258
335
|
# Mark task as completed
|
259
336
|
result["status"] = STATUS_COMPLETED
|
260
337
|
result["end_time"] = datetime.now().isoformat()
|
261
338
|
logger.info(f"Task {task_id} completed successfully")
|
262
|
-
|
339
|
+
|
263
340
|
except Exception as e:
|
264
341
|
logger.error(f"Error processing task {task_id}: {e}")
|
265
342
|
result["status"] = STATUS_FAILED
|
@@ -302,7 +379,8 @@ def save_task_status(task_status: Dict[str, Any]):
|
|
302
379
|
with open(status_path, "w") as f:
|
303
380
|
json.dump(task_status, f, indent=2)
|
304
381
|
|
305
|
-
def submit_upload_task(filepath, hash_id, zip_path, project_name, project_id, dataset_name, user_details, base_url,
|
382
|
+
def submit_upload_task(filepath, hash_id, zip_path, project_name, project_id, dataset_name, user_details, base_url,
|
383
|
+
tracer_type, timeout=120):
|
306
384
|
"""
|
307
385
|
Submit a new upload task using futures.
|
308
386
|
|
@@ -349,6 +427,7 @@ def submit_upload_task(filepath, hash_id, zip_path, project_name, project_id, da
|
|
349
427
|
dataset_name=dataset_name,
|
350
428
|
user_details=user_details,
|
351
429
|
base_url=base_url,
|
430
|
+
tracer_type = tracer_type,
|
352
431
|
timeout=timeout,
|
353
432
|
fail_on_trace_error=True
|
354
433
|
)
|
@@ -379,6 +458,7 @@ def submit_upload_task(filepath, hash_id, zip_path, project_name, project_id, da
|
|
379
458
|
dataset_name=dataset_name,
|
380
459
|
user_details=user_details,
|
381
460
|
base_url=base_url,
|
461
|
+
tracer_type=tracer_type,
|
382
462
|
timeout=timeout,
|
383
463
|
fail_on_trace_error=True
|
384
464
|
)
|
@@ -550,6 +630,14 @@ def shutdown(timeout=120):
|
|
550
630
|
|
551
631
|
_executor = None
|
552
632
|
|
633
|
+
# Close the session manager to clean up HTTP connections
|
634
|
+
if session_manager is not None:
|
635
|
+
try:
|
636
|
+
session_manager.close()
|
637
|
+
logger.info("Session manager closed successfully")
|
638
|
+
except Exception as e:
|
639
|
+
logger.error(f"Error closing session manager: {e}")
|
640
|
+
|
553
641
|
# Register shutdown handler
|
554
642
|
atexit.register(shutdown)
|
555
643
|
|
@@ -4,13 +4,13 @@ import os
|
|
4
4
|
import re
|
5
5
|
import time
|
6
6
|
from urllib.parse import urlparse, urlunparse
|
7
|
+
from urllib3.exceptions import PoolError, MaxRetryError, NewConnectionError
|
8
|
+
from requests.exceptions import ConnectionError, Timeout, RequestException
|
9
|
+
from .session_manager import session_manager
|
7
10
|
|
8
11
|
import requests
|
9
12
|
|
10
13
|
logger = logging.getLogger(__name__)
|
11
|
-
logging_level = (
|
12
|
-
logger.setLevel(logging.DEBUG) if os.getenv("DEBUG") == "1" else logging.INFO
|
13
|
-
)
|
14
14
|
|
15
15
|
from ragaai_catalyst.ragaai_catalyst import RagaAICatalyst
|
16
16
|
|
@@ -47,42 +47,36 @@ class UploadAgenticTraces:
|
|
47
47
|
"X-Project-Name": self.project_name,
|
48
48
|
}
|
49
49
|
|
50
|
-
logger.debug("Started getting presigned url: ")
|
51
|
-
logger.debug(f"Payload: {payload}")
|
52
|
-
logger.debug(f"Headers: {headers}")
|
53
50
|
try:
|
54
51
|
start_time = time.time()
|
55
52
|
endpoint = f"{self.base_url}/v1/llm/presigned-url"
|
56
53
|
# Changed to POST from GET
|
57
|
-
response =
|
54
|
+
response = session_manager.session.request(
|
58
55
|
"POST", endpoint, headers=headers, data=payload, timeout=self.timeout
|
59
56
|
)
|
60
57
|
elapsed_ms = (time.time() - start_time) * 1000
|
61
58
|
logger.debug(
|
62
59
|
f"API Call: [POST] {endpoint} | Status: {response.status_code} | Time: {elapsed_ms:.2f}ms"
|
63
60
|
)
|
64
|
-
|
61
|
+
|
62
|
+
if response.status_code == 200:
|
65
63
|
presignedURLs = response.json()["data"]["presignedUrls"][0]
|
66
|
-
logger.debug(f"Got presigned url: {presignedURLs}")
|
67
64
|
presignedurl = self.update_presigned_url(presignedURLs, self.base_url)
|
68
|
-
logger.debug(f"Updated presigned url: {presignedurl}")
|
69
65
|
return presignedurl
|
70
66
|
else:
|
71
67
|
# If POST fails, try GET
|
72
|
-
response =
|
68
|
+
response = session_manager.session.request(
|
73
69
|
"GET", endpoint, headers=headers, data=payload, timeout=self.timeout
|
74
70
|
)
|
75
71
|
elapsed_ms = (time.time() - start_time) * 1000
|
76
72
|
logger.debug(
|
77
73
|
f"API Call: [GET] {endpoint} | Status: {response.status_code} | Time: {elapsed_ms:.2f}ms"
|
78
74
|
)
|
79
|
-
if response.status_code
|
75
|
+
if response.status_code == 200:
|
80
76
|
presignedURLs = response.json()["data"]["presignedUrls"][0]
|
81
|
-
logger.debug(f"Got presigned url: {presignedURLs}")
|
82
77
|
presignedurl = self.update_presigned_url(
|
83
78
|
presignedURLs, self.base_url
|
84
79
|
)
|
85
|
-
logger.debug(f"Updated presigned url: {presignedurl}")
|
86
80
|
return presignedurl
|
87
81
|
elif response.status_code == 401:
|
88
82
|
logger.warning("Received 401 error. Attempting to refresh token.")
|
@@ -92,7 +86,7 @@ class UploadAgenticTraces:
|
|
92
86
|
"Authorization": f"Bearer {token}",
|
93
87
|
"X-Project-Name": self.project_name,
|
94
88
|
}
|
95
|
-
response =
|
89
|
+
response = session_manager.session.request(
|
96
90
|
"POST",
|
97
91
|
endpoint,
|
98
92
|
headers=headers,
|
@@ -103,13 +97,11 @@ class UploadAgenticTraces:
|
|
103
97
|
logger.debug(
|
104
98
|
f"API Call: [POST] {endpoint} | Status: {response.status_code} | Time: {elapsed_ms:.2f}ms"
|
105
99
|
)
|
106
|
-
if response.status_code
|
100
|
+
if response.status_code == 200:
|
107
101
|
presignedURLs = response.json()["data"]["presignedUrls"][0]
|
108
|
-
logger.debug(f"Got presigned url: {presignedURLs}")
|
109
102
|
presignedurl = self.update_presigned_url(
|
110
103
|
presignedURLs, self.base_url
|
111
104
|
)
|
112
|
-
logger.debug(f"Updated presigned url: {presignedurl}")
|
113
105
|
return presignedurl
|
114
106
|
else:
|
115
107
|
logger.error(
|
@@ -121,8 +113,10 @@ class UploadAgenticTraces:
|
|
121
113
|
f"Error while getting presigned url: {response.json()['message']}"
|
122
114
|
)
|
123
115
|
return None
|
124
|
-
|
125
|
-
|
116
|
+
except (PoolError, MaxRetryError, NewConnectionError, ConnectionError, Timeout) as e:
|
117
|
+
session_manager.handle_request_exceptions(e, "getting presigned URL")
|
118
|
+
return None
|
119
|
+
except RequestException as e:
|
126
120
|
logger.error(f"Error while getting presigned url: {e}")
|
127
121
|
return None
|
128
122
|
|
@@ -149,16 +143,16 @@ class UploadAgenticTraces:
|
|
149
143
|
|
150
144
|
if "blob.core.windows.net" in presignedUrl: # Azure
|
151
145
|
headers["x-ms-blob-type"] = "BlockBlob"
|
152
|
-
|
146
|
+
logger.info("Uploading agentic traces to presigned URL...")
|
153
147
|
try:
|
154
148
|
with open(filename) as f:
|
155
149
|
payload = f.read().replace("\n", "").replace("\r", "").encode()
|
156
150
|
except Exception as e:
|
157
|
-
|
151
|
+
logger.error(f"Error while reading file: {e}")
|
158
152
|
return False
|
159
153
|
try:
|
160
154
|
start_time = time.time()
|
161
|
-
response =
|
155
|
+
response = session_manager.session.request(
|
162
156
|
"PUT", presignedUrl, headers=headers, data=payload, timeout=self.timeout
|
163
157
|
)
|
164
158
|
elapsed_ms = (time.time() - start_time) * 1000
|
@@ -168,8 +162,11 @@ class UploadAgenticTraces:
|
|
168
162
|
if response.status_code != 200 or response.status_code != 201:
|
169
163
|
return response, response.status_code
|
170
164
|
return True
|
171
|
-
except
|
172
|
-
|
165
|
+
except (PoolError, MaxRetryError, NewConnectionError, ConnectionError, Timeout) as e:
|
166
|
+
session_manager.handle_request_exceptions(e, "uploading trace to presigned URL")
|
167
|
+
return False
|
168
|
+
except RequestException as e:
|
169
|
+
logger.error(f"Error while uploading trace to presigned url: {e}")
|
173
170
|
return False
|
174
171
|
|
175
172
|
def insert_traces(self, presignedUrl):
|
@@ -185,21 +182,18 @@ class UploadAgenticTraces:
|
|
185
182
|
"datasetSpans": self._get_dataset_spans(), # Extra key for agentic traces
|
186
183
|
}
|
187
184
|
)
|
188
|
-
logger.debug(f"Inserting agentic traces to presigned url: {presignedUrl}")
|
189
185
|
try:
|
190
186
|
start_time = time.time()
|
191
187
|
endpoint = f"{self.base_url}/v1/llm/insert/trace"
|
192
|
-
response =
|
188
|
+
response = session_manager.session.request(
|
193
189
|
"POST", endpoint, headers=headers, data=payload, timeout=self.timeout
|
194
190
|
)
|
195
|
-
logger.debug(f"Payload: {payload}")
|
196
|
-
logger.debug(f"Headers: {headers}")
|
197
191
|
elapsed_ms = (time.time() - start_time) * 1000
|
198
192
|
logger.debug(
|
199
193
|
f"API Call: [POST] {endpoint} | Status: {response.status_code} | Time: {elapsed_ms:.2f}ms"
|
200
194
|
)
|
201
195
|
if response.status_code in [200, 201]:
|
202
|
-
logger.
|
196
|
+
logger.info(f"Traces inserted successfully: {response.json()['message']}")
|
203
197
|
return True
|
204
198
|
elif response.status_code == 401:
|
205
199
|
logger.warning("Received 401 error. Attempting to refresh token.")
|
@@ -209,7 +203,7 @@ class UploadAgenticTraces:
|
|
209
203
|
"Content-Type": "application/json",
|
210
204
|
"X-Project-Name": self.project_name,
|
211
205
|
}
|
212
|
-
response =
|
206
|
+
response = session_manager.session.request(
|
213
207
|
"POST",
|
214
208
|
endpoint,
|
215
209
|
headers=headers,
|
@@ -221,24 +215,27 @@ class UploadAgenticTraces:
|
|
221
215
|
f"API Call: [POST] {endpoint} | Status: {response.status_code} | Time: {elapsed_ms:.2f}ms"
|
222
216
|
)
|
223
217
|
if response.status_code in [200, 201]:
|
224
|
-
logger.
|
218
|
+
logger.info(f"Traces inserted successfully: {response.json()['message']}")
|
225
219
|
return True
|
226
220
|
else:
|
227
|
-
logger.
|
221
|
+
logger.error(f"Error while inserting traces after 401: {response.json()['message']}")
|
228
222
|
return False
|
229
223
|
else:
|
230
|
-
logger.
|
224
|
+
logger.error(f"Error while inserting traces: {response.json()['message']}")
|
231
225
|
return False
|
232
|
-
except
|
233
|
-
|
234
|
-
return
|
226
|
+
except (PoolError, MaxRetryError, NewConnectionError, ConnectionError, Timeout) as e:
|
227
|
+
session_manager.handle_request_exceptions(e, "inserting traces")
|
228
|
+
return False
|
229
|
+
except RequestException as e:
|
230
|
+
logger.error(f"Error while inserting traces: {e}")
|
231
|
+
return False
|
235
232
|
|
236
233
|
def _get_dataset_spans(self):
|
237
234
|
try:
|
238
235
|
with open(self.json_file_path) as f:
|
239
236
|
data = json.load(f)
|
240
237
|
except Exception as e:
|
241
|
-
|
238
|
+
print(f"Error while reading file: {e}")
|
242
239
|
return None
|
243
240
|
try:
|
244
241
|
spans = data["data"][0]["spans"]
|
@@ -260,41 +257,41 @@ class UploadAgenticTraces:
|
|
260
257
|
continue
|
261
258
|
return dataset_spans
|
262
259
|
except Exception as e:
|
263
|
-
logger.
|
260
|
+
logger.error(f"Error while reading dataset spans: {e}")
|
264
261
|
return None
|
265
262
|
|
266
263
|
def upload_agentic_traces(self):
|
267
264
|
try:
|
268
265
|
presigned_url = self._get_presigned_url()
|
269
266
|
if presigned_url is None:
|
270
|
-
logger.
|
267
|
+
logger.warning("Warning: Failed to obtain presigned URL")
|
271
268
|
return False
|
272
269
|
|
273
270
|
# Upload the file using the presigned URL
|
274
271
|
upload_result = self._put_presigned_url(presigned_url, self.json_file_path)
|
275
272
|
if not upload_result:
|
276
|
-
logger.
|
273
|
+
logger.error("Error: Failed to upload file to presigned URL")
|
277
274
|
return False
|
278
275
|
elif isinstance(upload_result, tuple):
|
279
276
|
response, status_code = upload_result
|
280
277
|
if status_code not in [200, 201]:
|
281
|
-
logger.
|
282
|
-
f"Error:
|
278
|
+
logger.error(
|
279
|
+
f"Error: Uploading agentic traces failed with status code {status_code}: {response.text if hasattr(response, 'text') else 'Unknown error'}")
|
283
280
|
return False
|
284
281
|
# Insert trace records
|
285
282
|
insert_success = self.insert_traces(presigned_url)
|
286
283
|
if not insert_success:
|
287
|
-
|
284
|
+
print("Error: Failed to insert trace records")
|
288
285
|
return False
|
289
286
|
|
290
|
-
logger.
|
287
|
+
logger.info("Successfully uploaded agentic traces")
|
291
288
|
return True
|
292
289
|
except FileNotFoundError:
|
293
|
-
logger.
|
290
|
+
logger.error(f"Error: Trace file not found at {self.json_file_path}")
|
294
291
|
return False
|
295
292
|
except ConnectionError as e:
|
296
|
-
logger.
|
293
|
+
logger.error(f"Error: Network connection failed while uploading traces: {e}")
|
297
294
|
return False
|
298
295
|
except Exception as e:
|
299
|
-
logger.
|
296
|
+
logger.error(f"Error while uploading agentic traces: {e}")
|
300
297
|
return False
|
@@ -1,15 +1,18 @@
|
|
1
|
-
import json
|
2
1
|
import logging
|
3
2
|
import os
|
4
3
|
import time
|
4
|
+
import re
|
5
|
+
import json
|
6
|
+
from urllib.parse import urlparse, urlunparse
|
7
|
+
from urllib3.exceptions import PoolError, MaxRetryError, NewConnectionError
|
8
|
+
from requests.exceptions import ConnectionError, Timeout, RequestException
|
5
9
|
|
6
10
|
import requests
|
7
11
|
|
8
12
|
from ragaai_catalyst.ragaai_catalyst import RagaAICatalyst
|
13
|
+
from .session_manager import session_manager
|
9
14
|
|
10
15
|
logger = logging.getLogger(__name__)
|
11
|
-
import re
|
12
|
-
from urllib.parse import urlparse, urlunparse
|
13
16
|
|
14
17
|
|
15
18
|
def upload_code(
|
@@ -19,11 +22,26 @@ def upload_code(
|
|
19
22
|
project_name, dataset_name, base_url, timeout=timeout
|
20
23
|
)
|
21
24
|
|
25
|
+
# Handle None case during exceptions - do not proceed
|
26
|
+
if code_hashes_list is None:
|
27
|
+
logger.error("Failed to fetch existing code hashes, cannot proceed with upload")
|
28
|
+
return None
|
29
|
+
|
22
30
|
if hash_id not in code_hashes_list:
|
23
31
|
presigned_url = _fetch_presigned_url(
|
24
32
|
project_name, dataset_name, base_url, timeout=timeout
|
25
33
|
)
|
26
|
-
|
34
|
+
# Handle None case for presigned URL
|
35
|
+
if presigned_url is None:
|
36
|
+
logger.error("Failed to fetch presigned URL, cannot proceed with upload")
|
37
|
+
return None
|
38
|
+
|
39
|
+
upload_result = _put_zip_presigned_url(project_name, presigned_url, zip_path, timeout=timeout)
|
40
|
+
|
41
|
+
# Handle upload failure
|
42
|
+
if upload_result is False or (isinstance(upload_result, tuple) and upload_result[1] not in [200, 201]):
|
43
|
+
logger.error("Failed to upload zip file")
|
44
|
+
return None
|
27
45
|
|
28
46
|
response = _insert_code(
|
29
47
|
dataset_name,
|
@@ -33,6 +51,10 @@ def upload_code(
|
|
33
51
|
base_url,
|
34
52
|
timeout=timeout,
|
35
53
|
)
|
54
|
+
# Handle None response from insert_code
|
55
|
+
if response is None:
|
56
|
+
logger.error("Failed to insert code metadata")
|
57
|
+
return None
|
36
58
|
return response
|
37
59
|
else:
|
38
60
|
return "Code already exists"
|
@@ -49,7 +71,7 @@ def _fetch_dataset_code_hashes(project_name, dataset_name, base_url=None, timeou
|
|
49
71
|
url_base = base_url if base_url is not None else RagaAICatalyst.BASE_URL
|
50
72
|
start_time = time.time()
|
51
73
|
endpoint = f"{url_base}/v2/llm/dataset/code?datasetName={dataset_name}"
|
52
|
-
response =
|
74
|
+
response = session_manager.session.request(
|
53
75
|
"GET", endpoint, headers=headers, data=payload, timeout=timeout
|
54
76
|
)
|
55
77
|
elapsed_ms = (time.time() - start_time) * 1000
|
@@ -57,7 +79,7 @@ def _fetch_dataset_code_hashes(project_name, dataset_name, base_url=None, timeou
|
|
57
79
|
f"API Call: [GET] {endpoint} | Status: {response.status_code} | Time: {elapsed_ms:.2f}ms"
|
58
80
|
)
|
59
81
|
|
60
|
-
if response.status_code
|
82
|
+
if response.status_code in [200, 201]:
|
61
83
|
return response.json()["data"]["codeHashes"]
|
62
84
|
elif response.status_code == 401:
|
63
85
|
logger.warning("Received 401 error. Attempting to refresh token.")
|
@@ -66,22 +88,25 @@ def _fetch_dataset_code_hashes(project_name, dataset_name, base_url=None, timeou
|
|
66
88
|
"Authorization": f"Bearer {os.getenv('RAGAAI_CATALYST_TOKEN')}",
|
67
89
|
"X-Project-Name": project_name,
|
68
90
|
}
|
69
|
-
response =
|
91
|
+
response = session_manager.session.request(
|
70
92
|
"GET", endpoint, headers=headers, data=payload, timeout=timeout
|
71
93
|
)
|
72
94
|
elapsed_ms = (time.time() - start_time) * 1000
|
73
|
-
logger.debug(
|
74
|
-
|
75
|
-
)
|
76
|
-
if response.status_code == 200:
|
95
|
+
logger.debug(f"API Call: [GET] {endpoint} | Status: {response.status_code} | Time: {elapsed_ms:.2f}ms")
|
96
|
+
if response.status_code in [200, 201]:
|
77
97
|
return response.json()["data"]["codeHashes"]
|
78
98
|
else:
|
79
|
-
logger.error(
|
80
|
-
|
81
|
-
|
82
|
-
|
99
|
+
logger.error(f"Failed to fetch code hashes: {response.json()['message']}")
|
100
|
+
return None
|
101
|
+
else:
|
102
|
+
logger.error(f"Error while fetching dataset code hashes: {response.json()['message']}")
|
103
|
+
return None
|
104
|
+
except (PoolError, MaxRetryError, NewConnectionError, ConnectionError, Timeout) as e:
|
105
|
+
session_manager.handle_request_exceptions(e, "fetching dataset code hashes")
|
106
|
+
return None
|
107
|
+
except RequestException as e:
|
83
108
|
logger.error(f"Failed to list datasets: {e}")
|
84
|
-
|
109
|
+
return None
|
85
110
|
|
86
111
|
|
87
112
|
def update_presigned_url(presigned_url, base_url):
|
@@ -156,7 +181,7 @@ def _fetch_presigned_url(project_name, dataset_name, base_url=None, timeout=120)
|
|
156
181
|
logger.debug(
|
157
182
|
f"API Call: [POST] {endpoint} | Status: {response.status_code} | Time: {elapsed_ms:.2f}ms"
|
158
183
|
)
|
159
|
-
if response.status_code
|
184
|
+
if response.status_code in [200, 201]:
|
160
185
|
presigned_url = response.json()["data"]["presignedUrls"][0]
|
161
186
|
presigned_url = update_presigned_url(presigned_url, url_base)
|
162
187
|
return presigned_url
|
@@ -168,9 +193,10 @@ def _fetch_presigned_url(project_name, dataset_name, base_url=None, timeout=120)
|
|
168
193
|
logger.error(
|
169
194
|
f"Failed to fetch code hashes: {response.json()['message']}"
|
170
195
|
)
|
196
|
+
return None
|
171
197
|
except requests.exceptions.RequestException as e:
|
172
198
|
logger.error(f"Failed to list datasets: {e}")
|
173
|
-
|
199
|
+
return None
|
174
200
|
|
175
201
|
|
176
202
|
def _put_zip_presigned_url(project_name, presignedUrl, filename, timeout=120):
|
@@ -181,21 +207,28 @@ def _put_zip_presigned_url(project_name, presignedUrl, filename, timeout=120):
|
|
181
207
|
|
182
208
|
if "blob.core.windows.net" in presignedUrl: # Azure
|
183
209
|
headers["x-ms-blob-type"] = "BlockBlob"
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
start_time = time.time()
|
189
|
-
response = requests.request(
|
190
|
-
"PUT", presignedUrl, headers=headers, data=payload, timeout=timeout
|
191
|
-
)
|
192
|
-
elapsed_ms = (time.time() - start_time) * 1000
|
193
|
-
logger.debug(
|
194
|
-
f"API Call: [PUT] {presignedUrl} | Status: {response.status_code} | Time: {elapsed_ms:.2f}ms"
|
195
|
-
)
|
196
|
-
if response.status_code != 200 or response.status_code != 201:
|
197
|
-
return response, response.status_code
|
210
|
+
logger.info("Uploading code to presigned URL...")
|
211
|
+
try:
|
212
|
+
with open(filename, "rb") as f:
|
213
|
+
payload = f.read()
|
198
214
|
|
215
|
+
start_time = time.time()
|
216
|
+
response = session_manager.session.request(
|
217
|
+
"PUT", presignedUrl, headers=headers, data=payload, timeout=timeout
|
218
|
+
)
|
219
|
+
elapsed_ms = (time.time() - start_time) * 1000
|
220
|
+
logger.debug(
|
221
|
+
f"API Call: [PUT] {presignedUrl} | Status: {response.status_code} | Time: {elapsed_ms:.2f}ms"
|
222
|
+
)
|
223
|
+
if response.status_code not in [200, 201]:
|
224
|
+
return response, response.status_code
|
225
|
+
return True
|
226
|
+
except (PoolError, MaxRetryError, NewConnectionError, ConnectionError, Timeout) as e:
|
227
|
+
session_manager.handle_request_exceptions(e, "uploading zip to presigned URL")
|
228
|
+
return False
|
229
|
+
except RequestException as e:
|
230
|
+
logger.error(f"Failed to upload zip: {e}")
|
231
|
+
return False
|
199
232
|
|
200
233
|
def _insert_code(
|
201
234
|
dataset_name, hash_id, presigned_url, project_name, base_url=None, timeout=120
|
@@ -218,39 +251,43 @@ def _insert_code(
|
|
218
251
|
url_base = base_url if base_url is not None else RagaAICatalyst.BASE_URL
|
219
252
|
start_time = time.time()
|
220
253
|
endpoint = f"{url_base}/v2/llm/dataset/code"
|
221
|
-
response =
|
254
|
+
response = session_manager.session.request(
|
222
255
|
"POST", endpoint, headers=headers, data=payload, timeout=timeout
|
223
256
|
)
|
224
257
|
elapsed_ms = (time.time() - start_time) * 1000
|
225
258
|
logger.debug(
|
226
259
|
f"API Call: [POST] {endpoint} | Status: {response.status_code} | Time: {elapsed_ms:.2f}ms"
|
227
260
|
)
|
228
|
-
if response.status_code
|
261
|
+
if response.status_code in [200, 201]:
|
229
262
|
return response.json()["message"]
|
230
263
|
|
231
264
|
elif response.status_code == 401:
|
232
|
-
logger.warning("Received 401 error. Attempting to refresh token.")
|
265
|
+
logger.warning("Received 401 error during inserting code. Attempting to refresh token.")
|
233
266
|
token = RagaAICatalyst.get_token(force_refresh=True)
|
234
267
|
headers = {
|
235
268
|
"X-Project-Name": project_name,
|
236
269
|
"Content-Type": "application/json",
|
237
270
|
"Authorization": f"Bearer {token}",
|
238
271
|
}
|
239
|
-
response =
|
272
|
+
response = session_manager.session.request(
|
240
273
|
"POST", endpoint, headers=headers, data=payload, timeout=timeout
|
241
274
|
)
|
242
275
|
elapsed_ms = (time.time() - start_time) * 1000
|
243
276
|
logger.debug(
|
244
277
|
f"API Call: [POST] {endpoint} | Status: {response.status_code} | Time: {elapsed_ms:.2f}ms"
|
245
278
|
)
|
246
|
-
if response.status_code
|
279
|
+
if response.status_code in [200, 201]:
|
280
|
+
logger.info(f"Code inserted successfully after 401: {response.json()['message']}")
|
247
281
|
return response.json()["message"]
|
248
282
|
else:
|
249
|
-
logger.error(f"Failed to insert code: {response.json()['message']}")
|
250
|
-
|
283
|
+
logger.error(f"Failed to insert code after 401: {response.json()['message']}")
|
284
|
+
return None
|
251
285
|
else:
|
252
286
|
logger.error(f"Failed to insert code: {response.json()['message']}")
|
253
|
-
|
254
|
-
except
|
287
|
+
return None
|
288
|
+
except (PoolError, MaxRetryError, NewConnectionError, ConnectionError, Timeout) as e:
|
289
|
+
session_manager.handle_request_exceptions(e, "inserting code")
|
290
|
+
return None
|
291
|
+
except RequestException as e:
|
255
292
|
logger.error(f"Failed to insert code: {e}")
|
256
|
-
|
293
|
+
return None
|
@@ -19,7 +19,7 @@ from ragaai_catalyst.tracers.agentic_tracing.utils.zip_list_of_unique_files impo
|
|
19
19
|
)
|
20
20
|
from ragaai_catalyst.tracers.utils.trace_json_converter import convert_json_format
|
21
21
|
|
22
|
-
logger = logging.getLogger(
|
22
|
+
logger = logging.getLogger("RagaAICatalyst")
|
23
23
|
logging_level = (
|
24
24
|
logger.setLevel(logging.DEBUG) if os.getenv("DEBUG") == "1" else logging.INFO
|
25
25
|
)
|
@@ -46,7 +46,6 @@ class RAGATraceExporter(SpanExporter):
|
|
46
46
|
self.external_id = external_id
|
47
47
|
|
48
48
|
def export(self, spans):
|
49
|
-
logger.debug("Starting export of span: ")
|
50
49
|
for span in spans:
|
51
50
|
try:
|
52
51
|
span_json = json.loads(span.to_json())
|
@@ -61,11 +60,8 @@ class RAGATraceExporter(SpanExporter):
|
|
61
60
|
|
62
61
|
if span_json["parent_id"] is None:
|
63
62
|
trace = self.trace_spans[trace_id]
|
64
|
-
logger.debug("End of trace found: ")
|
65
63
|
try:
|
66
|
-
logger.debug("Started processing complete trace: ")
|
67
64
|
self.process_complete_trace(trace, trace_id)
|
68
|
-
logger.debug("Completed processing complete trace: ")
|
69
65
|
except Exception as e:
|
70
66
|
logger.error(f"Error processing complete trace: {e}")
|
71
67
|
try:
|
@@ -88,11 +84,9 @@ class RAGATraceExporter(SpanExporter):
|
|
88
84
|
def process_complete_trace(self, spans, trace_id):
|
89
85
|
# Convert the trace to ragaai trace format
|
90
86
|
try:
|
91
|
-
logger.debug("Started preparing trace to trace format: ")
|
92
87
|
ragaai_trace_details = self.prepare_trace(spans, trace_id)
|
93
|
-
logger.debug("Completed preparing trace to trace format: ")
|
94
88
|
except Exception as e:
|
95
|
-
|
89
|
+
print(f"Error converting trace {trace_id}: {e}")
|
96
90
|
return # Exit early if conversion fails
|
97
91
|
|
98
92
|
# Check if trace details are None (conversion failed)
|
@@ -102,118 +96,98 @@ class RAGATraceExporter(SpanExporter):
|
|
102
96
|
|
103
97
|
# Upload the trace if upload_trace function is provided
|
104
98
|
try:
|
105
|
-
logger.debug("Started uploading trace: ")
|
106
99
|
if self.post_processor!=None:
|
107
100
|
ragaai_trace_details['trace_file_path'] = self.post_processor(ragaai_trace_details['trace_file_path'])
|
108
101
|
self.upload_trace(ragaai_trace_details, trace_id)
|
109
|
-
logger.debug("Completed uploading trace: ")
|
110
102
|
except Exception as e:
|
111
|
-
|
103
|
+
print(f"Error uploading trace {trace_id}: {e}")
|
112
104
|
|
113
105
|
def prepare_trace(self, spans, trace_id):
|
114
106
|
try:
|
115
107
|
try:
|
116
|
-
logger.debug("Started converting trace to trace format: ")
|
117
108
|
ragaai_trace = convert_json_format(spans, self.custom_model_cost, self.user_context, self.user_gt,self.external_id)
|
118
|
-
logger.debug("Completed converting trace to trace format: ")
|
119
109
|
except Exception as e:
|
120
|
-
|
110
|
+
print(f"Error in convert_json_format function: {trace_id}: {e}")
|
121
111
|
return None
|
122
112
|
|
123
113
|
try:
|
124
|
-
logger.debug("Started formatting interactions: ")
|
125
114
|
interactions = format_interactions(ragaai_trace)
|
126
115
|
ragaai_trace["workflow"] = interactions['workflow']
|
127
|
-
logger.debug("Completed formatting interactions: ")
|
128
116
|
except Exception as e:
|
129
|
-
|
117
|
+
print(f"Error in format_interactions function: {trace_id}: {e}")
|
130
118
|
return None
|
131
119
|
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
# logger.error(f"Error in zip_list_of_unique_files function: {trace_id}: {e}")
|
141
|
-
# return None
|
120
|
+
try:
|
121
|
+
# Add source code hash
|
122
|
+
hash_id, zip_path = zip_list_of_unique_files(
|
123
|
+
self.files_to_zip, output_dir=self.tmp_dir
|
124
|
+
)
|
125
|
+
except Exception as e:
|
126
|
+
print(f"Error in zip_list_of_unique_files function: {trace_id}: {e}")
|
127
|
+
return None
|
142
128
|
|
143
129
|
try:
|
144
|
-
logger.debug("Started adding system info: ")
|
145
130
|
ragaai_trace["metadata"]["system_info"] = asdict(self.system_monitor.get_system_info())
|
146
131
|
ragaai_trace["metadata"]["resources"] = asdict(self.system_monitor.get_resources())
|
147
|
-
logger.debug("Completed adding system info: ")
|
148
132
|
except Exception as e:
|
149
|
-
|
133
|
+
print(f"Error in get_system_info or get_resources function: {trace_id}: {e}")
|
150
134
|
return None
|
151
135
|
|
152
136
|
try:
|
153
|
-
|
154
|
-
ragaai_trace["metadata"]["system_info"]["source_code"] = ""
|
155
|
-
logger.debug("Completed adding source code hash: ")
|
137
|
+
ragaai_trace["metadata"]["system_info"]["source_code"] = hash_id
|
156
138
|
except Exception as e:
|
157
|
-
|
139
|
+
print(f"Error in adding source code hash: {trace_id}: {e}")
|
158
140
|
return None
|
159
141
|
|
160
142
|
try:
|
161
143
|
ragaai_trace["data"][0]["start_time"] = ragaai_trace["start_time"]
|
162
144
|
ragaai_trace["data"][0]["end_time"] = ragaai_trace["end_time"]
|
163
145
|
except Exception as e:
|
164
|
-
|
146
|
+
print(f"Error in adding start_time or end_time: {trace_id}: {e}")
|
165
147
|
return None
|
166
148
|
|
167
149
|
try:
|
168
|
-
logger.debug("Started adding project name: ")
|
169
150
|
ragaai_trace["project_name"] = self.project_name
|
170
|
-
logger.debug("Completed adding project name: ")
|
171
151
|
except Exception as e:
|
172
|
-
|
152
|
+
print(f"Error in adding project name: {trace_id}: {e}")
|
173
153
|
return None
|
174
154
|
|
175
155
|
try:
|
176
|
-
logger.debug("Started adding tracer type: ")
|
177
156
|
# Add tracer type to the trace
|
178
157
|
ragaai_trace["tracer_type"] = self.tracer_type
|
179
|
-
logger.debug("Completed adding tracer type: ")
|
180
158
|
except Exception as e:
|
181
|
-
|
159
|
+
print(f"Error in adding tracer type: {trace_id}: {e}")
|
182
160
|
return None
|
183
161
|
|
184
162
|
#Add user passed metadata to the trace
|
185
163
|
try:
|
186
|
-
logger.debug("Started adding user passed metadata: ")
|
187
164
|
if self.user_details.get("trace_user_detail").get("metadata") and isinstance(self.user_details.get("trace_user_detail").get("metadata"), dict):
|
188
165
|
for key, value in self.user_details.get("trace_user_detail").get("metadata").items():
|
189
166
|
if key in ["log_source", "recorded_on"]:
|
190
167
|
continue
|
191
168
|
ragaai_trace["metadata"][key] = value
|
192
|
-
logger.debug("Completed adding user passed metadata: ")
|
193
169
|
except Exception as e:
|
194
|
-
|
170
|
+
print(f"Error in adding metadata: {trace_id}: {e}")
|
195
171
|
return None
|
196
172
|
|
197
173
|
try:
|
198
|
-
logger.debug("Started saving trace json: ")
|
199
174
|
# Save the trace_json
|
200
175
|
trace_file_path = os.path.join(self.tmp_dir, f"{trace_id}.json")
|
201
176
|
with open(trace_file_path, "w") as file:
|
202
177
|
json.dump(ragaai_trace, file, cls=TracerJSONEncoder, indent=2)
|
203
178
|
with open(os.path.join(os.getcwd(), 'rag_agent_traces.json'), 'w') as f:
|
204
179
|
json.dump(ragaai_trace, f, cls=TracerJSONEncoder, indent=2)
|
205
|
-
logger.debug("Completed saving trace json: ")
|
206
180
|
except Exception as e:
|
207
|
-
|
181
|
+
print(f"Error in saving trace json: {trace_id}: {e}")
|
208
182
|
return None
|
209
183
|
|
210
184
|
return {
|
211
185
|
'trace_file_path': trace_file_path,
|
212
|
-
'code_zip_path':
|
213
|
-
'hash_id':
|
186
|
+
'code_zip_path': zip_path,
|
187
|
+
'hash_id': hash_id
|
214
188
|
}
|
215
189
|
except Exception as e:
|
216
|
-
|
190
|
+
print(f"Error converting trace {trace_id}: {str(e)}")
|
217
191
|
return None
|
218
192
|
|
219
193
|
def upload_trace(self, ragaai_trace_details, trace_id):
|
@@ -229,6 +203,7 @@ class RAGATraceExporter(SpanExporter):
|
|
229
203
|
dataset_name=self.dataset_name,
|
230
204
|
user_details=self.user_details,
|
231
205
|
base_url=self.base_url,
|
206
|
+
tracer_type=self.tracer_type,
|
232
207
|
timeout=self.timeout
|
233
208
|
)
|
234
209
|
|
@@ -127,11 +127,9 @@ class Tracer(AgenticTracing):
|
|
127
127
|
self.model_custom_cost = {}
|
128
128
|
super().__init__(user_detail=user_detail, auto_instrumentation=auto_instrumentation)
|
129
129
|
|
130
|
-
logger.debug(f"Setting up Tracer instance with project: {project_name}, dataset: {dataset_name}")
|
131
130
|
self.project_name = project_name
|
132
131
|
self.dataset_name = dataset_name
|
133
132
|
self.tracer_type = tracer_type
|
134
|
-
logger.debug(f"Tracer type set to: {tracer_type}")
|
135
133
|
self.metadata = self._improve_metadata(metadata, tracer_type)
|
136
134
|
# self.metadata["total_cost"] = 0.0
|
137
135
|
# self.metadata["total_tokens"] = 0
|
@@ -148,16 +146,12 @@ class Tracer(AgenticTracing):
|
|
148
146
|
self.file_tracker = TrackName()
|
149
147
|
self.post_processor = None
|
150
148
|
self.max_upload_workers = max_upload_workers
|
151
|
-
logger.debug(f"Max upload workers: {self.max_upload_workers}")
|
152
149
|
self.user_details = self._pass_user_data()
|
153
150
|
self.update_llm_cost = update_llm_cost
|
154
151
|
self.auto_instrumentation = auto_instrumentation
|
155
152
|
self.external_id = external_id
|
156
|
-
if external_id:
|
157
|
-
logger.debug(f"External ID provided: {external_id}")
|
158
153
|
|
159
154
|
try:
|
160
|
-
logger.debug(f"Fetching projects list from {self.base_url}/v2/llm/projects")
|
161
155
|
response = requests.get(
|
162
156
|
f"{self.base_url}/v2/llm/projects?size={self.num_projects}",
|
163
157
|
headers={
|
@@ -171,13 +165,8 @@ class Tracer(AgenticTracing):
|
|
171
165
|
project_list = [
|
172
166
|
project["name"] for project in response.json()["data"]["content"]
|
173
167
|
]
|
174
|
-
logger.debug(f"Found {len(project_list)} projects")
|
175
168
|
if project_name not in project_list:
|
176
|
-
logger.
|
177
|
-
logger.debug(f"Available projects: {project_list}")
|
178
|
-
else:
|
179
|
-
logger.debug(f"Project '{project_name}' found in available projects")
|
180
|
-
|
169
|
+
logger.error("Project not found. Please enter a valid project name")
|
181
170
|
|
182
171
|
self.project_id = [
|
183
172
|
project["id"] for project in response.json()["data"]["content"] if project["name"] == project_name
|
@@ -188,7 +177,6 @@ class Tracer(AgenticTracing):
|
|
188
177
|
|
189
178
|
except requests.exceptions.RequestException as e:
|
190
179
|
logger.error(f"Failed to retrieve projects list: {e}")
|
191
|
-
logger.debug(f"Request exception details: {str(e)}, URL: {self.base_url}/v2/llm/projects")
|
192
180
|
|
193
181
|
# if tracer_type == "langchain":
|
194
182
|
# instrumentors = []
|
@@ -203,16 +191,13 @@ class Tracer(AgenticTracing):
|
|
203
191
|
# from openinference.instrumentation.langchain import LangChainInstrumentor
|
204
192
|
# instrumentors += [(LangChainInstrumentor, [])]
|
205
193
|
# self._setup_agentic_tracer(instrumentors)
|
206
|
-
|
207
194
|
# Handle agentic tracers
|
208
|
-
logger.debug(f"Starting Instrumentation for tracer type: {tracer_type}")
|
209
195
|
if tracer_type == "agentic" or tracer_type.startswith("agentic/") or tracer_type == "langchain":
|
210
196
|
# Setup instrumentors based on tracer type
|
211
197
|
instrumentors = []
|
212
198
|
|
213
199
|
# Add LLM Instrumentors
|
214
200
|
if tracer_type in ['agentic/crewai']:
|
215
|
-
logger.debug("Setting up instrumentors for CrewAI")
|
216
201
|
try:
|
217
202
|
from openinference.instrumentation.vertexai import VertexAIInstrumentor
|
218
203
|
instrumentors.append((VertexAIInstrumentor, []))
|
@@ -325,38 +310,31 @@ class Tracer(AgenticTracing):
|
|
325
310
|
elif tracer_type == "agentic/llamaindex" or tracer_type == "llamaindex":
|
326
311
|
from openinference.instrumentation.llama_index import LlamaIndexInstrumentor
|
327
312
|
instrumentors += [(LlamaIndexInstrumentor, [])]
|
328
|
-
logger.info("Instrumenting LlamaIndex...")
|
329
313
|
|
330
314
|
elif tracer_type == "agentic/langchain" or tracer_type == "agentic/langgraph" or tracer_type == "langchain":
|
331
315
|
from openinference.instrumentation.langchain import LangChainInstrumentor
|
332
316
|
instrumentors += [(LangChainInstrumentor, [])]
|
333
|
-
logger.info("Instrumenting LangChain...")
|
334
317
|
|
335
318
|
elif tracer_type == "agentic/crewai":
|
336
319
|
from openinference.instrumentation.crewai import CrewAIInstrumentor
|
337
320
|
from openinference.instrumentation.langchain import LangChainInstrumentor
|
338
321
|
instrumentors += [(CrewAIInstrumentor, []), (LangChainInstrumentor, [])]
|
339
|
-
logger.info("Instrumenting CrewAI...")
|
340
322
|
|
341
323
|
elif tracer_type == "agentic/haystack":
|
342
324
|
from openinference.instrumentation.haystack import HaystackInstrumentor
|
343
325
|
instrumentors += [(HaystackInstrumentor, [])]
|
344
|
-
logger.info("Instrumenting Haystack...")
|
345
326
|
|
346
327
|
elif tracer_type == "agentic/autogen":
|
347
328
|
from openinference.instrumentation.autogen import AutogenInstrumentor
|
348
329
|
instrumentors += [(AutogenInstrumentor, [])]
|
349
|
-
logger.info("Instrumenting Autogen...")
|
350
330
|
|
351
331
|
elif tracer_type == "agentic/smolagents":
|
352
332
|
from openinference.instrumentation.smolagents import SmolagentsInstrumentor
|
353
333
|
instrumentors += [(SmolagentsInstrumentor, [])]
|
354
|
-
logger.info("Instrumenting Smolagents...")
|
355
334
|
|
356
335
|
elif tracer_type == "agentic/openai_agents":
|
357
336
|
from openinference.instrumentation.openai_agents import OpenAIAgentsInstrumentor
|
358
337
|
instrumentors += [(OpenAIAgentsInstrumentor, [])]
|
359
|
-
logger.info("Instrumenting OpenAI Agents...")
|
360
338
|
|
361
339
|
else:
|
362
340
|
# Unknown agentic tracer type
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: ragaai_catalyst
|
3
|
-
Version: 2.2.4.
|
3
|
+
Version: 2.2.4.1b5
|
4
4
|
Summary: RAGA AI CATALYST
|
5
5
|
Author-email: Kiran Scaria <kiran.scaria@raga.ai>, Kedar Gaikwad <kedar.gaikwad@raga.ai>, Dushyant Mahajan <dushyant.mahajan@raga.ai>, Siddhartha Kosti <siddhartha.kosti@raga.ai>, Ritika Goel <ritika.goel@raga.ai>, Vijay Chaurasia <vijay.chaurasia@raga.ai>, Tushar Kumar <tushar.kumar@raga.ai>, Rishabh Pandey <rishabh.pandey@raga.ai>, Jyotsana C G <jyotsana@raga.ai>
|
6
6
|
Requires-Python: <=3.13.2,>=3.10
|
@@ -31,7 +31,7 @@ ragaai_catalyst/tracers/distributed.py,sha256=CGPuOh4CsgEk428PPibieLaAG2Tt3BVygF
|
|
31
31
|
ragaai_catalyst/tracers/langchain_callback.py,sha256=CB75zzG3-DkYTELj0vI1MOHQTY0MuQJfoHIXz9Cl8S8,34568
|
32
32
|
ragaai_catalyst/tracers/llamaindex_callback.py,sha256=ZY0BJrrlz-P9Mg2dX-ZkVKG3gSvzwqBtk7JL_05MiYA,14028
|
33
33
|
ragaai_catalyst/tracers/llamaindex_instrumentation.py,sha256=Ys_jLkvVqo12bKgXDmkp4TxJu9HkBATrFE8cIcTYxWw,14329
|
34
|
-
ragaai_catalyst/tracers/tracer.py,sha256=
|
34
|
+
ragaai_catalyst/tracers/tracer.py,sha256=hxVJN45CtIeU8Dc5G1kreXJa7Vv_3buBAHVz-Q3buKo,41435
|
35
35
|
ragaai_catalyst/tracers/upload_traces.py,sha256=w1clGGfdOMpStUJX40NAlxe6dcFdN4pwcezyII0bGYA,6994
|
36
36
|
ragaai_catalyst/tracers/agentic_tracing/README.md,sha256=X4QwLb7-Jg7GQMIXj-SerZIgDETfw-7VgYlczOR8ZeQ,4508
|
37
37
|
ragaai_catalyst/tracers/agentic_tracing/__init__.py,sha256=yf6SKvOPSpH-9LiKaoLKXwqj5sez8F_5wkOb91yp0oE,260
|
@@ -54,9 +54,10 @@ ragaai_catalyst/tracers/agentic_tracing/tracers/network_tracer.py,sha256=m8CxYkl
|
|
54
54
|
ragaai_catalyst/tracers/agentic_tracing/tracers/tool_tracer.py,sha256=xxrliKPfdfbIZRZqMnUewsaTD8_Hv0dbuoBivNZGD4U,21674
|
55
55
|
ragaai_catalyst/tracers/agentic_tracing/tracers/user_interaction_tracer.py,sha256=bhSUhNQCuJXKjgJAXhjKEYjnHMpYN90FSZdR84fNIKU,4614
|
56
56
|
ragaai_catalyst/tracers/agentic_tracing/upload/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
57
|
-
ragaai_catalyst/tracers/agentic_tracing/upload/
|
58
|
-
ragaai_catalyst/tracers/agentic_tracing/upload/
|
59
|
-
ragaai_catalyst/tracers/agentic_tracing/upload/
|
57
|
+
ragaai_catalyst/tracers/agentic_tracing/upload/session_manager.py,sha256=xgheT_XV2PFov709V0J5DwytW9-muvZnPTjbMsurGAw,5335
|
58
|
+
ragaai_catalyst/tracers/agentic_tracing/upload/trace_uploader.py,sha256=Ujbu0KDl7oDr-cFtLwrQK_i7ghMuPV92mFnRfobJ1aI,24822
|
59
|
+
ragaai_catalyst/tracers/agentic_tracing/upload/upload_agentic_traces.py,sha256=vH9at3012iNrNIA30TMr7qLyvWtKyZn9wpd5esmBg0A,12866
|
60
|
+
ragaai_catalyst/tracers/agentic_tracing/upload/upload_code.py,sha256=bpzL-eNCUaqXimSg7nl5YB0KlHbS_2sNvJTfKnfRjek,12027
|
60
61
|
ragaai_catalyst/tracers/agentic_tracing/upload/upload_local_metric.py,sha256=m1O8lKpxKwtHofXLW3fTHX5yfqDW5GxoveARlg5cTw4,2571
|
61
62
|
ragaai_catalyst/tracers/agentic_tracing/utils/__init__.py,sha256=XdB3X_ufe4RVvGorxSqAiB9dYv4UD7Hvvuw3bsDUppY,60
|
62
63
|
ragaai_catalyst/tracers/agentic_tracing/utils/api_utils.py,sha256=ZduFA7MmTnWfQ2FzSD0hxMAAfNNTgBs4CXcHZdXJv6k,749
|
@@ -76,7 +77,7 @@ ragaai_catalyst/tracers/exporters/__init__.py,sha256=wQbaqyeIjVZxYprHCKZ9BeiqxeX
|
|
76
77
|
ragaai_catalyst/tracers/exporters/dynamic_trace_exporter.py,sha256=Rm-QaLv1qMAKpHKcFOcK_HWaKHwFBoUH45_4QYipE-g,6843
|
77
78
|
ragaai_catalyst/tracers/exporters/file_span_exporter.py,sha256=NZsD3rShUiC3rO9y3Y2vqEtS3MO51FXZy0p3q9cdDNY,6403
|
78
79
|
ragaai_catalyst/tracers/exporters/raga_exporter.py,sha256=l-RfysTIXYxtvYkVlJbRvg-AzJbT4Fdb-YiZh0mfuDs,17868
|
79
|
-
ragaai_catalyst/tracers/exporters/ragaai_trace_exporter.py,sha256=
|
80
|
+
ragaai_catalyst/tracers/exporters/ragaai_trace_exporter.py,sha256=VxO96ldBpG5mCncrN5mXErIZMlxQ1ewhNoMLfCrzegM,9025
|
80
81
|
ragaai_catalyst/tracers/instrumentators/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
81
82
|
ragaai_catalyst/tracers/utils/__init__.py,sha256=KeMaZtYaTojilpLv65qH08QmpYclfpacDA0U3wg6Ybw,64
|
82
83
|
ragaai_catalyst/tracers/utils/convert_langchain_callbacks_output.py,sha256=SehrD7q8ytAiUYoWr406b4mWs3Lk0Rcy6Ekkihh22TI,1703
|
@@ -88,8 +89,8 @@ ragaai_catalyst/tracers/utils/rag_extraction_logic_final.py,sha256=3ygkRT__lLDRf
|
|
88
89
|
ragaai_catalyst/tracers/utils/rag_trace_json_converter.py,sha256=54IEZO-YRjUAahV5nw8KClXqTF1LhfDry_TsZ4KGow4,20467
|
89
90
|
ragaai_catalyst/tracers/utils/trace_json_converter.py,sha256=-HZVmijeUFLO7e9OAvi1RJdWVTxPRUHPd1MkKQlCD54,11785
|
90
91
|
ragaai_catalyst/tracers/utils/utils.py,sha256=o-p9n2ZuophdrV0wrixu-BqRHCkovup_klc3mS8mU8g,2374
|
91
|
-
ragaai_catalyst-2.2.4.
|
92
|
-
ragaai_catalyst-2.2.4.
|
93
|
-
ragaai_catalyst-2.2.4.
|
94
|
-
ragaai_catalyst-2.2.4.
|
95
|
-
ragaai_catalyst-2.2.4.
|
92
|
+
ragaai_catalyst-2.2.4.1b5.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
93
|
+
ragaai_catalyst-2.2.4.1b5.dist-info/METADATA,sha256=aZAvm_cDpbl_xbOO6d9Lp2kMLmRmdiViDe6EIWDufaI,17681
|
94
|
+
ragaai_catalyst-2.2.4.1b5.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
95
|
+
ragaai_catalyst-2.2.4.1b5.dist-info/top_level.txt,sha256=HpgsdRgEJMk8nqrU6qdCYk3di7MJkDL0B19lkc7dLfM,16
|
96
|
+
ragaai_catalyst-2.2.4.1b5.dist-info/RECORD,,
|
File without changes
|
{ragaai_catalyst-2.2.4.1b4.dist-info → ragaai_catalyst-2.2.4.1b5.dist-info}/licenses/LICENSE
RENAMED
File without changes
|
File without changes
|