veadk-python 0.2.27__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.
- veadk/__init__.py +37 -0
- veadk/a2a/__init__.py +13 -0
- veadk/a2a/agent_card.py +45 -0
- veadk/a2a/remote_ve_agent.py +390 -0
- veadk/a2a/utils/__init__.py +13 -0
- veadk/a2a/utils/agent_to_a2a.py +170 -0
- veadk/a2a/ve_a2a_server.py +93 -0
- veadk/a2a/ve_agent_executor.py +78 -0
- veadk/a2a/ve_middlewares.py +313 -0
- veadk/a2a/ve_task_store.py +37 -0
- veadk/agent.py +402 -0
- veadk/agent_builder.py +93 -0
- veadk/agents/loop_agent.py +68 -0
- veadk/agents/parallel_agent.py +72 -0
- veadk/agents/sequential_agent.py +64 -0
- veadk/auth/__init__.py +13 -0
- veadk/auth/base_auth.py +22 -0
- veadk/auth/ve_credential_service.py +203 -0
- veadk/auth/veauth/__init__.py +13 -0
- veadk/auth/veauth/apmplus_veauth.py +58 -0
- veadk/auth/veauth/ark_veauth.py +75 -0
- veadk/auth/veauth/base_veauth.py +50 -0
- veadk/auth/veauth/cozeloop_veauth.py +13 -0
- veadk/auth/veauth/opensearch_veauth.py +75 -0
- veadk/auth/veauth/postgresql_veauth.py +75 -0
- veadk/auth/veauth/prompt_pilot_veauth.py +60 -0
- veadk/auth/veauth/speech_veauth.py +54 -0
- veadk/auth/veauth/utils.py +69 -0
- veadk/auth/veauth/vesearch_veauth.py +62 -0
- veadk/auth/veauth/viking_mem0_veauth.py +91 -0
- veadk/cli/__init__.py +13 -0
- veadk/cli/cli.py +58 -0
- veadk/cli/cli_clean.py +87 -0
- veadk/cli/cli_create.py +163 -0
- veadk/cli/cli_deploy.py +233 -0
- veadk/cli/cli_eval.py +215 -0
- veadk/cli/cli_init.py +214 -0
- veadk/cli/cli_kb.py +110 -0
- veadk/cli/cli_pipeline.py +285 -0
- veadk/cli/cli_prompt.py +86 -0
- veadk/cli/cli_update.py +106 -0
- veadk/cli/cli_uploadevalset.py +139 -0
- veadk/cli/cli_web.py +143 -0
- veadk/cloud/__init__.py +13 -0
- veadk/cloud/cloud_agent_engine.py +485 -0
- veadk/cloud/cloud_app.py +475 -0
- veadk/config.py +115 -0
- veadk/configs/__init__.py +13 -0
- veadk/configs/auth_configs.py +133 -0
- veadk/configs/database_configs.py +132 -0
- veadk/configs/model_configs.py +78 -0
- veadk/configs/tool_configs.py +54 -0
- veadk/configs/tracing_configs.py +110 -0
- veadk/consts.py +74 -0
- veadk/evaluation/__init__.py +17 -0
- veadk/evaluation/adk_evaluator/__init__.py +17 -0
- veadk/evaluation/adk_evaluator/adk_evaluator.py +302 -0
- veadk/evaluation/base_evaluator.py +642 -0
- veadk/evaluation/deepeval_evaluator/__init__.py +17 -0
- veadk/evaluation/deepeval_evaluator/deepeval_evaluator.py +339 -0
- veadk/evaluation/eval_set_file_loader.py +48 -0
- veadk/evaluation/eval_set_recorder.py +146 -0
- veadk/evaluation/types.py +65 -0
- veadk/evaluation/utils/prometheus.py +196 -0
- veadk/integrations/__init__.py +13 -0
- veadk/integrations/ve_apig/__init__.py +13 -0
- veadk/integrations/ve_apig/ve_apig.py +349 -0
- veadk/integrations/ve_apig/ve_apig_utils.py +332 -0
- veadk/integrations/ve_code_pipeline/__init__.py +13 -0
- veadk/integrations/ve_code_pipeline/ve_code_pipeline.py +431 -0
- veadk/integrations/ve_cozeloop/__init__.py +13 -0
- veadk/integrations/ve_cozeloop/ve_cozeloop.py +96 -0
- veadk/integrations/ve_cr/__init__.py +13 -0
- veadk/integrations/ve_cr/ve_cr.py +220 -0
- veadk/integrations/ve_faas/__init__.py +13 -0
- veadk/integrations/ve_faas/template/cookiecutter.json +15 -0
- veadk/integrations/ve_faas/template/{{cookiecutter.local_dir_name}}/__init__.py +13 -0
- veadk/integrations/ve_faas/template/{{cookiecutter.local_dir_name}}/clean.py +23 -0
- veadk/integrations/ve_faas/template/{{cookiecutter.local_dir_name}}/config.yaml.example +6 -0
- veadk/integrations/ve_faas/template/{{cookiecutter.local_dir_name}}/deploy.py +106 -0
- veadk/integrations/ve_faas/template/{{cookiecutter.local_dir_name}}/src/__init__.py +13 -0
- veadk/integrations/ve_faas/template/{{cookiecutter.local_dir_name}}/src/agent.py +25 -0
- veadk/integrations/ve_faas/template/{{cookiecutter.local_dir_name}}/src/app.py +202 -0
- veadk/integrations/ve_faas/template/{{cookiecutter.local_dir_name}}/src/requirements.txt +3 -0
- veadk/integrations/ve_faas/template/{{cookiecutter.local_dir_name}}/src/run.sh +49 -0
- veadk/integrations/ve_faas/template/{{cookiecutter.local_dir_name}}/src/{{ cookiecutter.app_name }}/__init__.py +14 -0
- veadk/integrations/ve_faas/template/{{cookiecutter.local_dir_name}}/src/{{ cookiecutter.app_name }}/agent.py +27 -0
- veadk/integrations/ve_faas/ve_faas.py +754 -0
- veadk/integrations/ve_faas/ve_faas_utils.py +408 -0
- veadk/integrations/ve_faas/web_template/cookiecutter.json +20 -0
- veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/__init__.py +13 -0
- veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/clean.py +23 -0
- veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/config.yaml.example +2 -0
- veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/deploy.py +44 -0
- veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/Dockerfile +23 -0
- veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/app.py +123 -0
- veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/init_db.py +46 -0
- veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/models.py +36 -0
- veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/requirements.txt +4 -0
- veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/run.sh +21 -0
- veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/static/css/style.css +368 -0
- veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/static/js/admin.js +0 -0
- veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/templates/admin/dashboard.html +21 -0
- veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/templates/admin/edit_post.html +24 -0
- veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/templates/admin/login.html +21 -0
- veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/templates/admin/posts.html +53 -0
- veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/templates/base.html +45 -0
- veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/templates/index.html +29 -0
- veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/templates/post.html +14 -0
- veadk/integrations/ve_identity/__init__.py +110 -0
- veadk/integrations/ve_identity/auth_config.py +261 -0
- veadk/integrations/ve_identity/auth_mixins.py +650 -0
- veadk/integrations/ve_identity/auth_processor.py +385 -0
- veadk/integrations/ve_identity/function_tool.py +158 -0
- veadk/integrations/ve_identity/identity_client.py +864 -0
- veadk/integrations/ve_identity/mcp_tool.py +181 -0
- veadk/integrations/ve_identity/mcp_toolset.py +431 -0
- veadk/integrations/ve_identity/models.py +228 -0
- veadk/integrations/ve_identity/token_manager.py +188 -0
- veadk/integrations/ve_identity/utils.py +151 -0
- veadk/integrations/ve_prompt_pilot/__init__.py +13 -0
- veadk/integrations/ve_prompt_pilot/ve_prompt_pilot.py +85 -0
- veadk/integrations/ve_tls/__init__.py +13 -0
- veadk/integrations/ve_tls/utils.py +116 -0
- veadk/integrations/ve_tls/ve_tls.py +212 -0
- veadk/integrations/ve_tos/ve_tos.py +710 -0
- veadk/integrations/ve_viking_db_memory/__init__.py +13 -0
- veadk/integrations/ve_viking_db_memory/ve_viking_db_memory.py +308 -0
- veadk/knowledgebase/__init__.py +17 -0
- veadk/knowledgebase/backends/__init__.py +13 -0
- veadk/knowledgebase/backends/base_backend.py +72 -0
- veadk/knowledgebase/backends/in_memory_backend.py +91 -0
- veadk/knowledgebase/backends/opensearch_backend.py +162 -0
- veadk/knowledgebase/backends/redis_backend.py +172 -0
- veadk/knowledgebase/backends/utils.py +92 -0
- veadk/knowledgebase/backends/vikingdb_knowledge_backend.py +608 -0
- veadk/knowledgebase/entry.py +25 -0
- veadk/knowledgebase/knowledgebase.py +307 -0
- veadk/memory/__init__.py +35 -0
- veadk/memory/long_term_memory.py +365 -0
- veadk/memory/long_term_memory_backends/__init__.py +13 -0
- veadk/memory/long_term_memory_backends/base_backend.py +35 -0
- veadk/memory/long_term_memory_backends/in_memory_backend.py +67 -0
- veadk/memory/long_term_memory_backends/mem0_backend.py +155 -0
- veadk/memory/long_term_memory_backends/opensearch_backend.py +124 -0
- veadk/memory/long_term_memory_backends/redis_backend.py +140 -0
- veadk/memory/long_term_memory_backends/vikingdb_memory_backend.py +189 -0
- veadk/memory/short_term_memory.py +252 -0
- veadk/memory/short_term_memory_backends/__init__.py +13 -0
- veadk/memory/short_term_memory_backends/base_backend.py +31 -0
- veadk/memory/short_term_memory_backends/mysql_backend.py +49 -0
- veadk/memory/short_term_memory_backends/postgresql_backend.py +49 -0
- veadk/memory/short_term_memory_backends/sqlite_backend.py +55 -0
- veadk/memory/short_term_memory_processor.py +100 -0
- veadk/processors/__init__.py +26 -0
- veadk/processors/base_run_processor.py +120 -0
- veadk/prompts/__init__.py +13 -0
- veadk/prompts/agent_default_prompt.py +30 -0
- veadk/prompts/prompt_evaluator.py +20 -0
- veadk/prompts/prompt_memory_processor.py +55 -0
- veadk/prompts/prompt_optimization.py +150 -0
- veadk/runner.py +732 -0
- veadk/tools/__init__.py +13 -0
- veadk/tools/builtin_tools/__init__.py +13 -0
- veadk/tools/builtin_tools/agent_authorization.py +94 -0
- veadk/tools/builtin_tools/generate_image.py +23 -0
- veadk/tools/builtin_tools/image_edit.py +300 -0
- veadk/tools/builtin_tools/image_generate.py +446 -0
- veadk/tools/builtin_tools/lark.py +67 -0
- veadk/tools/builtin_tools/las.py +24 -0
- veadk/tools/builtin_tools/link_reader.py +66 -0
- veadk/tools/builtin_tools/llm_shield.py +381 -0
- veadk/tools/builtin_tools/load_knowledgebase.py +97 -0
- veadk/tools/builtin_tools/mcp_router.py +29 -0
- veadk/tools/builtin_tools/run_code.py +113 -0
- veadk/tools/builtin_tools/tts.py +253 -0
- veadk/tools/builtin_tools/vesearch.py +49 -0
- veadk/tools/builtin_tools/video_generate.py +363 -0
- veadk/tools/builtin_tools/web_scraper.py +76 -0
- veadk/tools/builtin_tools/web_search.py +83 -0
- veadk/tools/demo_tools.py +58 -0
- veadk/tools/load_knowledgebase_tool.py +149 -0
- veadk/tools/sandbox/__init__.py +13 -0
- veadk/tools/sandbox/browser_sandbox.py +37 -0
- veadk/tools/sandbox/code_sandbox.py +40 -0
- veadk/tools/sandbox/computer_sandbox.py +34 -0
- veadk/tracing/__init__.py +13 -0
- veadk/tracing/base_tracer.py +58 -0
- veadk/tracing/telemetry/__init__.py +13 -0
- veadk/tracing/telemetry/attributes/attributes.py +29 -0
- veadk/tracing/telemetry/attributes/extractors/common_attributes_extractors.py +180 -0
- veadk/tracing/telemetry/attributes/extractors/llm_attributes_extractors.py +858 -0
- veadk/tracing/telemetry/attributes/extractors/tool_attributes_extractors.py +152 -0
- veadk/tracing/telemetry/attributes/extractors/types.py +164 -0
- veadk/tracing/telemetry/exporters/__init__.py +13 -0
- veadk/tracing/telemetry/exporters/apmplus_exporter.py +558 -0
- veadk/tracing/telemetry/exporters/base_exporter.py +39 -0
- veadk/tracing/telemetry/exporters/cozeloop_exporter.py +129 -0
- veadk/tracing/telemetry/exporters/inmemory_exporter.py +248 -0
- veadk/tracing/telemetry/exporters/tls_exporter.py +139 -0
- veadk/tracing/telemetry/opentelemetry_tracer.py +320 -0
- veadk/tracing/telemetry/telemetry.py +411 -0
- veadk/types.py +47 -0
- veadk/utils/__init__.py +13 -0
- veadk/utils/audio_manager.py +95 -0
- veadk/utils/auth.py +294 -0
- veadk/utils/logger.py +59 -0
- veadk/utils/mcp_utils.py +44 -0
- veadk/utils/misc.py +184 -0
- veadk/utils/patches.py +101 -0
- veadk/utils/volcengine_sign.py +205 -0
- veadk/version.py +15 -0
- veadk_python-0.2.27.dist-info/METADATA +373 -0
- veadk_python-0.2.27.dist-info/RECORD +218 -0
- veadk_python-0.2.27.dist-info/WHEEL +5 -0
- veadk_python-0.2.27.dist-info/entry_points.txt +2 -0
- veadk_python-0.2.27.dist-info/licenses/LICENSE +201 -0
- veadk_python-0.2.27.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,320 @@
|
|
|
1
|
+
# Copyright (c) 2025 Beijing Volcano Engine Technology Co., Ltd. and/or its affiliates.
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
15
|
+
from __future__ import annotations
|
|
16
|
+
|
|
17
|
+
import json
|
|
18
|
+
import time
|
|
19
|
+
from typing import Any
|
|
20
|
+
|
|
21
|
+
from opentelemetry import trace as trace_api
|
|
22
|
+
from opentelemetry.sdk import trace as trace_sdk
|
|
23
|
+
from opentelemetry.sdk.resources import Resource
|
|
24
|
+
from opentelemetry.sdk.trace import SpanLimits, TracerProvider
|
|
25
|
+
from opentelemetry.sdk.trace.export import BatchSpanProcessor, SimpleSpanProcessor
|
|
26
|
+
from pydantic import BaseModel, ConfigDict, Field, field_validator
|
|
27
|
+
from typing_extensions import override
|
|
28
|
+
|
|
29
|
+
from veadk.tracing.base_tracer import BaseTracer
|
|
30
|
+
from veadk.tracing.telemetry.exporters.apmplus_exporter import APMPlusExporter
|
|
31
|
+
from veadk.tracing.telemetry.exporters.base_exporter import BaseExporter
|
|
32
|
+
from veadk.tracing.telemetry.exporters.inmemory_exporter import InMemoryExporter
|
|
33
|
+
from veadk.utils.logger import get_logger
|
|
34
|
+
from veadk.utils.misc import get_agent_dir
|
|
35
|
+
from veadk.utils.patches import patch_google_adk_telemetry
|
|
36
|
+
|
|
37
|
+
logger = get_logger(__name__)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def _update_resource_attributions(
|
|
41
|
+
provider: TracerProvider, resource_attributes: dict
|
|
42
|
+
) -> None:
|
|
43
|
+
"""Update the resource attributes of a TracerProvider instance.
|
|
44
|
+
|
|
45
|
+
This function merges new resource attributes with the existing ones in the
|
|
46
|
+
provider, allowing dynamic configuration of telemetry metadata.
|
|
47
|
+
|
|
48
|
+
Args:
|
|
49
|
+
provider: The TracerProvider instance to update
|
|
50
|
+
resource_attributes: Dictionary of attributes to merge with existing resources
|
|
51
|
+
"""
|
|
52
|
+
provider._resource = provider._resource.merge(Resource.create(resource_attributes))
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
class OpentelemetryTracer(BaseModel, BaseTracer):
|
|
56
|
+
"""OpenTelemetry-based tracer implementation for comprehensive agent observability.
|
|
57
|
+
|
|
58
|
+
This class provides a complete tracing solution using OpenTelemetry standards,
|
|
59
|
+
supporting multiple exporters for different observability platforms. It captures
|
|
60
|
+
detailed execution traces including LLM calls, tool invocations, and agent workflow
|
|
61
|
+
patterns for debugging and performance analysis.
|
|
62
|
+
|
|
63
|
+
Key Features:
|
|
64
|
+
- Multi-exporter support (APMPlus, in-memory, custom exporters)
|
|
65
|
+
- Thread-safe span processing with configurable limits
|
|
66
|
+
- Local trace dumping with JSON serialization
|
|
67
|
+
- Resource attribute management for metadata enrichment
|
|
68
|
+
- Force flush capabilities for immediate data export
|
|
69
|
+
|
|
70
|
+
Architecture:
|
|
71
|
+
The tracer initializes a global TracerProvider with custom span processors for
|
|
72
|
+
each configured exporter. It maintains an internal in-memory exporter for local
|
|
73
|
+
operations while supporting external observability platforms simultaneously.
|
|
74
|
+
|
|
75
|
+
Attributes:
|
|
76
|
+
name: Identifier for this tracer instance, used in file naming and logging
|
|
77
|
+
exporters: List of exporter instances for sending trace data to different backends
|
|
78
|
+
|
|
79
|
+
Examples:
|
|
80
|
+
Basic usage with APMPlus exporter:
|
|
81
|
+
```python
|
|
82
|
+
exporters = [
|
|
83
|
+
CozeloopExporter(),
|
|
84
|
+
APMPlusExporter(),
|
|
85
|
+
TLSExporter(),
|
|
86
|
+
]
|
|
87
|
+
tracer = OpentelemetryTracer(exporters=exporters)
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
Note:
|
|
91
|
+
- InMemoryExporter cannot be explicitly added to exporters list
|
|
92
|
+
- Span limits are set to 4096 attributes for comprehensive data capture
|
|
93
|
+
"""
|
|
94
|
+
|
|
95
|
+
model_config = ConfigDict(arbitrary_types_allowed=True)
|
|
96
|
+
|
|
97
|
+
name: str = Field(
|
|
98
|
+
default="veadk_opentelemetry_tracer", description="The identifier of tracer."
|
|
99
|
+
)
|
|
100
|
+
|
|
101
|
+
exporters: list[BaseExporter] = Field(
|
|
102
|
+
default_factory=list,
|
|
103
|
+
description="The exporters to export spans.",
|
|
104
|
+
)
|
|
105
|
+
|
|
106
|
+
# Forbid InMemoryExporter in exporters list
|
|
107
|
+
# cause we need to set custom in-memory span processor by VeADK
|
|
108
|
+
@field_validator("exporters")
|
|
109
|
+
@classmethod
|
|
110
|
+
def forbid_inmemory_exporter(cls, v: list[BaseExporter]) -> list[BaseExporter]:
|
|
111
|
+
"""Validate that InMemoryExporter is not explicitly added to exporters list.
|
|
112
|
+
|
|
113
|
+
InMemoryExporter is automatically managed internally and should not be
|
|
114
|
+
included in the user-provided exporters list to avoid conflicts.
|
|
115
|
+
|
|
116
|
+
Args:
|
|
117
|
+
v: List of exporter instances to validate
|
|
118
|
+
|
|
119
|
+
Returns:
|
|
120
|
+
list[BaseExporter]: The validated list of exporters
|
|
121
|
+
|
|
122
|
+
Raises:
|
|
123
|
+
ValueError: If InMemoryExporter is found in the exporters list
|
|
124
|
+
"""
|
|
125
|
+
for e in v:
|
|
126
|
+
if isinstance(e, InMemoryExporter):
|
|
127
|
+
raise ValueError("InMemoryExporter is not allowed in exporters list")
|
|
128
|
+
return v
|
|
129
|
+
|
|
130
|
+
def model_post_init(self, context: Any) -> None:
|
|
131
|
+
"""Initialize the tracer after model construction.
|
|
132
|
+
|
|
133
|
+
This method performs post-initialization setup including Google ADK
|
|
134
|
+
telemetry patching and global tracer provider configuration.
|
|
135
|
+
"""
|
|
136
|
+
# Replace Google ADK tracing funcs
|
|
137
|
+
# `trace_call_llm` and `trace_tool_call`
|
|
138
|
+
patch_google_adk_telemetry()
|
|
139
|
+
|
|
140
|
+
# We save internal processors for tracing data dump
|
|
141
|
+
self._processors = []
|
|
142
|
+
|
|
143
|
+
# Initialize global tracer provider to avoid VeFaaS global tracer
|
|
144
|
+
# provider conflicts
|
|
145
|
+
self._init_global_tracer_provider()
|
|
146
|
+
|
|
147
|
+
def _init_global_tracer_provider(self) -> None:
|
|
148
|
+
"""Initialize the global OpenTelemetry tracer provider with configured exporters.
|
|
149
|
+
|
|
150
|
+
This method sets up the global tracer provider, configures span processors
|
|
151
|
+
for each exporter, and ensures proper resource attribution. It also handles
|
|
152
|
+
duplicate exporter detection and in-memory span collection setup.
|
|
153
|
+
"""
|
|
154
|
+
# set provider anyway, then get global provider
|
|
155
|
+
trace_api.set_tracer_provider(
|
|
156
|
+
trace_sdk.TracerProvider(
|
|
157
|
+
span_limits=SpanLimits(
|
|
158
|
+
max_attributes=4096,
|
|
159
|
+
)
|
|
160
|
+
)
|
|
161
|
+
)
|
|
162
|
+
global_tracer_provider: TracerProvider = trace_api.get_tracer_provider() # type: ignore
|
|
163
|
+
|
|
164
|
+
span_processors = global_tracer_provider._active_span_processor._span_processors
|
|
165
|
+
have_apmplus_exporter = any(
|
|
166
|
+
isinstance(p, (BatchSpanProcessor, SimpleSpanProcessor))
|
|
167
|
+
and hasattr(p.span_exporter, "_endpoint")
|
|
168
|
+
and "apmplus" in p.span_exporter._endpoint
|
|
169
|
+
for p in span_processors
|
|
170
|
+
)
|
|
171
|
+
|
|
172
|
+
if have_apmplus_exporter:
|
|
173
|
+
self.exporters = [
|
|
174
|
+
e for e in self.exporters if not isinstance(e, APMPlusExporter)
|
|
175
|
+
]
|
|
176
|
+
|
|
177
|
+
for exporter in self.exporters:
|
|
178
|
+
processor = exporter.processor
|
|
179
|
+
resource_attributes = exporter.resource_attributes
|
|
180
|
+
|
|
181
|
+
if resource_attributes:
|
|
182
|
+
_update_resource_attributions(
|
|
183
|
+
global_tracer_provider, resource_attributes
|
|
184
|
+
)
|
|
185
|
+
|
|
186
|
+
if processor:
|
|
187
|
+
global_tracer_provider.add_span_processor(processor)
|
|
188
|
+
self._processors.append(processor)
|
|
189
|
+
|
|
190
|
+
logger.debug(
|
|
191
|
+
f"Add span processor for exporter `{exporter.__class__.__name__}` to OpentelemetryTracer."
|
|
192
|
+
)
|
|
193
|
+
else:
|
|
194
|
+
logger.error(
|
|
195
|
+
f"Add span processor for exporter `{exporter.__class__.__name__}` to OpentelemetryTracer failed."
|
|
196
|
+
)
|
|
197
|
+
|
|
198
|
+
self._inmemory_exporter = InMemoryExporter()
|
|
199
|
+
if self._inmemory_exporter.processor:
|
|
200
|
+
# make sure the in memory exporter processor is added at index 0
|
|
201
|
+
# because we use this to record all spans
|
|
202
|
+
global_tracer_provider._active_span_processor._span_processors = (
|
|
203
|
+
self._inmemory_exporter.processor,
|
|
204
|
+
) + global_tracer_provider._active_span_processor._span_processors
|
|
205
|
+
|
|
206
|
+
self._processors.append(self._inmemory_exporter.processor)
|
|
207
|
+
self.exporters.append(self._inmemory_exporter)
|
|
208
|
+
else:
|
|
209
|
+
logger.warning(
|
|
210
|
+
"InMemoryExporter processor is not initialized, cannot add to OpentelemetryTracer."
|
|
211
|
+
)
|
|
212
|
+
|
|
213
|
+
logger.info(
|
|
214
|
+
f"Init OpentelemetryTracer with {len(self._processors)} exporter(s)."
|
|
215
|
+
)
|
|
216
|
+
|
|
217
|
+
@property
|
|
218
|
+
def trace_file_path(self) -> str:
|
|
219
|
+
"""Get the file path of the most recent trace dump.
|
|
220
|
+
|
|
221
|
+
Returns:
|
|
222
|
+
str: Full path to the trace file, or placeholder if not yet dumped
|
|
223
|
+
"""
|
|
224
|
+
return self._trace_file_path
|
|
225
|
+
|
|
226
|
+
@property
|
|
227
|
+
def trace_id(self) -> str:
|
|
228
|
+
"""Get the current trace ID in hexadecimal format.
|
|
229
|
+
|
|
230
|
+
Returns:
|
|
231
|
+
str: Hexadecimal representation of the current trace ID, or
|
|
232
|
+
placeholder string if trace ID cannot be retrieved
|
|
233
|
+
"""
|
|
234
|
+
try:
|
|
235
|
+
trace_id = hex(int(self._inmemory_exporter._exporter.trace_id))[2:] # type: ignore
|
|
236
|
+
return trace_id
|
|
237
|
+
except Exception as e:
|
|
238
|
+
logger.error(f"Failed to get trace_id from InMemoryExporter: {e}")
|
|
239
|
+
return self._trace_id
|
|
240
|
+
|
|
241
|
+
def force_export(self) -> None:
|
|
242
|
+
"""Force immediate export of all pending spans across all processors.
|
|
243
|
+
|
|
244
|
+
This method triggers force_flush on all configured span processors,
|
|
245
|
+
ensuring that buffered span data is immediately sent to exporters.
|
|
246
|
+
Includes a small delay between flushes to prevent overwhelming exporters.
|
|
247
|
+
"""
|
|
248
|
+
for processor in self._processors:
|
|
249
|
+
time.sleep(0.05)
|
|
250
|
+
processor.force_flush()
|
|
251
|
+
|
|
252
|
+
@override
|
|
253
|
+
def dump(
|
|
254
|
+
self,
|
|
255
|
+
user_id: str = "unknown_user_id",
|
|
256
|
+
session_id: str = "unknown_session_id",
|
|
257
|
+
path: str = get_agent_dir(),
|
|
258
|
+
) -> str:
|
|
259
|
+
"""Dump collected trace data to a local JSON file.
|
|
260
|
+
|
|
261
|
+
This method exports all spans associated with the current session to a
|
|
262
|
+
structured JSON file for offline analysis. The file includes span metadata,
|
|
263
|
+
timing information, attributes, and parent-child relationships.
|
|
264
|
+
|
|
265
|
+
Args:
|
|
266
|
+
user_id: User identifier for trace organization and file naming
|
|
267
|
+
session_id: Session identifier for filtering and organizing spans
|
|
268
|
+
path: Directory path for the output file. Defaults to agents directory
|
|
269
|
+
|
|
270
|
+
Returns:
|
|
271
|
+
str: Full path to the created trace file, or empty string if export fails
|
|
272
|
+
|
|
273
|
+
Note:
|
|
274
|
+
- Forces export of all pending spans before dumping
|
|
275
|
+
- Filters spans by session_id for relevant data only
|
|
276
|
+
- File format is structured JSON with span details and relationships
|
|
277
|
+
- Supports non-ASCII characters for international content
|
|
278
|
+
"""
|
|
279
|
+
|
|
280
|
+
def _build_trace_file_path(path: str, user_id: str, session_id: str) -> str:
|
|
281
|
+
return f"{path}/{self.name}_{user_id}_{session_id}_{self.trace_id}.json"
|
|
282
|
+
|
|
283
|
+
if not self._inmemory_exporter:
|
|
284
|
+
logger.warning(
|
|
285
|
+
"InMemoryExporter is not initialized. Please check your tracer exporters."
|
|
286
|
+
)
|
|
287
|
+
return ""
|
|
288
|
+
self.force_export()
|
|
289
|
+
|
|
290
|
+
spans = self._inmemory_exporter._exporter.get_finished_spans( # type: ignore
|
|
291
|
+
session_id=session_id
|
|
292
|
+
)
|
|
293
|
+
data = (
|
|
294
|
+
[
|
|
295
|
+
{
|
|
296
|
+
"name": s.name,
|
|
297
|
+
"span_id": s.context.span_id,
|
|
298
|
+
"trace_id": s.context.trace_id,
|
|
299
|
+
"start_time": s.start_time,
|
|
300
|
+
"end_time": s.end_time,
|
|
301
|
+
"attributes": dict(s.attributes),
|
|
302
|
+
"parent_span_id": s.parent.span_id if s.parent else None,
|
|
303
|
+
}
|
|
304
|
+
for s in spans
|
|
305
|
+
]
|
|
306
|
+
if spans
|
|
307
|
+
else []
|
|
308
|
+
)
|
|
309
|
+
|
|
310
|
+
self._trace_file_path = _build_trace_file_path(path, user_id, session_id)
|
|
311
|
+
with open(self._trace_file_path, "w") as f:
|
|
312
|
+
json.dump(
|
|
313
|
+
data, f, indent=4, ensure_ascii=False
|
|
314
|
+
) # ensure_ascii=False to support Chinese characters
|
|
315
|
+
|
|
316
|
+
logger.info(
|
|
317
|
+
f"OpenTelemetryTracer dumps {len(spans)} spans to {self._trace_file_path}. Trace id: {self.trace_id} (hex)"
|
|
318
|
+
)
|
|
319
|
+
|
|
320
|
+
return self._trace_file_path
|