agenta 0.12.2__py3-none-any.whl → 0.32.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 +64 -7
- agenta/cli/helper.py +7 -3
- agenta/cli/main.py +15 -50
- agenta/cli/variant_commands.py +50 -29
- agenta/client/Readme.md +72 -64
- agenta/client/api.py +2 -2
- agenta/client/backend/__init__.py +193 -22
- agenta/client/backend/access_control/__init__.py +1 -0
- agenta/client/backend/access_control/client.py +167 -0
- agenta/client/backend/apps/__init__.py +1 -0
- agenta/client/backend/apps/client.py +1691 -0
- agenta/client/backend/bases/__init__.py +1 -0
- agenta/client/backend/bases/client.py +190 -0
- agenta/client/backend/client.py +2508 -5712
- agenta/client/backend/configs/__init__.py +1 -0
- agenta/client/backend/configs/client.py +604 -0
- agenta/client/backend/containers/__init__.py +5 -0
- agenta/client/backend/containers/client.py +648 -0
- agenta/client/backend/containers/types/__init__.py +5 -0
- agenta/client/backend/{types → containers/types}/container_templates_response.py +1 -2
- agenta/client/backend/core/__init__.py +30 -0
- agenta/client/backend/core/client_wrapper.py +42 -9
- agenta/client/backend/core/file.py +70 -0
- agenta/client/backend/core/http_client.py +575 -0
- agenta/client/backend/core/jsonable_encoder.py +33 -39
- agenta/client/backend/core/pydantic_utilities.py +325 -0
- agenta/client/backend/core/query_encoder.py +60 -0
- agenta/client/backend/core/remove_none_from_dict.py +2 -2
- agenta/client/backend/core/request_options.py +35 -0
- agenta/client/backend/core/serialization.py +276 -0
- agenta/client/backend/environments/__init__.py +1 -0
- agenta/client/backend/environments/client.py +196 -0
- agenta/client/backend/evaluations/__init__.py +1 -0
- agenta/client/backend/evaluations/client.py +1469 -0
- agenta/client/backend/evaluators/__init__.py +1 -0
- agenta/client/backend/evaluators/client.py +1283 -0
- agenta/client/backend/observability/__init__.py +1 -0
- agenta/client/backend/observability/client.py +1286 -0
- agenta/client/backend/observability_v_1/__init__.py +5 -0
- agenta/client/backend/observability_v_1/client.py +763 -0
- agenta/client/backend/observability_v_1/types/__init__.py +7 -0
- agenta/client/backend/observability_v_1/types/format.py +5 -0
- agenta/client/backend/observability_v_1/types/query_analytics_response.py +7 -0
- agenta/client/backend/observability_v_1/types/query_traces_response.py +11 -0
- agenta/client/backend/scopes/__init__.py +1 -0
- agenta/client/backend/scopes/client.py +114 -0
- agenta/client/backend/testsets/__init__.py +1 -0
- agenta/client/backend/testsets/client.py +1284 -0
- agenta/client/backend/types/__init__.py +154 -26
- agenta/client/backend/types/agenta_node_dto.py +48 -0
- agenta/client/backend/types/agenta_node_dto_nodes_value.py +6 -0
- agenta/client/backend/types/agenta_nodes_response.py +30 -0
- agenta/client/backend/types/agenta_root_dto.py +30 -0
- agenta/client/backend/types/agenta_roots_response.py +30 -0
- agenta/client/backend/types/agenta_tree_dto.py +30 -0
- agenta/client/backend/types/agenta_trees_response.py +30 -0
- agenta/client/backend/types/aggregated_result.py +16 -31
- agenta/client/backend/types/aggregated_result_evaluator_config.py +8 -0
- agenta/client/backend/types/analytics_response.py +24 -0
- agenta/client/backend/types/app.py +17 -30
- agenta/client/backend/types/app_variant_response.py +36 -0
- agenta/client/backend/types/app_variant_revision.py +17 -32
- agenta/client/backend/types/base_output.py +13 -28
- agenta/client/backend/types/body_import_testset.py +15 -31
- agenta/client/backend/types/bucket_dto.py +26 -0
- agenta/client/backend/types/collect_status_response.py +22 -0
- agenta/client/backend/types/config_db.py +16 -31
- agenta/client/backend/types/config_dto.py +32 -0
- agenta/client/backend/types/config_response_model.py +32 -0
- agenta/client/backend/types/correct_answer.py +22 -0
- agenta/client/backend/types/create_app_output.py +13 -28
- agenta/client/backend/types/create_span.py +45 -0
- agenta/client/backend/types/create_trace_response.py +22 -0
- agenta/client/backend/types/docker_env_vars.py +13 -28
- agenta/client/backend/types/environment_output.py +22 -34
- agenta/client/backend/types/environment_output_extended.py +31 -0
- agenta/client/backend/types/environment_revision.py +26 -0
- agenta/client/backend/types/error.py +22 -0
- agenta/client/backend/types/evaluation.py +22 -33
- agenta/client/backend/types/evaluation_scenario.py +18 -33
- agenta/client/backend/types/evaluation_scenario_input.py +16 -31
- agenta/client/backend/types/evaluation_scenario_output.py +17 -30
- agenta/client/backend/types/evaluation_scenario_result.py +14 -29
- agenta/client/backend/types/evaluation_scenario_score_update.py +21 -0
- agenta/client/backend/types/evaluation_status_enum.py +11 -29
- agenta/client/backend/types/evaluation_type.py +3 -21
- agenta/client/backend/types/evaluator.py +20 -31
- agenta/client/backend/types/evaluator_config.py +21 -33
- agenta/client/backend/types/evaluator_mapping_output_interface.py +21 -0
- agenta/client/backend/types/evaluator_output_interface.py +21 -0
- agenta/client/backend/types/exception_dto.py +26 -0
- agenta/client/backend/types/get_config_response.py +23 -0
- agenta/client/backend/types/header_dto.py +22 -0
- agenta/client/backend/types/http_validation_error.py +14 -29
- agenta/client/backend/types/human_evaluation.py +18 -34
- agenta/client/backend/types/human_evaluation_scenario.py +22 -38
- agenta/client/backend/types/human_evaluation_scenario_input.py +13 -28
- agenta/client/backend/types/human_evaluation_scenario_output.py +13 -28
- agenta/client/backend/types/human_evaluation_scenario_update.py +30 -0
- agenta/client/backend/types/human_evaluation_update.py +22 -0
- agenta/client/backend/types/image.py +18 -32
- agenta/client/backend/types/invite_request.py +16 -30
- agenta/client/backend/types/legacy_analytics_response.py +29 -0
- agenta/client/backend/types/legacy_data_point.py +27 -0
- agenta/client/backend/types/lifecycle_dto.py +24 -0
- agenta/client/backend/types/link_dto.py +24 -0
- agenta/client/backend/types/list_api_keys_response.py +24 -0
- agenta/client/backend/types/llm_run_rate_limit.py +13 -28
- agenta/client/backend/types/llm_tokens.py +23 -0
- agenta/client/backend/types/metrics_dto.py +24 -0
- agenta/client/backend/types/new_human_evaluation.py +27 -0
- agenta/client/backend/types/new_testset.py +16 -31
- agenta/client/backend/types/node_dto.py +24 -0
- agenta/client/backend/types/node_type.py +19 -0
- agenta/client/backend/types/o_tel_context_dto.py +22 -0
- agenta/client/backend/types/o_tel_event_dto.py +23 -0
- agenta/client/backend/types/o_tel_extra_dto.py +26 -0
- agenta/client/backend/types/o_tel_link_dto.py +23 -0
- agenta/client/backend/types/o_tel_span_dto.py +37 -0
- agenta/client/backend/types/o_tel_span_kind.py +15 -0
- agenta/client/backend/types/o_tel_spans_response.py +24 -0
- agenta/client/backend/types/o_tel_status_code.py +8 -0
- agenta/client/backend/types/organization.py +22 -35
- agenta/client/backend/types/organization_output.py +13 -28
- agenta/client/backend/types/outputs.py +5 -0
- agenta/client/backend/types/parent_dto.py +21 -0
- agenta/client/backend/types/permission.py +41 -0
- agenta/client/backend/types/projects_response.py +28 -0
- agenta/client/backend/types/provider_key_dto.py +23 -0
- agenta/client/backend/types/provider_kind.py +21 -0
- agenta/client/backend/types/reference_dto.py +23 -0
- agenta/client/backend/types/reference_request_model.py +23 -0
- agenta/client/backend/types/result.py +18 -31
- agenta/client/backend/types/root_dto.py +21 -0
- agenta/client/backend/types/{human_evaluation_scenario_score.py → score.py} +1 -1
- agenta/client/backend/types/secret_dto.py +24 -0
- agenta/client/backend/types/{human_evaluation_scenario_update_score.py → secret_kind.py} +1 -1
- agenta/client/backend/types/secret_response_dto.py +27 -0
- agenta/client/backend/types/simple_evaluation_output.py +13 -28
- agenta/client/backend/types/span.py +39 -49
- agenta/client/backend/types/span_detail.py +44 -0
- agenta/client/backend/types/span_dto.py +54 -0
- agenta/client/backend/types/span_dto_nodes_value.py +9 -0
- agenta/client/backend/types/span_status_code.py +5 -0
- agenta/client/backend/types/span_variant.py +23 -0
- agenta/client/backend/types/status_code.py +5 -0
- agenta/client/backend/types/status_dto.py +23 -0
- agenta/client/backend/types/template.py +14 -29
- agenta/client/backend/types/template_image_info.py +21 -35
- agenta/client/backend/types/test_set_output_response.py +20 -33
- agenta/client/backend/types/test_set_simple_response.py +13 -28
- agenta/client/backend/types/time_dto.py +23 -0
- agenta/client/backend/types/trace_detail.py +44 -0
- agenta/client/backend/types/tree_dto.py +23 -0
- agenta/client/backend/types/tree_type.py +5 -0
- agenta/client/backend/types/update_app_output.py +22 -0
- agenta/client/backend/types/uri.py +13 -28
- agenta/client/backend/types/validation_error.py +13 -28
- agenta/client/backend/types/variant_action.py +14 -29
- agenta/client/backend/types/variant_action_enum.py +1 -19
- agenta/client/backend/types/with_pagination.py +26 -0
- agenta/client/backend/types/workspace_member_response.py +23 -0
- agenta/client/backend/types/workspace_permission.py +25 -0
- agenta/client/backend/types/workspace_response.py +29 -0
- agenta/client/backend/types/workspace_role.py +15 -0
- agenta/client/backend/types/workspace_role_response.py +23 -0
- agenta/client/backend/variants/__init__.py +5 -0
- agenta/client/backend/variants/client.py +2814 -0
- agenta/client/backend/variants/types/__init__.py +7 -0
- agenta/client/backend/variants/types/add_variant_from_base_and_config_response.py +8 -0
- agenta/client/backend/vault/__init__.py +1 -0
- agenta/client/backend/vault/client.py +685 -0
- agenta/client/client.py +1 -1
- agenta/config.py +0 -2
- agenta/config.toml +0 -1
- agenta/docker/docker-assets/Dockerfile.cloud.template +2 -1
- agenta/docker/docker-assets/Dockerfile.template +2 -1
- agenta/docker/docker_utils.py +11 -12
- agenta/sdk/__init__.py +58 -7
- agenta/sdk/agenta_init.py +182 -164
- agenta/sdk/assets.py +95 -0
- agenta/sdk/client.py +56 -0
- agenta/sdk/context/__init__.py +0 -0
- agenta/sdk/context/exporting.py +25 -0
- agenta/sdk/context/routing.py +27 -0
- agenta/sdk/context/tracing.py +28 -0
- agenta/sdk/decorators/__init__.py +0 -0
- agenta/sdk/decorators/routing.py +576 -0
- agenta/sdk/decorators/tracing.py +296 -0
- agenta/sdk/litellm/__init__.py +1 -0
- agenta/sdk/litellm/litellm.py +314 -0
- agenta/sdk/litellm/mockllm.py +27 -0
- agenta/sdk/litellm/mocks/__init__.py +26 -0
- agenta/sdk/managers/__init__.py +6 -0
- agenta/sdk/managers/config.py +208 -0
- agenta/sdk/managers/deployment.py +45 -0
- agenta/sdk/managers/secrets.py +38 -0
- agenta/sdk/managers/shared.py +639 -0
- agenta/sdk/managers/variant.py +182 -0
- agenta/sdk/managers/vault.py +16 -0
- agenta/sdk/middleware/__init__.py +0 -0
- agenta/sdk/middleware/auth.py +180 -0
- agenta/sdk/middleware/cache.py +47 -0
- agenta/sdk/middleware/config.py +255 -0
- agenta/sdk/middleware/cors.py +29 -0
- agenta/sdk/middleware/inline.py +38 -0
- agenta/sdk/middleware/mock.py +33 -0
- agenta/sdk/middleware/otel.py +40 -0
- agenta/sdk/middleware/vault.py +145 -0
- agenta/sdk/router.py +0 -7
- agenta/sdk/tracing/__init__.py +1 -0
- agenta/sdk/tracing/attributes.py +141 -0
- agenta/sdk/tracing/conventions.py +49 -0
- agenta/sdk/tracing/exporters.py +103 -0
- agenta/sdk/tracing/inline.py +1146 -0
- agenta/sdk/tracing/processors.py +121 -0
- agenta/sdk/tracing/spans.py +136 -0
- agenta/sdk/tracing/tracing.py +237 -0
- agenta/sdk/types.py +478 -74
- agenta/sdk/utils/__init__.py +0 -0
- agenta/sdk/utils/constants.py +1 -0
- agenta/sdk/utils/{helper/openai_cost.py → costs.py} +3 -0
- agenta/sdk/utils/exceptions.py +59 -0
- agenta/sdk/utils/globals.py +6 -10
- agenta/sdk/utils/helpers.py +8 -0
- agenta/sdk/utils/logging.py +21 -0
- agenta/sdk/utils/singleton.py +13 -0
- agenta/sdk/utils/timing.py +58 -0
- {agenta-0.12.2.dist-info → agenta-0.32.0a1.dist-info}/METADATA +98 -151
- agenta-0.32.0a1.dist-info/RECORD +263 -0
- {agenta-0.12.2.dist-info → agenta-0.32.0a1.dist-info}/WHEEL +1 -1
- agenta/client/backend/types/add_variant_from_base_and_config_response.py +0 -7
- agenta/client/backend/types/app_variant_output.py +0 -47
- agenta/client/backend/types/app_variant_output_extended.py +0 -50
- agenta/client/backend/types/delete_evaluation.py +0 -36
- agenta/client/backend/types/evaluation_webhook.py +0 -36
- agenta/client/backend/types/feedback.py +0 -40
- agenta/client/backend/types/get_config_reponse.py +0 -39
- agenta/client/backend/types/list_api_keys_output.py +0 -39
- agenta/client/backend/types/trace.py +0 -48
- agenta/sdk/agenta_decorator.py +0 -443
- agenta/sdk/context.py +0 -41
- agenta-0.12.2.dist-info/RECORD +0 -114
- {agenta-0.12.2.dist-info → agenta-0.32.0a1.dist-info}/entry_points.txt +0 -0
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
from typing import Optional, Dict, List
|
|
2
|
+
|
|
3
|
+
from opentelemetry.baggage import get_all as get_baggage
|
|
4
|
+
from opentelemetry.context import Context
|
|
5
|
+
from opentelemetry.sdk.trace import Span
|
|
6
|
+
from opentelemetry.sdk.trace.export import (
|
|
7
|
+
SpanExporter,
|
|
8
|
+
ReadableSpan,
|
|
9
|
+
BatchSpanProcessor,
|
|
10
|
+
_DEFAULT_MAX_QUEUE_SIZE,
|
|
11
|
+
_DEFAULT_MAX_EXPORT_BATCH_SIZE,
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
from agenta.sdk.utils.logging import log
|
|
15
|
+
from agenta.sdk.tracing.conventions import Reference
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class TraceProcessor(BatchSpanProcessor):
|
|
19
|
+
def __init__(
|
|
20
|
+
self,
|
|
21
|
+
span_exporter: SpanExporter,
|
|
22
|
+
references: Dict[str, str] = None,
|
|
23
|
+
max_queue_size: int = None,
|
|
24
|
+
schedule_delay_millis: float = None,
|
|
25
|
+
max_export_batch_size: int = None,
|
|
26
|
+
export_timeout_millis: float = None,
|
|
27
|
+
):
|
|
28
|
+
super().__init__(
|
|
29
|
+
span_exporter,
|
|
30
|
+
_DEFAULT_MAX_QUEUE_SIZE,
|
|
31
|
+
12 * 60 * 60 * 1000, # 12 hours
|
|
32
|
+
_DEFAULT_MAX_EXPORT_BATCH_SIZE,
|
|
33
|
+
500, # < 1 second (0.5 seconds)
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
self._registry = dict()
|
|
37
|
+
self._exporter = span_exporter
|
|
38
|
+
self.references = references or dict()
|
|
39
|
+
self.spans: Dict[int, List[ReadableSpan]] = dict()
|
|
40
|
+
|
|
41
|
+
def on_start(
|
|
42
|
+
self,
|
|
43
|
+
span: Span,
|
|
44
|
+
parent_context: Optional[Context] = None,
|
|
45
|
+
) -> None:
|
|
46
|
+
baggage = get_baggage(parent_context)
|
|
47
|
+
|
|
48
|
+
for key in self.references.keys():
|
|
49
|
+
span.set_attribute(f"ag.refs.{key}", self.references[key])
|
|
50
|
+
|
|
51
|
+
for key in baggage.keys():
|
|
52
|
+
if key.startswith("ag.refs."):
|
|
53
|
+
_key = key.replace("ag.refs.", "")
|
|
54
|
+
if _key in [_.value for _ in Reference.__members__.values()]:
|
|
55
|
+
span.set_attribute(key, baggage[key])
|
|
56
|
+
|
|
57
|
+
if span.context.trace_id not in self._registry:
|
|
58
|
+
self._registry[span.context.trace_id] = dict()
|
|
59
|
+
|
|
60
|
+
self._registry[span.context.trace_id][span.context.span_id] = True
|
|
61
|
+
|
|
62
|
+
def on_end(
|
|
63
|
+
self,
|
|
64
|
+
span: ReadableSpan,
|
|
65
|
+
):
|
|
66
|
+
if self.done:
|
|
67
|
+
return
|
|
68
|
+
|
|
69
|
+
if span.context.trace_id not in self.spans:
|
|
70
|
+
self.spans[span.context.trace_id] = list()
|
|
71
|
+
|
|
72
|
+
self.spans[span.context.trace_id].append(span)
|
|
73
|
+
|
|
74
|
+
del self._registry[span.context.trace_id][span.context.span_id]
|
|
75
|
+
|
|
76
|
+
if len(self._registry[span.context.trace_id]) == 0:
|
|
77
|
+
self.export(span.context.trace_id)
|
|
78
|
+
|
|
79
|
+
def export(
|
|
80
|
+
self,
|
|
81
|
+
trace_id: int,
|
|
82
|
+
):
|
|
83
|
+
spans = self.spans[trace_id]
|
|
84
|
+
|
|
85
|
+
for span in spans:
|
|
86
|
+
self.queue.appendleft(span)
|
|
87
|
+
|
|
88
|
+
with self.condition:
|
|
89
|
+
self.condition.notify()
|
|
90
|
+
|
|
91
|
+
del self.spans[trace_id]
|
|
92
|
+
|
|
93
|
+
def force_flush(
|
|
94
|
+
self,
|
|
95
|
+
timeout_millis: int = None,
|
|
96
|
+
) -> bool:
|
|
97
|
+
ret = super().force_flush(timeout_millis)
|
|
98
|
+
|
|
99
|
+
if not ret:
|
|
100
|
+
log.warning("Agenta - Skipping export due to timeout.")
|
|
101
|
+
|
|
102
|
+
def is_ready(
|
|
103
|
+
self,
|
|
104
|
+
trace_id: Optional[int] = None,
|
|
105
|
+
) -> bool:
|
|
106
|
+
is_ready = True
|
|
107
|
+
|
|
108
|
+
try:
|
|
109
|
+
is_ready = self._exporter.is_ready(trace_id)
|
|
110
|
+
except: # pylint: disable=bare-except
|
|
111
|
+
pass
|
|
112
|
+
|
|
113
|
+
return is_ready
|
|
114
|
+
|
|
115
|
+
def fetch(
|
|
116
|
+
self,
|
|
117
|
+
trace_id: Optional[int] = None,
|
|
118
|
+
) -> Dict[str, ReadableSpan]:
|
|
119
|
+
trace = self._exporter.fetch(trace_id) # type: ignore
|
|
120
|
+
|
|
121
|
+
return trace
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
from typing import Optional, Union, Any, Dict
|
|
2
|
+
|
|
3
|
+
from opentelemetry.trace import SpanContext
|
|
4
|
+
from opentelemetry.trace.status import Status, StatusCode
|
|
5
|
+
from opentelemetry.sdk.trace import Span
|
|
6
|
+
|
|
7
|
+
from agenta.sdk.tracing.attributes import serialize
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class CustomSpan(Span): # INHERITANCE FOR TYPING ONLY
|
|
11
|
+
def __init__(
|
|
12
|
+
self,
|
|
13
|
+
span: Span,
|
|
14
|
+
) -> None:
|
|
15
|
+
super().__init__( # INHERITANCE FOR TYPING ONLY
|
|
16
|
+
name=span.name,
|
|
17
|
+
context=span.context,
|
|
18
|
+
parent=span.parent,
|
|
19
|
+
sampler=span._sampler,
|
|
20
|
+
trace_config=span._trace_config,
|
|
21
|
+
resource=span.resource,
|
|
22
|
+
attributes=span.attributes,
|
|
23
|
+
events=span.events,
|
|
24
|
+
links=span.links,
|
|
25
|
+
kind=span.kind,
|
|
26
|
+
span_processor=span._span_processor,
|
|
27
|
+
instrumentation_info=span.instrumentation_info,
|
|
28
|
+
record_exception=span._record_exception,
|
|
29
|
+
set_status_on_exception=span._set_status_on_exception,
|
|
30
|
+
limits=span._limits,
|
|
31
|
+
instrumentation_scope=span.instrumentation_scope,
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
self._span = span
|
|
35
|
+
|
|
36
|
+
## --- PROXY METHODS --- ##
|
|
37
|
+
|
|
38
|
+
def get_span_context(self):
|
|
39
|
+
return self._span.get_span_context()
|
|
40
|
+
|
|
41
|
+
def is_recording(self) -> bool:
|
|
42
|
+
return self._span.is_recording()
|
|
43
|
+
|
|
44
|
+
def update_name(
|
|
45
|
+
self,
|
|
46
|
+
name: str,
|
|
47
|
+
) -> None:
|
|
48
|
+
self._span.update_name(name)
|
|
49
|
+
|
|
50
|
+
def set_status(
|
|
51
|
+
self,
|
|
52
|
+
status: Union[Status, StatusCode],
|
|
53
|
+
description: Optional[str] = None,
|
|
54
|
+
) -> None:
|
|
55
|
+
self._span.set_status(
|
|
56
|
+
status=status,
|
|
57
|
+
description=description,
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
def end(self) -> None:
|
|
61
|
+
self._span.end()
|
|
62
|
+
|
|
63
|
+
## --- CUSTOM METHODS W/ ATTRIBUTES SERALIZATION --- ##
|
|
64
|
+
|
|
65
|
+
def set_attributes(
|
|
66
|
+
self,
|
|
67
|
+
attributes: Dict[str, Any],
|
|
68
|
+
namespace: Optional[str] = None,
|
|
69
|
+
max_depth: Optional[int] = None,
|
|
70
|
+
) -> None:
|
|
71
|
+
self._span.set_attributes(
|
|
72
|
+
attributes=serialize(
|
|
73
|
+
namespace=namespace,
|
|
74
|
+
attributes=attributes,
|
|
75
|
+
max_depth=max_depth,
|
|
76
|
+
)
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
def set_attribute(
|
|
80
|
+
self,
|
|
81
|
+
key: str,
|
|
82
|
+
value: Any,
|
|
83
|
+
namespace: Optional[str] = None,
|
|
84
|
+
) -> None:
|
|
85
|
+
self.set_attributes(
|
|
86
|
+
attributes={key: value},
|
|
87
|
+
namespace=namespace,
|
|
88
|
+
)
|
|
89
|
+
|
|
90
|
+
def add_event(
|
|
91
|
+
self,
|
|
92
|
+
name: str,
|
|
93
|
+
attributes: Optional[Dict[str, Any]] = None,
|
|
94
|
+
timestamp: Optional[int] = None,
|
|
95
|
+
namespace: Optional[str] = None,
|
|
96
|
+
) -> None:
|
|
97
|
+
self._span.add_event(
|
|
98
|
+
name=name,
|
|
99
|
+
attributes=serialize(
|
|
100
|
+
namespace=namespace,
|
|
101
|
+
attributes=attributes,
|
|
102
|
+
),
|
|
103
|
+
timestamp=timestamp,
|
|
104
|
+
)
|
|
105
|
+
|
|
106
|
+
def add_link(
|
|
107
|
+
self,
|
|
108
|
+
context: SpanContext,
|
|
109
|
+
attributes: Optional[Dict[str, Any]] = None,
|
|
110
|
+
namespace: Optional[str] = None,
|
|
111
|
+
) -> None:
|
|
112
|
+
self._span.add_link(
|
|
113
|
+
context=context,
|
|
114
|
+
attributes=serialize(
|
|
115
|
+
namespace=namespace,
|
|
116
|
+
attributes=attributes,
|
|
117
|
+
),
|
|
118
|
+
)
|
|
119
|
+
|
|
120
|
+
def record_exception(
|
|
121
|
+
self,
|
|
122
|
+
exception: BaseException,
|
|
123
|
+
attributes: Optional[Dict[str, Any]] = None,
|
|
124
|
+
timestamp: Optional[int] = None,
|
|
125
|
+
escaped: bool = False,
|
|
126
|
+
namespace: Optional[str] = None,
|
|
127
|
+
) -> None:
|
|
128
|
+
self._span.record_exception(
|
|
129
|
+
exception=exception,
|
|
130
|
+
attributes=serialize(
|
|
131
|
+
namespace=namespace,
|
|
132
|
+
attributes=attributes,
|
|
133
|
+
),
|
|
134
|
+
timestamp=timestamp,
|
|
135
|
+
escaped=escaped,
|
|
136
|
+
)
|
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
from typing import Optional, Any, Dict, Callable
|
|
2
|
+
from enum import Enum
|
|
3
|
+
|
|
4
|
+
from httpx import get as check
|
|
5
|
+
|
|
6
|
+
from opentelemetry.trace import (
|
|
7
|
+
get_current_span,
|
|
8
|
+
set_tracer_provider,
|
|
9
|
+
get_tracer_provider,
|
|
10
|
+
Status,
|
|
11
|
+
StatusCode,
|
|
12
|
+
)
|
|
13
|
+
from opentelemetry.sdk.trace import Span, Tracer, TracerProvider
|
|
14
|
+
from opentelemetry.sdk.resources import Resource
|
|
15
|
+
|
|
16
|
+
from agenta.sdk.utils.singleton import Singleton
|
|
17
|
+
from agenta.sdk.utils.exceptions import suppress
|
|
18
|
+
from agenta.sdk.utils.logging import log
|
|
19
|
+
from agenta.sdk.tracing.processors import TraceProcessor
|
|
20
|
+
from agenta.sdk.tracing.exporters import InlineExporter, OTLPExporter
|
|
21
|
+
from agenta.sdk.tracing.spans import CustomSpan
|
|
22
|
+
from agenta.sdk.tracing.inline import parse_inline_trace
|
|
23
|
+
from agenta.sdk.tracing.conventions import Reference, is_valid_attribute_key
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class Tracing(metaclass=Singleton):
|
|
27
|
+
VERSION = "0.1.0"
|
|
28
|
+
|
|
29
|
+
Status = Status
|
|
30
|
+
StatusCode = StatusCode
|
|
31
|
+
|
|
32
|
+
def __init__(
|
|
33
|
+
self,
|
|
34
|
+
url: str,
|
|
35
|
+
redact: Optional[Callable[..., Any]] = None,
|
|
36
|
+
redact_on_error: Optional[bool] = True,
|
|
37
|
+
) -> None:
|
|
38
|
+
# ENDPOINT (OTLP)
|
|
39
|
+
self.otlp_url = url
|
|
40
|
+
# HEADERS (OTLP)
|
|
41
|
+
self.headers: Dict[str, str] = dict()
|
|
42
|
+
# REFERENCES
|
|
43
|
+
self.references: Dict[str, str] = dict()
|
|
44
|
+
# CREDENTIALS
|
|
45
|
+
self.credentials: Dict[int, str] = dict()
|
|
46
|
+
|
|
47
|
+
# TRACER PROVIDER
|
|
48
|
+
self.tracer_provider: Optional[TracerProvider] = None
|
|
49
|
+
# TRACE PROCESSORS -- INLINE
|
|
50
|
+
self.inline: Optional[TraceProcessor] = None
|
|
51
|
+
# TRACER
|
|
52
|
+
self.tracer: Optional[Tracer] = None
|
|
53
|
+
# INLINE SPANS for INLINE TRACES (INLINE PROCESSOR)
|
|
54
|
+
self.inline_spans: Dict[str, Any] = dict()
|
|
55
|
+
|
|
56
|
+
# REDACT
|
|
57
|
+
self.redact = redact
|
|
58
|
+
self.redact_on_error = redact_on_error
|
|
59
|
+
|
|
60
|
+
# PUBLIC
|
|
61
|
+
|
|
62
|
+
def configure(
|
|
63
|
+
self,
|
|
64
|
+
api_key: Optional[str] = None,
|
|
65
|
+
service_id: Optional[str] = None,
|
|
66
|
+
# DEPRECATING
|
|
67
|
+
app_id: Optional[str] = None,
|
|
68
|
+
):
|
|
69
|
+
# HEADERS (OTLP)
|
|
70
|
+
if api_key:
|
|
71
|
+
self.headers["Authorization"] = f"ApiKey {api_key}"
|
|
72
|
+
# REFERENCES
|
|
73
|
+
if service_id:
|
|
74
|
+
self.references["service.id"] = service_id
|
|
75
|
+
if app_id:
|
|
76
|
+
self.references["application.id"] = app_id
|
|
77
|
+
|
|
78
|
+
# TRACER PROVIDER
|
|
79
|
+
self.tracer_provider = TracerProvider(
|
|
80
|
+
resource=Resource(attributes={"service.name": "agenta-sdk"})
|
|
81
|
+
)
|
|
82
|
+
# TRACE PROCESSORS -- INLINE
|
|
83
|
+
self.inline = TraceProcessor(
|
|
84
|
+
InlineExporter(
|
|
85
|
+
registry=self.inline_spans,
|
|
86
|
+
),
|
|
87
|
+
references=self.references,
|
|
88
|
+
)
|
|
89
|
+
self.tracer_provider.add_span_processor(self.inline)
|
|
90
|
+
# TRACE PROCESSORS -- OTLP
|
|
91
|
+
try:
|
|
92
|
+
log.info(
|
|
93
|
+
"Agenta - OLTP URL: %s",
|
|
94
|
+
self.otlp_url,
|
|
95
|
+
)
|
|
96
|
+
# check(
|
|
97
|
+
# self.otlp_url,
|
|
98
|
+
# headers=self.headers,
|
|
99
|
+
# timeout=1,
|
|
100
|
+
# )
|
|
101
|
+
|
|
102
|
+
_otlp = TraceProcessor(
|
|
103
|
+
OTLPExporter(
|
|
104
|
+
endpoint=self.otlp_url,
|
|
105
|
+
headers=self.headers,
|
|
106
|
+
credentials=self.credentials,
|
|
107
|
+
),
|
|
108
|
+
references=self.references,
|
|
109
|
+
)
|
|
110
|
+
|
|
111
|
+
self.tracer_provider.add_span_processor(_otlp)
|
|
112
|
+
except: # pylint: disable=bare-except
|
|
113
|
+
log.warning("Agenta - OLTP unreachable, skipping exports.")
|
|
114
|
+
|
|
115
|
+
# GLOBAL TRACER PROVIDER -- INSTRUMENTATION LIBRARIES
|
|
116
|
+
set_tracer_provider(self.tracer_provider)
|
|
117
|
+
# TRACER
|
|
118
|
+
self.tracer: Tracer = self.tracer_provider.get_tracer("agenta.tracer")
|
|
119
|
+
|
|
120
|
+
def get_current_span(self):
|
|
121
|
+
_span = None
|
|
122
|
+
|
|
123
|
+
with suppress():
|
|
124
|
+
_span = get_current_span()
|
|
125
|
+
|
|
126
|
+
if _span.is_recording():
|
|
127
|
+
return CustomSpan(_span)
|
|
128
|
+
|
|
129
|
+
return _span
|
|
130
|
+
|
|
131
|
+
def store_internals(
|
|
132
|
+
self,
|
|
133
|
+
attributes: Dict[str, Any],
|
|
134
|
+
span: Optional[Span] = None,
|
|
135
|
+
):
|
|
136
|
+
with suppress():
|
|
137
|
+
if span is None:
|
|
138
|
+
span = self.get_current_span()
|
|
139
|
+
|
|
140
|
+
span.set_attributes(
|
|
141
|
+
attributes={"internals": attributes},
|
|
142
|
+
namespace="data",
|
|
143
|
+
)
|
|
144
|
+
|
|
145
|
+
def store_refs(
|
|
146
|
+
self,
|
|
147
|
+
refs: Dict[str, str],
|
|
148
|
+
span: Optional[Span] = None,
|
|
149
|
+
):
|
|
150
|
+
with suppress():
|
|
151
|
+
if span is None:
|
|
152
|
+
span = self.get_current_span()
|
|
153
|
+
|
|
154
|
+
for key in refs.keys():
|
|
155
|
+
if key in [_.value for _ in Reference.__members__.values()]:
|
|
156
|
+
# ADD REFERENCE TO THIS SPAN
|
|
157
|
+
span.set_attribute(
|
|
158
|
+
key.value if isinstance(key, Enum) else key,
|
|
159
|
+
refs[key],
|
|
160
|
+
namespace="refs",
|
|
161
|
+
)
|
|
162
|
+
|
|
163
|
+
# AND TO ALL SPANS CREATED AFTER THIS ONE
|
|
164
|
+
self.references[key] = refs[key]
|
|
165
|
+
# TODO: THIS SHOULD BE REPLACED BY A TRACE CONTEXT !!!
|
|
166
|
+
|
|
167
|
+
def store_meta(
|
|
168
|
+
self,
|
|
169
|
+
meta: Dict[str, Any],
|
|
170
|
+
span: Optional[Span] = None,
|
|
171
|
+
):
|
|
172
|
+
with suppress():
|
|
173
|
+
if span is None:
|
|
174
|
+
span = self.get_current_span()
|
|
175
|
+
|
|
176
|
+
for key in meta.keys():
|
|
177
|
+
if is_valid_attribute_key(key):
|
|
178
|
+
span.set_attribute(
|
|
179
|
+
key,
|
|
180
|
+
meta[key],
|
|
181
|
+
namespace="meta",
|
|
182
|
+
)
|
|
183
|
+
|
|
184
|
+
def store_metrics(
|
|
185
|
+
self,
|
|
186
|
+
metrics: Dict[str, Any],
|
|
187
|
+
span: Optional[Span] = None,
|
|
188
|
+
):
|
|
189
|
+
with suppress():
|
|
190
|
+
if span is None:
|
|
191
|
+
span = self.get_current_span()
|
|
192
|
+
|
|
193
|
+
for key in metrics.keys():
|
|
194
|
+
if is_valid_attribute_key(key):
|
|
195
|
+
span.set_attribute(
|
|
196
|
+
key,
|
|
197
|
+
metrics[key],
|
|
198
|
+
namespace="metrics",
|
|
199
|
+
)
|
|
200
|
+
|
|
201
|
+
def is_inline_trace_ready(
|
|
202
|
+
self,
|
|
203
|
+
trace_id: Optional[int] = None,
|
|
204
|
+
) -> bool:
|
|
205
|
+
is_ready = True
|
|
206
|
+
|
|
207
|
+
with suppress():
|
|
208
|
+
if trace_id is not None:
|
|
209
|
+
is_ready = self.inline.is_ready(trace_id)
|
|
210
|
+
|
|
211
|
+
return is_ready
|
|
212
|
+
|
|
213
|
+
def get_inline_trace(
|
|
214
|
+
self,
|
|
215
|
+
trace_id: Optional[int] = None,
|
|
216
|
+
) -> Dict[str, Any]:
|
|
217
|
+
_inline_trace = {}
|
|
218
|
+
|
|
219
|
+
with suppress():
|
|
220
|
+
is_ready = self.inline.is_ready(trace_id)
|
|
221
|
+
|
|
222
|
+
if is_ready is True:
|
|
223
|
+
otel_spans = self.inline.fetch(trace_id)
|
|
224
|
+
|
|
225
|
+
if otel_spans:
|
|
226
|
+
_inline_trace = parse_inline_trace(otel_spans)
|
|
227
|
+
|
|
228
|
+
return _inline_trace
|
|
229
|
+
|
|
230
|
+
|
|
231
|
+
def get_tracer(
|
|
232
|
+
tracing: Tracing,
|
|
233
|
+
) -> Tracer:
|
|
234
|
+
if tracing is None or tracing.tracer is None or tracing.tracer_provider is None:
|
|
235
|
+
return get_tracer_provider().get_tracer("default.tracer")
|
|
236
|
+
|
|
237
|
+
return tracing.tracer
|