agenta 0.27.0__py3-none-any.whl → 0.27.0a1__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.
Potentially problematic release.
This version of agenta might be problematic. Click here for more details.
- agenta/__init__.py +3 -22
- agenta/cli/helper.py +1 -5
- agenta/client/backend/__init__.py +0 -14
- agenta/client/backend/apps/client.py +20 -28
- agenta/client/backend/client.py +2 -25
- agenta/client/backend/containers/client.py +1 -5
- agenta/client/backend/core/__init__.py +1 -2
- agenta/client/backend/core/client_wrapper.py +6 -6
- agenta/client/backend/core/file.py +11 -33
- agenta/client/backend/core/http_client.py +18 -24
- agenta/client/backend/core/pydantic_utilities.py +29 -144
- agenta/client/backend/core/request_options.py +0 -3
- agenta/client/backend/core/serialization.py +42 -139
- agenta/client/backend/evaluations/client.py +2 -7
- agenta/client/backend/evaluators/client.py +1 -349
- agenta/client/backend/observability/client.py +2 -11
- agenta/client/backend/testsets/client.py +10 -10
- agenta/client/backend/types/__init__.py +0 -14
- agenta/client/backend/types/app.py +0 -1
- agenta/client/backend/types/app_variant_response.py +1 -3
- agenta/client/backend/types/create_span.py +2 -3
- agenta/client/backend/types/environment_output.py +0 -1
- agenta/client/backend/types/environment_output_extended.py +0 -1
- agenta/client/backend/types/evaluation.py +2 -1
- agenta/client/backend/types/evaluator.py +0 -2
- agenta/client/backend/types/evaluator_config.py +0 -1
- agenta/client/backend/types/human_evaluation.py +2 -1
- agenta/client/backend/types/llm_tokens.py +2 -2
- agenta/client/backend/types/span.py +0 -1
- agenta/client/backend/types/span_detail.py +1 -7
- agenta/client/backend/types/test_set_output_response.py +2 -5
- agenta/client/backend/types/trace_detail.py +1 -7
- agenta/client/backend/types/with_pagination.py +2 -4
- agenta/client/backend/variants/client.py +273 -1566
- agenta/docker/docker-assets/Dockerfile.cloud.template +1 -1
- agenta/sdk/__init__.py +5 -20
- agenta/sdk/agenta_init.py +26 -30
- agenta/sdk/config_manager.py +205 -0
- agenta/sdk/context/routing.py +5 -6
- agenta/sdk/decorators/routing.py +135 -142
- agenta/sdk/decorators/tracing.py +245 -206
- agenta/sdk/litellm/litellm.py +36 -47
- agenta/sdk/tracing/attributes.py +2 -7
- agenta/sdk/tracing/context.py +2 -5
- agenta/sdk/tracing/conventions.py +8 -10
- agenta/sdk/tracing/exporters.py +6 -15
- agenta/sdk/tracing/inline.py +98 -70
- agenta/sdk/tracing/processors.py +14 -55
- agenta/sdk/tracing/spans.py +4 -16
- agenta/sdk/tracing/tracing.py +50 -54
- agenta/sdk/types.py +2 -61
- agenta/sdk/utils/exceptions.py +1 -31
- {agenta-0.27.0.dist-info → agenta-0.27.0a1.dist-info}/METADATA +1 -1
- {agenta-0.27.0.dist-info → agenta-0.27.0a1.dist-info}/RECORD +56 -67
- agenta/client/backend/types/config_dto.py +0 -32
- agenta/client/backend/types/config_response_model.py +0 -32
- agenta/client/backend/types/evaluator_mapping_output_interface.py +0 -21
- agenta/client/backend/types/evaluator_output_interface.py +0 -21
- agenta/client/backend/types/lifecycle_dto.py +0 -24
- agenta/client/backend/types/reference_dto.py +0 -23
- agenta/client/backend/types/reference_request_model.py +0 -23
- agenta/sdk/managers/__init__.py +0 -6
- agenta/sdk/managers/config.py +0 -318
- agenta/sdk/managers/deployment.py +0 -45
- agenta/sdk/managers/shared.py +0 -639
- agenta/sdk/managers/variant.py +0 -182
- {agenta-0.27.0.dist-info → agenta-0.27.0a1.dist-info}/WHEEL +0 -0
- {agenta-0.27.0.dist-info → agenta-0.27.0a1.dist-info}/entry_points.txt +0 -0
agenta/sdk/tracing/context.py
CHANGED
|
@@ -15,10 +15,7 @@ def tracing_context_manager():
|
|
|
15
15
|
try:
|
|
16
16
|
yield
|
|
17
17
|
except Exception as e:
|
|
18
|
-
log.error("
|
|
19
|
-
log.error("
|
|
20
|
-
log.error("----------------------------------------------")
|
|
21
|
-
log.error(format_exc().strip("\n"))
|
|
22
|
-
log.error("----------------------------------------------")
|
|
18
|
+
log.error(f"Error with tracing context: {_tracing_context}")
|
|
19
|
+
log.error(f"Exception: {format_exc()}")
|
|
23
20
|
finally:
|
|
24
21
|
tracing_context.reset(token)
|
|
@@ -1,7 +1,14 @@
|
|
|
1
|
+
from opentelemetry.trace import SpanKind
|
|
2
|
+
|
|
1
3
|
from enum import Enum
|
|
4
|
+
|
|
2
5
|
from re import fullmatch
|
|
3
6
|
|
|
4
|
-
|
|
7
|
+
_PATTERN = r"[A-Za-z0-9._-]+"
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def is_valid_attribute_key(string):
|
|
11
|
+
return bool(fullmatch(_PATTERN, string))
|
|
5
12
|
|
|
6
13
|
|
|
7
14
|
class Reference(str, Enum):
|
|
@@ -19,15 +26,6 @@ class Reference(str, Enum):
|
|
|
19
26
|
#
|
|
20
27
|
|
|
21
28
|
|
|
22
|
-
_PATTERN = r"[A-Za-z0-9._-]+"
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
def is_valid_attribute_key(
|
|
26
|
-
string: str,
|
|
27
|
-
):
|
|
28
|
-
return bool(fullmatch(_PATTERN, string))
|
|
29
|
-
|
|
30
|
-
|
|
31
29
|
def parse_span_kind(type: str) -> SpanKind:
|
|
32
30
|
kind = SpanKind.INTERNAL
|
|
33
31
|
if type in [
|
agenta/sdk/tracing/exporters.py
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
from typing import Sequence, Dict, List
|
|
2
2
|
|
|
3
|
-
from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter
|
|
4
3
|
from opentelemetry.sdk.trace.export import (
|
|
5
4
|
ConsoleSpanExporter,
|
|
6
5
|
SpanExporter,
|
|
7
6
|
SpanExportResult,
|
|
8
7
|
ReadableSpan,
|
|
9
8
|
)
|
|
9
|
+
from opentelemetry.exporter.otlp.proto.http.trace_exporter import (
|
|
10
|
+
OTLPSpanExporter,
|
|
11
|
+
)
|
|
10
12
|
|
|
11
13
|
from agenta.sdk.utils.exceptions import suppress
|
|
12
14
|
|
|
@@ -38,28 +40,17 @@ class InlineTraceExporter(SpanExporter):
|
|
|
38
40
|
def force_flush(self, timeout_millis: int = 30000) -> bool:
|
|
39
41
|
return True
|
|
40
42
|
|
|
41
|
-
def
|
|
42
|
-
self,
|
|
43
|
-
trace_id: int,
|
|
44
|
-
) -> bool:
|
|
45
|
-
is_ready = trace_id in self._registry
|
|
46
|
-
|
|
47
|
-
return is_ready
|
|
48
|
-
|
|
49
|
-
def fetch(
|
|
50
|
-
self,
|
|
51
|
-
trace_id: int,
|
|
52
|
-
) -> List[ReadableSpan]:
|
|
43
|
+
def fetch(self, trace_id: int) -> List[ReadableSpan]:
|
|
53
44
|
trace = self._registry.get(trace_id, [])
|
|
54
45
|
|
|
55
|
-
|
|
56
|
-
del self._registry[trace_id]
|
|
46
|
+
del self._registry[trace_id]
|
|
57
47
|
|
|
58
48
|
return trace
|
|
59
49
|
|
|
60
50
|
|
|
61
51
|
OTLPSpanExporter._MAX_RETRY_TIMEOUT = 2
|
|
62
52
|
|
|
53
|
+
|
|
63
54
|
ConsoleExporter = ConsoleSpanExporter
|
|
64
55
|
InlineExporter = InlineTraceExporter
|
|
65
56
|
OTLPExporter = OTLPSpanExporter
|
agenta/sdk/tracing/inline.py
CHANGED
|
@@ -11,11 +11,82 @@ from enum import Enum
|
|
|
11
11
|
from collections import OrderedDict
|
|
12
12
|
|
|
13
13
|
|
|
14
|
-
|
|
14
|
+
NOF_CHARS = 8
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def _p_id(id):
|
|
18
|
+
return repr(str(id)[:NOF_CHARS])
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def _p_osa(o):
|
|
22
|
+
elements = []
|
|
23
|
+
|
|
24
|
+
for i in OrderedDict(sorted(o.items())).items():
|
|
25
|
+
if not i[0].startswith("_"):
|
|
26
|
+
if i[1].__class__.__module__ != "builtins":
|
|
27
|
+
if repr(i[1]).startswith("<"):
|
|
28
|
+
elements.append(f"{i[0]}: {i[1].name}")
|
|
29
|
+
elif repr(i[1]).startswith("UUID("):
|
|
30
|
+
elements.append(f"{i[0]}: {_p_id(i[1])}")
|
|
31
|
+
else:
|
|
32
|
+
elements.append(f"{i[0]}: {i[1].__str__()}")
|
|
33
|
+
else:
|
|
34
|
+
if isinstance(i[1], list):
|
|
35
|
+
elements.append(
|
|
36
|
+
f"{i[0]}: [" + ", ".join([el.__str__() for el in i[1]]) + "]"
|
|
37
|
+
)
|
|
38
|
+
elif isinstance(i[1], dict):
|
|
39
|
+
elements.append(f"{i[0]}: {{{_p_osa(i[1])}}}")
|
|
40
|
+
else:
|
|
41
|
+
if i[1] is not None:
|
|
42
|
+
if i[0] == "slug":
|
|
43
|
+
elements.append(f"{i[0]}: {repr(i[1][:8])}")
|
|
44
|
+
else:
|
|
45
|
+
elements.append(f"{i[0]}: {repr(i[1])}")
|
|
46
|
+
|
|
47
|
+
return ", ".join(elements)
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def _p_ora(o, open="{", close="}", sep=": ", foo=repr):
|
|
51
|
+
if o.__class__.__module__ != "builtins":
|
|
52
|
+
if o.__class__.__name__ == "UUID":
|
|
53
|
+
return repr(o)
|
|
54
|
+
if isinstance(o, Enum):
|
|
55
|
+
return o
|
|
56
|
+
if isinstance(o, datetime):
|
|
57
|
+
return o.isoformat()
|
|
58
|
+
return f"{o.__class__.__name__}({_p_ora(o.__dict__, open='', close='', sep='=', foo=lambda x : x)})"
|
|
59
|
+
elif isinstance(o, list):
|
|
60
|
+
return f"[{', '.join([repr(el) for el in o])}]"
|
|
61
|
+
elif isinstance(o, dict):
|
|
62
|
+
o = OrderedDict(sorted(o.items()))
|
|
63
|
+
return f"{open}{', '.join([f'{foo(elk)}{sep}{_p_ora(elv)}' for elk, elv in o.items()])}{close}"
|
|
64
|
+
else:
|
|
65
|
+
if o is not None:
|
|
66
|
+
return repr(o)
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def _str(o):
|
|
70
|
+
return f"{{{_p_osa(o.__dict__)}}}"
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def _repr(o):
|
|
74
|
+
return _p_ora(o)
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
class DisplayBase(BaseModel):
|
|
78
|
+
def __str__(self):
|
|
79
|
+
return _str(self)
|
|
80
|
+
|
|
81
|
+
def __repr__(self):
|
|
82
|
+
return _repr(self)
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
class ProjectScopeDTO(DisplayBase):
|
|
15
86
|
project_id: UUID
|
|
16
87
|
|
|
17
88
|
|
|
18
|
-
class LifecycleDTO(
|
|
89
|
+
class LifecycleDTO(DisplayBase):
|
|
19
90
|
created_at: datetime
|
|
20
91
|
updated_at: Optional[datetime] = None
|
|
21
92
|
|
|
@@ -31,14 +102,14 @@ class LifecycleDTO(BaseModel):
|
|
|
31
102
|
### services.observability.dtos ###
|
|
32
103
|
### --------------------------- ###
|
|
33
104
|
|
|
34
|
-
from typing import List, Dict, Any, Union, Optional
|
|
105
|
+
from typing import List, Dict, Any, Union, Optional, Sequence
|
|
35
106
|
|
|
36
107
|
from enum import Enum
|
|
37
108
|
from datetime import datetime
|
|
38
109
|
from uuid import UUID
|
|
39
110
|
|
|
40
111
|
|
|
41
|
-
class TimeDTO(
|
|
112
|
+
class TimeDTO(DisplayBase):
|
|
42
113
|
start: datetime
|
|
43
114
|
end: datetime
|
|
44
115
|
span: int
|
|
@@ -50,7 +121,7 @@ class StatusCode(Enum):
|
|
|
50
121
|
ERROR = "ERROR"
|
|
51
122
|
|
|
52
123
|
|
|
53
|
-
class StatusDTO(
|
|
124
|
+
class StatusDTO(DisplayBase):
|
|
54
125
|
code: StatusCode
|
|
55
126
|
message: Optional[str] = None
|
|
56
127
|
stacktrace: Optional[str] = None
|
|
@@ -84,16 +155,16 @@ class NodeType(Enum):
|
|
|
84
155
|
# --- VARIANTS --- #
|
|
85
156
|
|
|
86
157
|
|
|
87
|
-
class RootDTO(
|
|
158
|
+
class RootDTO(DisplayBase):
|
|
88
159
|
id: UUID
|
|
89
160
|
|
|
90
161
|
|
|
91
|
-
class TreeDTO(
|
|
162
|
+
class TreeDTO(DisplayBase):
|
|
92
163
|
id: UUID
|
|
93
164
|
type: Optional[TreeType] = None
|
|
94
165
|
|
|
95
166
|
|
|
96
|
-
class NodeDTO(
|
|
167
|
+
class NodeDTO(DisplayBase):
|
|
97
168
|
id: UUID
|
|
98
169
|
type: Optional[NodeType] = None
|
|
99
170
|
name: str
|
|
@@ -106,13 +177,13 @@ Tags = Dict[str, str]
|
|
|
106
177
|
Refs = Dict[str, str]
|
|
107
178
|
|
|
108
179
|
|
|
109
|
-
class LinkDTO(
|
|
180
|
+
class LinkDTO(DisplayBase):
|
|
110
181
|
type: str
|
|
111
182
|
id: UUID
|
|
112
183
|
tree_id: Optional[UUID] = None
|
|
113
184
|
|
|
114
185
|
|
|
115
|
-
class ParentDTO(
|
|
186
|
+
class ParentDTO(DisplayBase):
|
|
116
187
|
id: UUID
|
|
117
188
|
|
|
118
189
|
|
|
@@ -134,25 +205,25 @@ class OTelStatusCode(Enum):
|
|
|
134
205
|
STATUS_CODE_UNSET = "STATUS_CODE_UNSET"
|
|
135
206
|
|
|
136
207
|
|
|
137
|
-
class OTelContextDTO(
|
|
208
|
+
class OTelContextDTO(DisplayBase):
|
|
138
209
|
trace_id: str
|
|
139
210
|
span_id: str
|
|
140
211
|
|
|
141
212
|
|
|
142
|
-
class OTelEventDTO(
|
|
213
|
+
class OTelEventDTO(DisplayBase):
|
|
143
214
|
name: str
|
|
144
215
|
timestamp: datetime
|
|
145
216
|
|
|
146
217
|
attributes: Optional[Attributes] = None
|
|
147
218
|
|
|
148
219
|
|
|
149
|
-
class OTelLinkDTO(
|
|
220
|
+
class OTelLinkDTO(DisplayBase):
|
|
150
221
|
context: OTelContextDTO
|
|
151
222
|
|
|
152
223
|
attributes: Optional[Attributes] = None
|
|
153
224
|
|
|
154
225
|
|
|
155
|
-
class OTelExtraDTO(
|
|
226
|
+
class OTelExtraDTO(DisplayBase):
|
|
156
227
|
kind: Optional[str] = None
|
|
157
228
|
|
|
158
229
|
attributes: Optional[Attributes] = None
|
|
@@ -160,8 +231,8 @@ class OTelExtraDTO(BaseModel):
|
|
|
160
231
|
links: Optional[List[OTelLinkDTO]] = None
|
|
161
232
|
|
|
162
233
|
|
|
163
|
-
class SpanDTO(
|
|
164
|
-
scope:
|
|
234
|
+
class SpanDTO(DisplayBase):
|
|
235
|
+
scope: ProjectScopeDTO
|
|
165
236
|
|
|
166
237
|
lifecycle: Optional[LifecycleDTO] = None
|
|
167
238
|
|
|
@@ -187,7 +258,7 @@ class SpanDTO(BaseModel):
|
|
|
187
258
|
nodes: Optional[Dict[str, Union["SpanDTO", List["SpanDTO"]]]] = None
|
|
188
259
|
|
|
189
260
|
|
|
190
|
-
class OTelSpanDTO(
|
|
261
|
+
class OTelSpanDTO(DisplayBase):
|
|
191
262
|
context: OTelContextDTO
|
|
192
263
|
|
|
193
264
|
name: str
|
|
@@ -412,12 +483,9 @@ def _connect_tree_dfs(
|
|
|
412
483
|
### apis.fastapi.observability.opentelemetry.semconv ###
|
|
413
484
|
### ------------------------------------------------ ###
|
|
414
485
|
|
|
415
|
-
from json import loads
|
|
416
|
-
|
|
417
486
|
VERSION = "0.4.1"
|
|
418
487
|
|
|
419
488
|
V_0_4_1_ATTRIBUTES_EXACT = [
|
|
420
|
-
# OPENLLMETRY
|
|
421
489
|
("gen_ai.system", "ag.meta.system"),
|
|
422
490
|
("gen_ai.request.base_url", "ag.meta.request.base_url"),
|
|
423
491
|
("gen_ai.request.endpoint", "ag.meta.request.endpoint"),
|
|
@@ -442,35 +510,12 @@ V_0_4_1_ATTRIBUTES_EXACT = [
|
|
|
442
510
|
("db.vector.query.top_k", "ag.meta.request.top_k"),
|
|
443
511
|
("pinecone.query.top_k", "ag.meta.request.top_k"),
|
|
444
512
|
("traceloop.span.kind", "ag.type.node"),
|
|
445
|
-
("traceloop.entity.name", "ag.node.name"),
|
|
446
|
-
# OPENINFERENCE
|
|
447
|
-
("output.value", "ag.data.outputs"),
|
|
448
|
-
("input.value", "ag.data.inputs"),
|
|
449
|
-
("embedding.model_name", "ag.meta.request.model"),
|
|
450
|
-
("llm.invocation_parameters", "ag.meta.request"),
|
|
451
|
-
("llm.model_name", "ag.meta.request.model"),
|
|
452
|
-
("llm.provider", "ag.meta.provider"),
|
|
453
|
-
("llm.system", "ag.meta.system"),
|
|
454
513
|
]
|
|
455
514
|
V_0_4_1_ATTRIBUTES_PREFIX = [
|
|
456
|
-
# OPENLLMETRY
|
|
457
515
|
("gen_ai.prompt", "ag.data.inputs.prompt"),
|
|
458
516
|
("gen_ai.completion", "ag.data.outputs.completion"),
|
|
459
|
-
("llm.request.functions", "ag.data.inputs.functions"),
|
|
460
|
-
("llm.request.tools", "ag.data.inputs.tools"),
|
|
461
|
-
# OPENINFERENCE
|
|
462
|
-
("llm.token_count", "ag.metrics.unit.tokens"),
|
|
463
|
-
("llm.input_messages", "ag.data.inputs.prompt"),
|
|
464
|
-
("llm.output_messages", "ag.data.outputs.completion"),
|
|
465
517
|
]
|
|
466
518
|
|
|
467
|
-
V_0_4_1_ATTRIBUTES_DYNAMIC = [
|
|
468
|
-
# OPENLLMETRY
|
|
469
|
-
("traceloop.entity.input", lambda x: ("ag.data.inputs", loads(x).get("inputs"))),
|
|
470
|
-
("traceloop.entity.output", lambda x: ("ag.data.outputs", loads(x).get("outputs"))),
|
|
471
|
-
]
|
|
472
|
-
|
|
473
|
-
|
|
474
519
|
V_0_4_1_MAPS = {
|
|
475
520
|
"attributes": {
|
|
476
521
|
"exact": {
|
|
@@ -481,9 +526,6 @@ V_0_4_1_MAPS = {
|
|
|
481
526
|
"from": {otel: agenta for otel, agenta in V_0_4_1_ATTRIBUTES_PREFIX[::-1]},
|
|
482
527
|
"to": {agenta: otel for otel, agenta in V_0_4_1_ATTRIBUTES_PREFIX[::-1]},
|
|
483
528
|
},
|
|
484
|
-
"dynamic": {
|
|
485
|
-
"from": {otel: agenta for otel, agenta in V_0_4_1_ATTRIBUTES_DYNAMIC[::-1]}
|
|
486
|
-
},
|
|
487
529
|
},
|
|
488
530
|
}
|
|
489
531
|
V_0_4_1_KEYS = {
|
|
@@ -496,9 +538,6 @@ V_0_4_1_KEYS = {
|
|
|
496
538
|
"from": list(V_0_4_1_MAPS["attributes"]["prefix"]["from"].keys()),
|
|
497
539
|
"to": list(V_0_4_1_MAPS["attributes"]["prefix"]["to"].keys()),
|
|
498
540
|
},
|
|
499
|
-
"dynamic": {
|
|
500
|
-
"from": list(V_0_4_1_MAPS["attributes"]["dynamic"]["from"].keys()),
|
|
501
|
-
},
|
|
502
541
|
},
|
|
503
542
|
}
|
|
504
543
|
|
|
@@ -512,7 +551,6 @@ KEYS = {
|
|
|
512
551
|
|
|
513
552
|
CODEX = {"maps": MAPS[VERSION], "keys": KEYS[VERSION]}
|
|
514
553
|
|
|
515
|
-
|
|
516
554
|
### ------------------------------------------------ ###
|
|
517
555
|
### apis.fastapi.observability.opentelemetry.semconv ###
|
|
518
556
|
########################################################
|
|
@@ -686,18 +724,6 @@ def _parse_from_semconv(
|
|
|
686
724
|
|
|
687
725
|
del attributes[old_key]
|
|
688
726
|
|
|
689
|
-
for dynamic_key in CODEX["keys"]["attributes"]["dynamic"]["from"]:
|
|
690
|
-
if old_key == dynamic_key:
|
|
691
|
-
try:
|
|
692
|
-
new_key, new_value = CODEX["maps"]["attributes"]["dynamic"][
|
|
693
|
-
"from"
|
|
694
|
-
][dynamic_key](value)
|
|
695
|
-
|
|
696
|
-
attributes[new_key] = new_value
|
|
697
|
-
|
|
698
|
-
except: # pylint: disable=bare-except
|
|
699
|
-
pass
|
|
700
|
-
|
|
701
727
|
|
|
702
728
|
def _parse_from_links(
|
|
703
729
|
otel_span_dto: OTelSpanDTO,
|
|
@@ -800,8 +826,11 @@ def _parse_from_attributes(
|
|
|
800
826
|
|
|
801
827
|
|
|
802
828
|
def parse_from_otel_span_dto(
|
|
829
|
+
project_id: str,
|
|
803
830
|
otel_span_dto: OTelSpanDTO,
|
|
804
831
|
) -> SpanDTO:
|
|
832
|
+
scope = ProjectScopeDTO(project_id=UUID(project_id))
|
|
833
|
+
|
|
805
834
|
lifecyle = LifecycleDTO(
|
|
806
835
|
created_at=datetime.now(),
|
|
807
836
|
)
|
|
@@ -821,15 +850,11 @@ def parse_from_otel_span_dto(
|
|
|
821
850
|
|
|
822
851
|
node_id = UUID(tree_id.hex[16:] + otel_span_dto.context.span_id[2:])
|
|
823
852
|
|
|
824
|
-
node_type =
|
|
825
|
-
try:
|
|
826
|
-
node_type = NodeType(types.get("node", "").lower())
|
|
827
|
-
except: # pylint: disable=bare-except
|
|
828
|
-
pass
|
|
853
|
+
node_type: str = types.get("node")
|
|
829
854
|
|
|
830
855
|
node = NodeDTO(
|
|
831
856
|
id=node_id,
|
|
832
|
-
type=node_type,
|
|
857
|
+
type=node_type.lower() if node_type else None,
|
|
833
858
|
name=otel_span_dto.name,
|
|
834
859
|
)
|
|
835
860
|
|
|
@@ -877,6 +902,7 @@ def parse_from_otel_span_dto(
|
|
|
877
902
|
)
|
|
878
903
|
|
|
879
904
|
span_dto = SpanDTO(
|
|
905
|
+
scope=scope,
|
|
880
906
|
lifecycle=lifecyle,
|
|
881
907
|
root=root,
|
|
882
908
|
tree=tree,
|
|
@@ -947,6 +973,7 @@ from opentelemetry.sdk.trace import ReadableSpan
|
|
|
947
973
|
|
|
948
974
|
|
|
949
975
|
def parse_inline_trace(
|
|
976
|
+
project_id: str,
|
|
950
977
|
spans: Dict[str, ReadableSpan],
|
|
951
978
|
):
|
|
952
979
|
otel_span_dtos = _parse_readable_spans(spans)
|
|
@@ -955,7 +982,8 @@ def parse_inline_trace(
|
|
|
955
982
|
### apis.fastapi.observability.api.otlp_collect_traces() ###
|
|
956
983
|
### ---------------------------------------------------- ###
|
|
957
984
|
span_dtos = [
|
|
958
|
-
parse_from_otel_span_dto(otel_span_dto)
|
|
985
|
+
parse_from_otel_span_dto(project_id, otel_span_dto)
|
|
986
|
+
for otel_span_dto in otel_span_dtos
|
|
959
987
|
]
|
|
960
988
|
### ---------------------------------------------------- ###
|
|
961
989
|
### apis.fastapi.observability.api.otlp_collect_traces() ###
|
|
@@ -1195,7 +1223,7 @@ def _parse_to_legacy_span(span: SpanDTO) -> CreateSpan:
|
|
|
1195
1223
|
),
|
|
1196
1224
|
#
|
|
1197
1225
|
app_id=(
|
|
1198
|
-
span.refs.get("application
|
|
1226
|
+
span.refs.get("application.id", "missing-app-id")
|
|
1199
1227
|
if span.refs
|
|
1200
1228
|
else "missing-app-id"
|
|
1201
1229
|
),
|
agenta/sdk/tracing/processors.py
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
from typing import Optional, Dict
|
|
1
|
+
from typing import Optional, Dict
|
|
2
|
+
from traceback import format_exc
|
|
2
3
|
|
|
3
4
|
from opentelemetry.context import Context
|
|
4
5
|
from opentelemetry.sdk.trace import Span
|
|
@@ -6,8 +7,8 @@ from opentelemetry.sdk.trace.export import (
|
|
|
6
7
|
SpanExporter,
|
|
7
8
|
ReadableSpan,
|
|
8
9
|
BatchSpanProcessor,
|
|
10
|
+
_DEFAULT_EXPORT_TIMEOUT_MILLIS,
|
|
9
11
|
_DEFAULT_MAX_QUEUE_SIZE,
|
|
10
|
-
_DEFAULT_MAX_EXPORT_BATCH_SIZE,
|
|
11
12
|
)
|
|
12
13
|
|
|
13
14
|
from agenta.sdk.utils.logging import log
|
|
@@ -28,21 +29,16 @@ class TraceProcessor(BatchSpanProcessor):
|
|
|
28
29
|
super().__init__(
|
|
29
30
|
span_exporter,
|
|
30
31
|
_DEFAULT_MAX_QUEUE_SIZE,
|
|
31
|
-
|
|
32
|
-
|
|
32
|
+
60 * 60 * 1000, # 1 hour
|
|
33
|
+
_DEFAULT_MAX_QUEUE_SIZE,
|
|
33
34
|
500, # < 1 second (0.5 seconds)
|
|
34
35
|
)
|
|
35
36
|
|
|
36
37
|
self._registry = dict()
|
|
37
38
|
self._exporter = span_exporter
|
|
38
39
|
self.references = references or dict()
|
|
39
|
-
self.spans: Dict[int, List[ReadableSpan]] = dict()
|
|
40
40
|
|
|
41
|
-
def on_start(
|
|
42
|
-
self,
|
|
43
|
-
span: Span,
|
|
44
|
-
parent_context: Optional[Context] = None,
|
|
45
|
-
) -> None:
|
|
41
|
+
def on_start(self, span: Span, parent_context: Optional[Context] = None) -> None:
|
|
46
42
|
# ADD LINKS FROM CONTEXT, HERE
|
|
47
43
|
|
|
48
44
|
for key in self.references.keys():
|
|
@@ -53,41 +49,15 @@ class TraceProcessor(BatchSpanProcessor):
|
|
|
53
49
|
|
|
54
50
|
self._registry[span.context.trace_id][span.context.span_id] = True
|
|
55
51
|
|
|
56
|
-
def on_end(
|
|
57
|
-
|
|
58
|
-
span: ReadableSpan,
|
|
59
|
-
):
|
|
60
|
-
if self.done:
|
|
61
|
-
return
|
|
62
|
-
|
|
63
|
-
if span.context.trace_id not in self.spans:
|
|
64
|
-
self.spans[span.context.trace_id] = list()
|
|
65
|
-
|
|
66
|
-
self.spans[span.context.trace_id].append(span)
|
|
52
|
+
def on_end(self, span: ReadableSpan):
|
|
53
|
+
super().on_end(span)
|
|
67
54
|
|
|
68
55
|
del self._registry[span.context.trace_id][span.context.span_id]
|
|
69
56
|
|
|
70
|
-
if
|
|
71
|
-
self.
|
|
72
|
-
|
|
73
|
-
def export(
|
|
74
|
-
self,
|
|
75
|
-
trace_id: int,
|
|
76
|
-
):
|
|
77
|
-
spans = self.spans[trace_id]
|
|
78
|
-
|
|
79
|
-
for span in spans:
|
|
80
|
-
self.queue.appendleft(span)
|
|
81
|
-
|
|
82
|
-
with self.condition:
|
|
83
|
-
self.condition.notify()
|
|
84
|
-
|
|
85
|
-
del self.spans[trace_id]
|
|
57
|
+
if self.is_ready(span.get_span_context().trace_id):
|
|
58
|
+
self.force_flush()
|
|
86
59
|
|
|
87
|
-
def force_flush(
|
|
88
|
-
self,
|
|
89
|
-
timeout_millis: int = None,
|
|
90
|
-
) -> bool:
|
|
60
|
+
def force_flush(self, timeout_millis: int = None) -> bool:
|
|
91
61
|
ret = super().force_flush(timeout_millis)
|
|
92
62
|
|
|
93
63
|
if not ret:
|
|
@@ -95,23 +65,12 @@ class TraceProcessor(BatchSpanProcessor):
|
|
|
95
65
|
log.error("Agenta SDK - skipping export due to timeout.")
|
|
96
66
|
log.error("--------------------------------------------")
|
|
97
67
|
|
|
98
|
-
def is_ready(
|
|
99
|
-
self,
|
|
100
|
-
trace_id: Optional[int] = None,
|
|
101
|
-
) -> bool:
|
|
102
|
-
is_ready = True
|
|
103
|
-
|
|
104
|
-
try:
|
|
105
|
-
is_ready = self._exporter.is_ready(trace_id)
|
|
106
|
-
except: # pylint: disable=bare-except
|
|
107
|
-
pass
|
|
68
|
+
def is_ready(self, trace_id: Optional[int] = None) -> bool:
|
|
69
|
+
is_ready = not len(self._registry.get(trace_id, {}))
|
|
108
70
|
|
|
109
71
|
return is_ready
|
|
110
72
|
|
|
111
|
-
def fetch(
|
|
112
|
-
self,
|
|
113
|
-
trace_id: Optional[int] = None,
|
|
114
|
-
) -> Dict[str, ReadableSpan]:
|
|
73
|
+
def fetch(self, trace_id: Optional[int] = None) -> Dict[str, ReadableSpan]:
|
|
115
74
|
trace = self._exporter.fetch(trace_id) # type: ignore
|
|
116
75
|
|
|
117
76
|
return trace
|
agenta/sdk/tracing/spans.py
CHANGED
|
@@ -8,10 +8,7 @@ from agenta.sdk.tracing.attributes import serialize
|
|
|
8
8
|
|
|
9
9
|
|
|
10
10
|
class CustomSpan(Span): # INHERITANCE FOR TYPING ONLY
|
|
11
|
-
def __init__(
|
|
12
|
-
self,
|
|
13
|
-
span: Span,
|
|
14
|
-
) -> None:
|
|
11
|
+
def __init__(self, span: Span) -> None:
|
|
15
12
|
super().__init__( # INHERITANCE FOR TYPING ONLY
|
|
16
13
|
name=span.name,
|
|
17
14
|
context=span.context,
|
|
@@ -41,10 +38,7 @@ class CustomSpan(Span): # INHERITANCE FOR TYPING ONLY
|
|
|
41
38
|
def is_recording(self) -> bool:
|
|
42
39
|
return self._span.is_recording()
|
|
43
40
|
|
|
44
|
-
def update_name(
|
|
45
|
-
self,
|
|
46
|
-
name: str,
|
|
47
|
-
) -> None:
|
|
41
|
+
def update_name(self, name: str) -> None:
|
|
48
42
|
self._span.update_name(name)
|
|
49
43
|
|
|
50
44
|
def set_status(
|
|
@@ -52,10 +46,7 @@ class CustomSpan(Span): # INHERITANCE FOR TYPING ONLY
|
|
|
52
46
|
status: Union[Status, StatusCode],
|
|
53
47
|
description: Optional[str] = None,
|
|
54
48
|
) -> None:
|
|
55
|
-
self._span.set_status(
|
|
56
|
-
status=status,
|
|
57
|
-
description=description,
|
|
58
|
-
)
|
|
49
|
+
self._span.set_status(status=status, description=description)
|
|
59
50
|
|
|
60
51
|
def end(self) -> None:
|
|
61
52
|
self._span.end()
|
|
@@ -82,10 +73,7 @@ class CustomSpan(Span): # INHERITANCE FOR TYPING ONLY
|
|
|
82
73
|
value: Any,
|
|
83
74
|
namespace: Optional[str] = None,
|
|
84
75
|
) -> None:
|
|
85
|
-
self.set_attributes(
|
|
86
|
-
attributes={key: value},
|
|
87
|
-
namespace=namespace,
|
|
88
|
-
)
|
|
76
|
+
self.set_attributes({key: value}, namespace)
|
|
89
77
|
|
|
90
78
|
def add_event(
|
|
91
79
|
self,
|