trodo-python 2.10.4__tar.gz → 2.10.6__tar.gz
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.
- {trodo_python-2.10.4 → trodo_python-2.10.6}/PKG-INFO +1 -1
- {trodo_python-2.10.4 → trodo_python-2.10.6}/pyproject.toml +1 -1
- {trodo_python-2.10.4 → trodo_python-2.10.6}/trodo/__init__.py +1 -1
- {trodo_python-2.10.4 → trodo_python-2.10.6}/trodo/api/http_client.py +18 -0
- {trodo_python-2.10.4 → trodo_python-2.10.6}/trodo/otel/auto_instrument.py +40 -3
- {trodo_python-2.10.4 → trodo_python-2.10.6}/trodo_python.egg-info/PKG-INFO +1 -1
- {trodo_python-2.10.4 → trodo_python-2.10.6}/README.md +0 -0
- {trodo_python-2.10.4 → trodo_python-2.10.6}/setup.cfg +0 -0
- {trodo_python-2.10.4 → trodo_python-2.10.6}/tests/test_anon_distinct_id 2.py +0 -0
- {trodo_python-2.10.4 → trodo_python-2.10.6}/tests/test_anon_distinct_id.py +0 -0
- {trodo_python-2.10.4 → trodo_python-2.10.6}/tests/test_auto_instrument_fixes.py +0 -0
- {trodo_python-2.10.4 → trodo_python-2.10.6}/tests/test_cross_process_session.py +0 -0
- {trodo_python-2.10.4 → trodo_python-2.10.6}/tests/test_end_run.py +0 -0
- {trodo_python-2.10.4 → trodo_python-2.10.6}/tests/test_error_enrichment.py +0 -0
- {trodo_python-2.10.4 → trodo_python-2.10.6}/tests/test_llm_usage_cost.py +0 -0
- {trodo_python-2.10.4 → trodo_python-2.10.6}/tests/test_processor_methods.py +0 -0
- {trodo_python-2.10.4 → trodo_python-2.10.6}/tests/test_register_otel.py +0 -0
- {trodo_python-2.10.4 → trodo_python-2.10.6}/tests/test_start_run.py +0 -0
- {trodo_python-2.10.4 → trodo_python-2.10.6}/tests/test_wrap_agent_unchanged.py +0 -0
- {trodo_python-2.10.4 → trodo_python-2.10.6}/trodo/api/__init__.py +0 -0
- {trodo_python-2.10.4 → trodo_python-2.10.6}/trodo/api/async_client.py +0 -0
- {trodo_python-2.10.4 → trodo_python-2.10.6}/trodo/api/endpoints.py +0 -0
- {trodo_python-2.10.4 → trodo_python-2.10.6}/trodo/auto/__init__.py +0 -0
- {trodo_python-2.10.4 → trodo_python-2.10.6}/trodo/auto/auto_event_manager.py +0 -0
- {trodo_python-2.10.4 → trodo_python-2.10.6}/trodo/client.py +0 -0
- {trodo_python-2.10.4 → trodo_python-2.10.6}/trodo/managers/__init__.py +0 -0
- {trodo_python-2.10.4 → trodo_python-2.10.6}/trodo/managers/group_manager.py +0 -0
- {trodo_python-2.10.4 → trodo_python-2.10.6}/trodo/managers/people_manager.py +0 -0
- {trodo_python-2.10.4 → trodo_python-2.10.6}/trodo/otel/__init__.py +0 -0
- {trodo_python-2.10.4 → trodo_python-2.10.6}/trodo/otel/context.py +0 -0
- {trodo_python-2.10.4 → trodo_python-2.10.6}/trodo/otel/helpers.py +0 -0
- {trodo_python-2.10.4 → trodo_python-2.10.6}/trodo/otel/processor.py +0 -0
- {trodo_python-2.10.4 → trodo_python-2.10.6}/trodo/otel/register.py +0 -0
- {trodo_python-2.10.4 → trodo_python-2.10.6}/trodo/otel/transport.py +0 -0
- {trodo_python-2.10.4 → trodo_python-2.10.6}/trodo/otel/wrap_agent.py +0 -0
- {trodo_python-2.10.4 → trodo_python-2.10.6}/trodo/queue/__init__.py +0 -0
- {trodo_python-2.10.4 → trodo_python-2.10.6}/trodo/queue/batch_flusher.py +0 -0
- {trodo_python-2.10.4 → trodo_python-2.10.6}/trodo/queue/event_queue.py +0 -0
- {trodo_python-2.10.4 → trodo_python-2.10.6}/trodo/session/__init__.py +0 -0
- {trodo_python-2.10.4 → trodo_python-2.10.6}/trodo/session/server_session.py +0 -0
- {trodo_python-2.10.4 → trodo_python-2.10.6}/trodo/session/session_manager.py +0 -0
- {trodo_python-2.10.4 → trodo_python-2.10.6}/trodo/types.py +0 -0
- {trodo_python-2.10.4 → trodo_python-2.10.6}/trodo/user_context.py +0 -0
- {trodo_python-2.10.4 → trodo_python-2.10.6}/trodo_python.egg-info/SOURCES.txt +0 -0
- {trodo_python-2.10.4 → trodo_python-2.10.6}/trodo_python.egg-info/dependency_links.txt +0 -0
- {trodo_python-2.10.4 → trodo_python-2.10.6}/trodo_python.egg-info/requires.txt +0 -0
- {trodo_python-2.10.4 → trodo_python-2.10.6}/trodo_python.egg-info/top_level.txt +0 -0
|
@@ -47,6 +47,24 @@ class HttpClient:
|
|
|
47
47
|
self._log(f"Retry {attempt + 1} after {delay}s (status {resp.status_code})")
|
|
48
48
|
time.sleep(delay)
|
|
49
49
|
return self._request(path, body, attempt + 1)
|
|
50
|
+
if resp.status_code >= 400:
|
|
51
|
+
# Surface non-2xx responses to on_error — a 4xx means the
|
|
52
|
+
# payload was REJECTED and the data is gone; before this it
|
|
53
|
+
# was fully silent (on_error only saw network errors), which
|
|
54
|
+
# made ingest-schema bugs invisible to callers.
|
|
55
|
+
detail = ""
|
|
56
|
+
try:
|
|
57
|
+
detail = resp.text[:300]
|
|
58
|
+
except Exception:
|
|
59
|
+
pass
|
|
60
|
+
self._log(f"HTTP {resp.status_code} on {path}: {detail}")
|
|
61
|
+
if self.on_error:
|
|
62
|
+
try:
|
|
63
|
+
self.on_error(
|
|
64
|
+
RuntimeError(f"trodo-python: POST {path} -> HTTP {resp.status_code}: {detail}")
|
|
65
|
+
)
|
|
66
|
+
except Exception:
|
|
67
|
+
pass
|
|
50
68
|
try:
|
|
51
69
|
return resp.json()
|
|
52
70
|
except Exception:
|
|
@@ -58,6 +58,24 @@ _ATTR_TRODO_RUN_ID = "trodo.run_id"
|
|
|
58
58
|
_ATTR_TRODO_PARENT_SPAN_ID = "trodo.parent_span_id"
|
|
59
59
|
|
|
60
60
|
|
|
61
|
+
def _span_id_to_uuid(span_id: Optional[str]) -> Optional[str]:
|
|
62
|
+
"""Convert an OTel hex span id into UUID format. Mirrors trodo-node's
|
|
63
|
+
spanIdToUuid: 16-hex OTel ids are left-zero-padded into the same UUID
|
|
64
|
+
address space as our uuid4-minted ids. Without this the bridge sent raw
|
|
65
|
+
16-hex into agent_spans' Postgres uuid columns -> the ingest 400'd and
|
|
66
|
+
the WHOLE run payload (run row + every span) was silently dropped, so
|
|
67
|
+
Python auto-instrumented runs never landed."""
|
|
68
|
+
if not span_id:
|
|
69
|
+
return span_id
|
|
70
|
+
h = str(span_id).replace("-", "").lower()
|
|
71
|
+
if len(h) == 32:
|
|
72
|
+
return f"{h[0:8]}-{h[8:12]}-{h[12:16]}-{h[16:20]}-{h[20:32]}"
|
|
73
|
+
if len(h) == 16:
|
|
74
|
+
p = "0000000000000000" + h
|
|
75
|
+
return f"{p[0:8]}-{p[8:12]}-{p[12:16]}-{p[16:20]}-{p[20:32]}"
|
|
76
|
+
return span_id
|
|
77
|
+
|
|
78
|
+
|
|
61
79
|
def otel_span_to_trodo_span(otel_span: Any) -> Optional[TrodoSpan]:
|
|
62
80
|
"""Translate an OTel ReadableSpan to our TrodoSpan using GenAI semconv.
|
|
63
81
|
|
|
@@ -77,7 +95,8 @@ def otel_span_to_trodo_span(otel_span: Any) -> Optional[TrodoSpan]:
|
|
|
77
95
|
span_id_int = getattr(span_ctx, "span_id", None)
|
|
78
96
|
if not span_id_int:
|
|
79
97
|
return None
|
|
80
|
-
|
|
98
|
+
span_id_hex = f"{span_id_int:016x}" if isinstance(span_id_int, int) else str(span_id_int)
|
|
99
|
+
span_id = _span_id_to_uuid(span_id_hex)
|
|
81
100
|
|
|
82
101
|
attrs = dict(getattr(otel_span, "attributes", {}) or {})
|
|
83
102
|
|
|
@@ -95,7 +114,7 @@ def otel_span_to_trodo_span(otel_span: Any) -> Optional[TrodoSpan]:
|
|
|
95
114
|
otel_parent_span_id: Optional[str] = None
|
|
96
115
|
if parent is not None:
|
|
97
116
|
pid = getattr(parent, "span_id", None)
|
|
98
|
-
otel_parent_span_id = (
|
|
117
|
+
otel_parent_span_id = _span_id_to_uuid(
|
|
99
118
|
f"{pid:016x}" if isinstance(pid, int) else str(pid) if pid else None
|
|
100
119
|
)
|
|
101
120
|
|
|
@@ -201,12 +220,30 @@ def otel_span_to_trodo_span(otel_span: Any) -> Optional[TrodoSpan]:
|
|
|
201
220
|
)
|
|
202
221
|
|
|
203
222
|
|
|
204
|
-
|
|
223
|
+
# Subclass the REAL SpanProcessor when the sdk is importable (it always is on
|
|
224
|
+
# the path that registers the adapter — enable_auto_instrument requires it).
|
|
225
|
+
# Duck-typing broke on opentelemetry-sdk >= 1.43: the provider calls
|
|
226
|
+
# `sp._on_ending(span)` on every span end, so a processor without the base
|
|
227
|
+
# class raises AttributeError INSIDE USER CODE at span.end().
|
|
228
|
+
try: # pragma: no cover — exercised implicitly by every auto-instrument test
|
|
229
|
+
from opentelemetry.sdk.trace import SpanProcessor as _SpanProcessorBase
|
|
230
|
+
except Exception:
|
|
231
|
+
_SpanProcessorBase = object # type: ignore[assignment,misc]
|
|
232
|
+
|
|
233
|
+
|
|
234
|
+
class _OtelAdapter(_SpanProcessorBase): # type: ignore[valid-type,misc]
|
|
205
235
|
"""Adapter matching opentelemetry.sdk.trace.SpanProcessor interface."""
|
|
206
236
|
|
|
207
237
|
def __init__(self, processor: TrodoSpanProcessor) -> None:
|
|
238
|
+
try:
|
|
239
|
+
super().__init__()
|
|
240
|
+
except TypeError:
|
|
241
|
+
pass
|
|
208
242
|
self._processor = processor
|
|
209
243
|
|
|
244
|
+
def on_ending(self, span: Any) -> None: # sdk >= 1.43 hook — no mutation needed
|
|
245
|
+
return None
|
|
246
|
+
|
|
210
247
|
def on_start(self, span: Any, parent_context: Any = None) -> None:
|
|
211
248
|
# Stamp active run/parent ids while contextvars are still alive.
|
|
212
249
|
# See otel_span_to_trodo_span() docstring for the failure mode this
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|