agenta 0.27.0a2__py3-none-any.whl → 0.27.0a5__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/sdk/decorators/routing.py +126 -130
- agenta/sdk/decorators/tracing.py +196 -244
- agenta/sdk/tracing/attributes.py +7 -2
- agenta/sdk/tracing/context.py +5 -2
- agenta/sdk/tracing/conventions.py +10 -8
- agenta/sdk/tracing/exporters.py +5 -5
- agenta/sdk/tracing/inline.py +16 -87
- agenta/sdk/tracing/processors.py +21 -7
- agenta/sdk/tracing/spans.py +16 -4
- agenta/sdk/tracing/tracing.py +58 -30
- {agenta-0.27.0a2.dist-info → agenta-0.27.0a5.dist-info}/METADATA +1 -1
- {agenta-0.27.0a2.dist-info → agenta-0.27.0a5.dist-info}/RECORD +14 -14
- {agenta-0.27.0a2.dist-info → agenta-0.27.0a5.dist-info}/WHEEL +0 -0
- {agenta-0.27.0a2.dist-info → agenta-0.27.0a5.dist-info}/entry_points.txt +0 -0
agenta/sdk/decorators/tracing.py
CHANGED
|
@@ -1,289 +1,241 @@
|
|
|
1
|
-
import
|
|
2
|
-
import traceback
|
|
1
|
+
from typing import Callable, Optional, Any, Dict, List, Union
|
|
3
2
|
from functools import wraps
|
|
4
3
|
from itertools import chain
|
|
5
|
-
from
|
|
6
|
-
|
|
7
|
-
import agenta as ag
|
|
8
|
-
|
|
4
|
+
from inspect import iscoroutinefunction, getfullargspec
|
|
9
5
|
|
|
10
6
|
from agenta.sdk.utils.exceptions import suppress
|
|
11
|
-
|
|
12
7
|
from agenta.sdk.context.tracing import tracing_context
|
|
13
8
|
from agenta.sdk.tracing.conventions import parse_span_kind
|
|
14
9
|
|
|
10
|
+
import agenta as ag
|
|
11
|
+
|
|
15
12
|
|
|
16
13
|
class instrument:
|
|
17
14
|
DEFAULT_KEY = "__default__"
|
|
18
15
|
|
|
19
16
|
def __init__(
|
|
20
17
|
self,
|
|
21
|
-
|
|
18
|
+
type: str = "task",
|
|
22
19
|
config: Optional[Dict[str, Any]] = None,
|
|
23
20
|
ignore_inputs: Optional[bool] = None,
|
|
24
21
|
ignore_outputs: Optional[bool] = None,
|
|
25
22
|
max_depth: Optional[int] = 2,
|
|
26
|
-
#
|
|
23
|
+
# DEPRECATING
|
|
24
|
+
kind: str = "task",
|
|
27
25
|
spankind: Optional[str] = "TASK",
|
|
28
26
|
) -> None:
|
|
29
|
-
self.
|
|
27
|
+
self.type = spankind or kind or type
|
|
28
|
+
self.kind = None
|
|
30
29
|
self.config = config
|
|
31
30
|
self.ignore_inputs = ignore_inputs
|
|
32
31
|
self.ignore_outputs = ignore_outputs
|
|
33
32
|
self.max_depth = max_depth
|
|
34
33
|
|
|
35
34
|
def __call__(self, func: Callable[..., Any]):
|
|
36
|
-
is_coroutine_function =
|
|
37
|
-
|
|
38
|
-
def parse(*args, **kwargs) -> Dict[str, Any]:
|
|
39
|
-
inputs = {
|
|
40
|
-
key: value
|
|
41
|
-
for key, value in chain(
|
|
42
|
-
zip(inspect.getfullargspec(func).args, args),
|
|
43
|
-
kwargs.items(),
|
|
44
|
-
)
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
return inputs
|
|
48
|
-
|
|
49
|
-
def redact(
|
|
50
|
-
io: Dict[str, Any], ignore: Union[List[str], bool] = False
|
|
51
|
-
) -> Dict[str, Any]:
|
|
52
|
-
"""
|
|
53
|
-
Redact user-defined sensitive information from inputs and outputs as defined by the ignore list or boolean flag.
|
|
54
|
-
|
|
55
|
-
Example:
|
|
56
|
-
- ignore = ["password"] -> {"username": "admin", "password": "********"} -> {"username": "admin"}
|
|
57
|
-
- ignore = True -> {"username": "admin", "password": "********"} -> {}
|
|
58
|
-
- ignore = False -> {"username": "admin", "password": "********"} -> {"username": "admin", "password": "********"}
|
|
59
|
-
"""
|
|
60
|
-
io = {
|
|
61
|
-
key: value
|
|
62
|
-
for key, value in io.items()
|
|
63
|
-
if key
|
|
64
|
-
not in (
|
|
65
|
-
ignore
|
|
66
|
-
if isinstance(ignore, list)
|
|
67
|
-
else io.keys()
|
|
68
|
-
if ignore is True
|
|
69
|
-
else []
|
|
70
|
-
)
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
return io
|
|
74
|
-
|
|
75
|
-
def patch(result: Any) -> Dict[str, Any]:
|
|
76
|
-
"""
|
|
77
|
-
Patch the result to ensure that it is a dictionary, with a default key when necessary.
|
|
78
|
-
|
|
79
|
-
Example:
|
|
80
|
-
- result = "Hello, World!" -> {"__default__": "Hello, World!"}
|
|
81
|
-
- result = {"message": "Hello, World!", "cost": 0.0, "usage": {}} -> {"__default__": "Hello, World!"}
|
|
82
|
-
- result = {"message": "Hello, World!"} -> {"message": "Hello, World!"}
|
|
83
|
-
"""
|
|
84
|
-
outputs = (
|
|
85
|
-
{instrument.DEFAULT_KEY: result}
|
|
86
|
-
if not isinstance(result, dict)
|
|
87
|
-
else (
|
|
88
|
-
{instrument.DEFAULT_KEY: result["message"]}
|
|
89
|
-
if all(key in result for key in ["message", "cost", "usage"])
|
|
90
|
-
else result
|
|
91
|
-
)
|
|
92
|
-
)
|
|
93
|
-
|
|
94
|
-
return outputs
|
|
35
|
+
is_coroutine_function = iscoroutinefunction(func)
|
|
95
36
|
|
|
96
37
|
@wraps(func)
|
|
97
38
|
async def async_wrapper(*args, **kwargs):
|
|
98
|
-
async def
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
with ag.tracer.start_as_current_span(func.__name__, kind=kind):
|
|
105
|
-
span = ag.tracing.get_current_span()
|
|
106
|
-
|
|
107
|
-
with suppress():
|
|
108
|
-
span.set_attributes(
|
|
109
|
-
attributes={"node": self.kind},
|
|
110
|
-
namespace="type",
|
|
111
|
-
)
|
|
112
|
-
|
|
113
|
-
if span.parent is None:
|
|
114
|
-
rctx = tracing_context.get()
|
|
115
|
-
|
|
116
|
-
span.set_attributes(
|
|
117
|
-
attributes={"configuration": rctx.get("config", {})},
|
|
118
|
-
namespace="meta",
|
|
119
|
-
)
|
|
120
|
-
span.set_attributes(
|
|
121
|
-
attributes={"environment": rctx.get("environment", {})},
|
|
122
|
-
namespace="meta",
|
|
123
|
-
)
|
|
124
|
-
span.set_attributes(
|
|
125
|
-
attributes={"version": rctx.get("version", {})},
|
|
126
|
-
namespace="meta",
|
|
127
|
-
)
|
|
128
|
-
span.set_attributes(
|
|
129
|
-
attributes={"variant": rctx.get("variant", {})},
|
|
130
|
-
namespace="meta",
|
|
131
|
-
)
|
|
132
|
-
|
|
133
|
-
_inputs = redact(parse(*args, **kwargs), self.ignore_inputs)
|
|
134
|
-
span.set_attributes(
|
|
135
|
-
attributes={"inputs": _inputs},
|
|
136
|
-
namespace="data",
|
|
137
|
-
max_depth=self.max_depth,
|
|
138
|
-
)
|
|
39
|
+
async def _async_auto_instrumented(*args, **kwargs):
|
|
40
|
+
self._parse_type_and_kind()
|
|
41
|
+
|
|
42
|
+
with ag.tracer.start_as_current_span(func.__name__, kind=self.kind):
|
|
43
|
+
self._pre_instrument(self, func, *args, **kwargs)
|
|
139
44
|
|
|
140
45
|
result = await func(*args, **kwargs)
|
|
141
46
|
|
|
142
|
-
|
|
143
|
-
cost = None
|
|
144
|
-
usage = {}
|
|
145
|
-
|
|
146
|
-
if isinstance(result, dict):
|
|
147
|
-
cost = result.get("cost", None)
|
|
148
|
-
usage = result.get("usage", {})
|
|
149
|
-
|
|
150
|
-
if isinstance(usage, (int, float)):
|
|
151
|
-
usage = {"total_tokens": usage}
|
|
152
|
-
|
|
153
|
-
span.set_attributes(
|
|
154
|
-
attributes={"total": cost},
|
|
155
|
-
namespace="metrics.unit.costs",
|
|
156
|
-
)
|
|
157
|
-
span.set_attributes(
|
|
158
|
-
attributes=(
|
|
159
|
-
{
|
|
160
|
-
"prompt": usage.get("prompt_tokens", None),
|
|
161
|
-
"completion": usage.get("completion_tokens", None),
|
|
162
|
-
"total": usage.get("total_tokens", None),
|
|
163
|
-
}
|
|
164
|
-
),
|
|
165
|
-
namespace="metrics.unit.tokens",
|
|
166
|
-
)
|
|
167
|
-
|
|
168
|
-
_outputs = redact(patch(result), self.ignore_outputs)
|
|
169
|
-
span.set_attributes(
|
|
170
|
-
attributes={"outputs": _outputs},
|
|
171
|
-
namespace="data",
|
|
172
|
-
max_depth=self.max_depth,
|
|
173
|
-
)
|
|
174
|
-
|
|
175
|
-
span.set_status("OK")
|
|
176
|
-
|
|
177
|
-
with suppress():
|
|
178
|
-
if hasattr(span, "parent") and span.parent is None:
|
|
179
|
-
tracing_context.set(
|
|
180
|
-
tracing_context.get()
|
|
181
|
-
| {
|
|
182
|
-
"root": {
|
|
183
|
-
"trace_id": span.get_span_context().trace_id,
|
|
184
|
-
"span_id": span.get_span_context().span_id,
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
)
|
|
47
|
+
self._post_instrument(result)
|
|
188
48
|
|
|
189
49
|
return result
|
|
190
50
|
|
|
191
|
-
return await
|
|
51
|
+
return await _async_auto_instrumented(*args, **kwargs)
|
|
192
52
|
|
|
193
53
|
@wraps(func)
|
|
194
54
|
def sync_wrapper(*args, **kwargs):
|
|
195
|
-
def
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
with ag.tracer.start_as_current_span(func.__name__, kind=kind):
|
|
202
|
-
span = ag.tracing.get_current_span()
|
|
203
|
-
|
|
204
|
-
with suppress():
|
|
205
|
-
span.set_attributes(
|
|
206
|
-
attributes={"node": self.kind},
|
|
207
|
-
namespace="type",
|
|
208
|
-
)
|
|
209
|
-
|
|
210
|
-
if span.parent is None:
|
|
211
|
-
rctx = tracing_context.get()
|
|
212
|
-
|
|
213
|
-
span.set_attributes(
|
|
214
|
-
attributes={"configuration": rctx.get("config", {})},
|
|
215
|
-
namespace="meta",
|
|
216
|
-
)
|
|
217
|
-
span.set_attributes(
|
|
218
|
-
attributes={"environment": rctx.get("environment", {})},
|
|
219
|
-
namespace="meta",
|
|
220
|
-
)
|
|
221
|
-
span.set_attributes(
|
|
222
|
-
attributes={"version": rctx.get("version", {})},
|
|
223
|
-
namespace="meta",
|
|
224
|
-
)
|
|
225
|
-
span.set_attributes(
|
|
226
|
-
attributes={"variant": rctx.get("variant", {})},
|
|
227
|
-
namespace="meta",
|
|
228
|
-
)
|
|
229
|
-
|
|
230
|
-
_inputs = redact(parse(*args, **kwargs), self.ignore_inputs)
|
|
231
|
-
span.set_attributes(
|
|
232
|
-
attributes={"inputs": _inputs},
|
|
233
|
-
namespace="data",
|
|
234
|
-
max_depth=self.max_depth,
|
|
235
|
-
)
|
|
55
|
+
def _sync_auto_instrumented(*args, **kwargs):
|
|
56
|
+
self._parse_type_and_kind()
|
|
57
|
+
|
|
58
|
+
with ag.tracer.start_as_current_span(func.__name__, kind=self.kind):
|
|
59
|
+
self._pre_instrument(self, func, *args, **kwargs)
|
|
236
60
|
|
|
237
61
|
result = func(*args, **kwargs)
|
|
238
62
|
|
|
239
|
-
|
|
240
|
-
cost = None
|
|
241
|
-
usage = {}
|
|
242
|
-
if isinstance(result, dict):
|
|
243
|
-
cost = result.get("cost", None)
|
|
244
|
-
usage = result.get("usage", {})
|
|
245
|
-
|
|
246
|
-
if isinstance(usage, (int, float)):
|
|
247
|
-
usage = {"total_tokens": usage}
|
|
248
|
-
|
|
249
|
-
span.set_attributes(
|
|
250
|
-
attributes={"total": cost},
|
|
251
|
-
namespace="metrics.unit.costs",
|
|
252
|
-
)
|
|
253
|
-
span.set_attributes(
|
|
254
|
-
attributes=(
|
|
255
|
-
{
|
|
256
|
-
"prompt": usage.get("prompt_tokens", None),
|
|
257
|
-
"completion": usage.get("completion_tokens", None),
|
|
258
|
-
"total": usage.get("total_tokens", None),
|
|
259
|
-
}
|
|
260
|
-
),
|
|
261
|
-
namespace="metrics.unit.tokens",
|
|
262
|
-
)
|
|
263
|
-
|
|
264
|
-
_outputs = redact(patch(result), self.ignore_outputs)
|
|
265
|
-
span.set_attributes(
|
|
266
|
-
attributes={"outputs": _outputs},
|
|
267
|
-
namespace="data",
|
|
268
|
-
max_depth=self.max_depth,
|
|
269
|
-
)
|
|
270
|
-
|
|
271
|
-
span.set_status("OK")
|
|
272
|
-
|
|
273
|
-
with suppress():
|
|
274
|
-
if hasattr(span, "parent") and span.parent is None:
|
|
275
|
-
tracing_context.set(
|
|
276
|
-
tracing_context.get()
|
|
277
|
-
| {
|
|
278
|
-
"root": {
|
|
279
|
-
"trace_id": span.get_span_context().trace_id,
|
|
280
|
-
"span_id": span.get_span_context().span_id,
|
|
281
|
-
}
|
|
282
|
-
}
|
|
283
|
-
)
|
|
63
|
+
self._post_instrument(result)
|
|
284
64
|
|
|
285
65
|
return result
|
|
286
66
|
|
|
287
|
-
return
|
|
67
|
+
return _sync_auto_instrumented(*args, **kwargs)
|
|
288
68
|
|
|
289
69
|
return async_wrapper if is_coroutine_function else sync_wrapper
|
|
70
|
+
|
|
71
|
+
def _parse_type_and_kind(self):
|
|
72
|
+
if not ag.tracing.get_current_span().is_recording():
|
|
73
|
+
self.type = "workflow"
|
|
74
|
+
|
|
75
|
+
self.kind = parse_span_kind(self.type)
|
|
76
|
+
|
|
77
|
+
def _pre_instrument(
|
|
78
|
+
self,
|
|
79
|
+
func,
|
|
80
|
+
*args,
|
|
81
|
+
**kwargs,
|
|
82
|
+
):
|
|
83
|
+
span = ag.tracing.get_current_span()
|
|
84
|
+
|
|
85
|
+
with suppress():
|
|
86
|
+
span.set_attributes(
|
|
87
|
+
attributes={"node": self.type},
|
|
88
|
+
namespace="type",
|
|
89
|
+
)
|
|
90
|
+
|
|
91
|
+
if span.parent is None:
|
|
92
|
+
rctx = tracing_context.get()
|
|
93
|
+
|
|
94
|
+
span.set_attributes(
|
|
95
|
+
attributes={"configuration": rctx.get("config", {})},
|
|
96
|
+
namespace="meta",
|
|
97
|
+
)
|
|
98
|
+
span.set_attributes(
|
|
99
|
+
attributes={"environment": rctx.get("environment", {})},
|
|
100
|
+
namespace="meta",
|
|
101
|
+
)
|
|
102
|
+
span.set_attributes(
|
|
103
|
+
attributes={"version": rctx.get("version", {})},
|
|
104
|
+
namespace="meta",
|
|
105
|
+
)
|
|
106
|
+
span.set_attributes(
|
|
107
|
+
attributes={"variant": rctx.get("variant", {})},
|
|
108
|
+
namespace="meta",
|
|
109
|
+
)
|
|
110
|
+
|
|
111
|
+
_inputs = self._redact(
|
|
112
|
+
self._parse(
|
|
113
|
+
func,
|
|
114
|
+
*args,
|
|
115
|
+
**kwargs,
|
|
116
|
+
),
|
|
117
|
+
self.ignore_inputs,
|
|
118
|
+
)
|
|
119
|
+
span.set_attributes(
|
|
120
|
+
attributes={"inputs": _inputs},
|
|
121
|
+
namespace="data",
|
|
122
|
+
max_depth=self.max_depth,
|
|
123
|
+
)
|
|
124
|
+
|
|
125
|
+
def _post_instrument(
|
|
126
|
+
self,
|
|
127
|
+
result,
|
|
128
|
+
):
|
|
129
|
+
span = ag.tracing.get_current_span()
|
|
130
|
+
with suppress():
|
|
131
|
+
cost = None
|
|
132
|
+
usage = {}
|
|
133
|
+
|
|
134
|
+
if isinstance(result, dict):
|
|
135
|
+
cost = result.get("cost", None)
|
|
136
|
+
usage = result.get("usage", {})
|
|
137
|
+
|
|
138
|
+
if isinstance(usage, (int, float)):
|
|
139
|
+
usage = {"total_tokens": usage}
|
|
140
|
+
|
|
141
|
+
span.set_attributes(
|
|
142
|
+
attributes={"total": cost},
|
|
143
|
+
namespace="metrics.unit.costs",
|
|
144
|
+
)
|
|
145
|
+
span.set_attributes(
|
|
146
|
+
attributes=(
|
|
147
|
+
{
|
|
148
|
+
"prompt": usage.get("prompt_tokens", None),
|
|
149
|
+
"completion": usage.get("completion_tokens", None),
|
|
150
|
+
"total": usage.get("total_tokens", None),
|
|
151
|
+
}
|
|
152
|
+
),
|
|
153
|
+
namespace="metrics.unit.tokens",
|
|
154
|
+
)
|
|
155
|
+
|
|
156
|
+
_outputs = self._redact(self._patch(result), self.ignore_outputs)
|
|
157
|
+
span.set_attributes(
|
|
158
|
+
attributes={"outputs": _outputs},
|
|
159
|
+
namespace="data",
|
|
160
|
+
max_depth=self.max_depth,
|
|
161
|
+
)
|
|
162
|
+
|
|
163
|
+
span.set_status("OK")
|
|
164
|
+
|
|
165
|
+
with suppress():
|
|
166
|
+
if hasattr(span, "parent") and span.parent is None:
|
|
167
|
+
tracing_context.set(
|
|
168
|
+
tracing_context.get()
|
|
169
|
+
| {
|
|
170
|
+
"root": {
|
|
171
|
+
"trace_id": span.get_span_context().trace_id,
|
|
172
|
+
"span_id": span.get_span_context().span_id,
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
)
|
|
176
|
+
|
|
177
|
+
def _parse(
|
|
178
|
+
self,
|
|
179
|
+
func,
|
|
180
|
+
*args,
|
|
181
|
+
**kwargs,
|
|
182
|
+
) -> Dict[str, Any]:
|
|
183
|
+
inputs = {
|
|
184
|
+
key: value
|
|
185
|
+
for key, value in chain(
|
|
186
|
+
zip(getfullargspec(func).args, args),
|
|
187
|
+
kwargs.items(),
|
|
188
|
+
)
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
return inputs
|
|
192
|
+
|
|
193
|
+
def _redact(
|
|
194
|
+
self,
|
|
195
|
+
io: Dict[str, Any],
|
|
196
|
+
ignore: Union[List[str], bool] = False,
|
|
197
|
+
) -> Dict[str, Any]:
|
|
198
|
+
"""
|
|
199
|
+
Redact user-defined sensitive information from inputs and outputs as defined by the ignore list or boolean flag.
|
|
200
|
+
|
|
201
|
+
Example:
|
|
202
|
+
- ignore = ["password"] -> {"username": "admin", "password": "********"} -> {"username": "admin"}
|
|
203
|
+
- ignore = True -> {"username": "admin", "password": "********"} -> {}
|
|
204
|
+
- ignore = False -> {"username": "admin", "password": "********"} -> {"username": "admin", "password": "********"}
|
|
205
|
+
"""
|
|
206
|
+
io = {
|
|
207
|
+
key: value
|
|
208
|
+
for key, value in io.items()
|
|
209
|
+
if key
|
|
210
|
+
not in (
|
|
211
|
+
ignore
|
|
212
|
+
if isinstance(ignore, list)
|
|
213
|
+
else io.keys() if ignore is True else []
|
|
214
|
+
)
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
return io
|
|
218
|
+
|
|
219
|
+
def _patch(
|
|
220
|
+
self,
|
|
221
|
+
result: Any,
|
|
222
|
+
) -> Dict[str, Any]:
|
|
223
|
+
"""
|
|
224
|
+
Patch the result to ensure that it is a dictionary, with a default key when necessary.
|
|
225
|
+
|
|
226
|
+
Example:
|
|
227
|
+
- result = "Hello, World!" -> {"__default__": "Hello, World!"}
|
|
228
|
+
- result = {"message": "Hello, World!", "cost": 0.0, "usage": {}} -> {"__default__": "Hello, World!"}
|
|
229
|
+
- result = {"message": "Hello, World!"} -> {"message": "Hello, World!"}
|
|
230
|
+
"""
|
|
231
|
+
outputs = (
|
|
232
|
+
{instrument.DEFAULT_KEY: result}
|
|
233
|
+
if not isinstance(result, dict)
|
|
234
|
+
else (
|
|
235
|
+
{instrument.DEFAULT_KEY: result["message"]}
|
|
236
|
+
if all(key in result for key in ["message", "cost", "usage"])
|
|
237
|
+
else result
|
|
238
|
+
)
|
|
239
|
+
)
|
|
240
|
+
|
|
241
|
+
return outputs
|
agenta/sdk/tracing/attributes.py
CHANGED
|
@@ -93,14 +93,19 @@ def _marshal(
|
|
|
93
93
|
return marshalled
|
|
94
94
|
|
|
95
95
|
|
|
96
|
-
def _encode_key(
|
|
96
|
+
def _encode_key(
|
|
97
|
+
namespace: Optional[str] = None,
|
|
98
|
+
key: str = "",
|
|
99
|
+
) -> str:
|
|
97
100
|
if namespace is None:
|
|
98
101
|
return key
|
|
99
102
|
|
|
100
103
|
return f"ag.{namespace}.{key}"
|
|
101
104
|
|
|
102
105
|
|
|
103
|
-
def _encode_value(
|
|
106
|
+
def _encode_value(
|
|
107
|
+
value: Any,
|
|
108
|
+
) -> Optional[Attribute]:
|
|
104
109
|
if value is None:
|
|
105
110
|
return None
|
|
106
111
|
|
agenta/sdk/tracing/context.py
CHANGED
|
@@ -15,7 +15,10 @@ def tracing_context_manager():
|
|
|
15
15
|
try:
|
|
16
16
|
yield
|
|
17
17
|
except Exception as e:
|
|
18
|
-
log.error(
|
|
19
|
-
log.error(
|
|
18
|
+
log.error("----------------------------------------------")
|
|
19
|
+
log.error("Agenta SDK - handling tracing exception below:")
|
|
20
|
+
log.error("----------------------------------------------")
|
|
21
|
+
log.error(format_exc().strip("\n"))
|
|
22
|
+
log.error("----------------------------------------------")
|
|
20
23
|
finally:
|
|
21
24
|
tracing_context.reset(token)
|
|
@@ -1,14 +1,7 @@
|
|
|
1
|
-
from opentelemetry.trace import SpanKind
|
|
2
|
-
|
|
3
1
|
from enum import Enum
|
|
4
|
-
|
|
5
2
|
from re import fullmatch
|
|
6
3
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
def is_valid_attribute_key(string):
|
|
11
|
-
return bool(fullmatch(_PATTERN, string))
|
|
4
|
+
from opentelemetry.trace import SpanKind
|
|
12
5
|
|
|
13
6
|
|
|
14
7
|
class Reference(str, Enum):
|
|
@@ -26,6 +19,15 @@ class Reference(str, Enum):
|
|
|
26
19
|
#
|
|
27
20
|
|
|
28
21
|
|
|
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
|
+
|
|
29
31
|
def parse_span_kind(type: str) -> SpanKind:
|
|
30
32
|
kind = SpanKind.INTERNAL
|
|
31
33
|
if type in [
|
agenta/sdk/tracing/exporters.py
CHANGED
|
@@ -1,14 +1,12 @@
|
|
|
1
1
|
from typing import Sequence, Dict, List
|
|
2
2
|
|
|
3
|
+
from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter
|
|
3
4
|
from opentelemetry.sdk.trace.export import (
|
|
4
5
|
ConsoleSpanExporter,
|
|
5
6
|
SpanExporter,
|
|
6
7
|
SpanExportResult,
|
|
7
8
|
ReadableSpan,
|
|
8
9
|
)
|
|
9
|
-
from opentelemetry.exporter.otlp.proto.http.trace_exporter import (
|
|
10
|
-
OTLPSpanExporter,
|
|
11
|
-
)
|
|
12
10
|
|
|
13
11
|
from agenta.sdk.utils.exceptions import suppress
|
|
14
12
|
|
|
@@ -40,7 +38,10 @@ class InlineTraceExporter(SpanExporter):
|
|
|
40
38
|
def force_flush(self, timeout_millis: int = 30000) -> bool:
|
|
41
39
|
return True
|
|
42
40
|
|
|
43
|
-
def fetch(
|
|
41
|
+
def fetch(
|
|
42
|
+
self,
|
|
43
|
+
trace_id: int,
|
|
44
|
+
) -> List[ReadableSpan]:
|
|
44
45
|
trace = self._registry.get(trace_id, [])
|
|
45
46
|
|
|
46
47
|
del self._registry[trace_id]
|
|
@@ -50,7 +51,6 @@ class InlineTraceExporter(SpanExporter):
|
|
|
50
51
|
|
|
51
52
|
OTLPSpanExporter._MAX_RETRY_TIMEOUT = 2
|
|
52
53
|
|
|
53
|
-
|
|
54
54
|
ConsoleExporter = ConsoleSpanExporter
|
|
55
55
|
InlineExporter = InlineTraceExporter
|
|
56
56
|
OTLPExporter = OTLPSpanExporter
|