@agentunion/kite 1.3.2 → 1.5.0
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.
- package/CHANGELOG.md +302 -0
- package/cli.js +119 -4
- package/core/dependency_checker.py +250 -0
- package/core/env_checker.py +490 -0
- package/dependencies_lock.json +128 -0
- package/extensions/agents/assistant/entry.py +111 -1
- package/extensions/agents/assistant/server.py +279 -215
- package/extensions/channels/acp_channel/entry.py +111 -1
- package/extensions/channels/acp_channel/module.md +23 -22
- package/extensions/channels/acp_channel/server.py +279 -215
- package/extensions/event_hub_bench/entry.py +107 -1
- package/extensions/services/backup/entry.py +306 -21
- package/extensions/services/backup/module.md +24 -22
- package/extensions/services/evol/auth_manager.py +443 -0
- package/extensions/services/evol/config.yaml +149 -0
- package/extensions/services/evol/config_loader.py +117 -0
- package/extensions/services/evol/entry.py +406 -0
- package/extensions/services/evol/evol_api.py +173 -0
- package/extensions/services/evol/evol_config.json5 +29 -0
- package/extensions/services/evol/migrate_tokens.py +122 -0
- package/extensions/services/evol/module.md +32 -0
- package/extensions/services/evol/pairing.py +250 -0
- package/extensions/services/evol/pairing_codes.jsonl +1 -0
- package/extensions/services/evol/relay.py +682 -0
- package/extensions/services/evol/relay_config.json5 +67 -0
- package/extensions/services/evol/routes/__init__.py +1 -0
- package/extensions/services/evol/routes/routes_management_ws.py +127 -0
- package/extensions/services/evol/routes/routes_rpc.py +89 -0
- package/extensions/services/evol/routes/routes_test.py +61 -0
- package/extensions/services/evol/server.py +875 -0
- package/extensions/services/evol/static/css/style.css +1200 -0
- package/extensions/services/evol/static/index.html +781 -0
- package/extensions/services/evol/static/index_evol.html +14 -0
- package/extensions/services/evol/static/js/app.js +6304 -0
- package/extensions/services/evol/static/js/auth.js +326 -0
- package/extensions/services/evol/static/js/dialog.js +285 -0
- package/extensions/services/evol/static/js/evol-app-fixed.js +50 -0
- package/extensions/services/evol/static/js/evol-app.js +1949 -0
- package/extensions/services/evol/static/js/evol-app.js.bak +1800 -0
- package/extensions/services/evol/static/js/kernel-client-example.js +228 -0
- package/extensions/services/evol/static/js/kernel-client.js +396 -0
- package/extensions/services/evol/static/js/main.js +141 -0
- package/extensions/services/evol/static/js/registry-tests.js +585 -0
- package/extensions/services/evol/static/js/stats.js +217 -0
- package/extensions/services/evol/static/js/token-manager.js +175 -0
- package/extensions/services/evol/static/pairing.html +248 -0
- package/extensions/services/evol/static/test_registry.html +262 -0
- package/extensions/services/evol/static/test_relay.html +462 -0
- package/extensions/services/evol/stats_manager.py +240 -0
- package/extensions/services/model_service/entry.py +167 -19
- package/extensions/services/model_service/module.md +21 -22
- package/extensions/services/proxy/.claude/settings.local.json +13 -0
- package/extensions/services/proxy/CHANGELOG_20260308.md +258 -0
- package/extensions/services/proxy/_fix_prints.py +133 -0
- package/extensions/services/proxy/_fix_prints2.py +87 -0
- package/extensions/services/proxy/agentcp/LICENCE +178 -0
- package/extensions/services/proxy/agentcp/README copy.md +85 -0
- package/extensions/services/proxy/agentcp/README.md +260 -0
- package/extensions/services/proxy/agentcp/__init__.py +16 -0
- package/extensions/services/proxy/agentcp/agent.py +4 -0
- package/extensions/services/proxy/agentcp/agentcp.py +2494 -0
- package/extensions/services/proxy/agentcp/agentprofile.json +89 -0
- package/extensions/services/proxy/agentcp/ap/__init__.py +16 -0
- package/extensions/services/proxy/agentcp/ap/ap_client.py +316 -0
- package/extensions/services/proxy/agentcp/assets/images/wechat_qr.png +0 -0
- package/extensions/services/proxy/agentcp/backup/metrics.json +31 -0
- package/extensions/services/proxy/agentcp/base/__init__.py +20 -0
- package/extensions/services/proxy/agentcp/base/auth_client.py +257 -0
- package/extensions/services/proxy/agentcp/base/client.py +112 -0
- package/extensions/services/proxy/agentcp/base/env.py +34 -0
- package/extensions/services/proxy/agentcp/base/html_util.py +336 -0
- package/extensions/services/proxy/agentcp/base/log.py +98 -0
- package/extensions/services/proxy/agentcp/ca/__init__.py +17 -0
- package/extensions/services/proxy/agentcp/ca/ca_client.py +414 -0
- package/extensions/services/proxy/agentcp/ca/ca_root.py +74 -0
- package/extensions/services/proxy/agentcp/context/__init__.py +20 -0
- package/extensions/services/proxy/agentcp/context/context.py +73 -0
- package/extensions/services/proxy/agentcp/context/exceptions.py +114 -0
- package/extensions/services/proxy/agentcp/create_profile.py +125 -0
- package/extensions/services/proxy/agentcp/create_profile_weather.py +125 -0
- package/extensions/services/proxy/agentcp/db/__init__.py +15 -0
- package/extensions/services/proxy/agentcp/db/db_mananger.py +550 -0
- package/extensions/services/proxy/agentcp/docs/UDP_HEARTBEAT_FIX_REPORT.md +265 -0
- package/extensions/services/proxy/agentcp/docs/heartbeat_issue_analysis.md +291 -0
- package/extensions/services/proxy/agentcp/file/__init__.py +16 -0
- package/extensions/services/proxy/agentcp/file/file_client.py +141 -0
- package/extensions/services/proxy/agentcp/file/wss_binary_message.py +137 -0
- package/extensions/services/proxy/agentcp/hcp.py +299 -0
- package/extensions/services/proxy/agentcp/heartbeat/__init__.py +16 -0
- package/extensions/services/proxy/agentcp/heartbeat/heartbeat_client.py +360 -0
- package/extensions/services/proxy/agentcp/improved_scheduler.py +498 -0
- package/extensions/services/proxy/agentcp/llm_agent_utils.py +249 -0
- package/extensions/services/proxy/agentcp/llm_server.py +172 -0
- package/extensions/services/proxy/agentcp/mermaid.py +210 -0
- package/extensions/services/proxy/agentcp/message.py +149 -0
- package/extensions/services/proxy/agentcp/metrics.py +256 -0
- package/extensions/services/proxy/agentcp/monitoring/__init__.py +20 -0
- package/extensions/services/proxy/agentcp/monitoring/global_monitor.py +27 -0
- package/extensions/services/proxy/agentcp/monitoring/metrics_store.py +325 -0
- package/extensions/services/proxy/agentcp/monitoring/monitoring_service.py +269 -0
- package/extensions/services/proxy/agentcp/monitoring/sliding_window.py +222 -0
- package/extensions/services/proxy/agentcp/monitoring/standalone_reader.py +224 -0
- package/extensions/services/proxy/agentcp/msg/__init__.py +21 -0
- package/extensions/services/proxy/agentcp/msg/connection_manager.py +456 -0
- package/extensions/services/proxy/agentcp/msg/message_client.py +2058 -0
- package/extensions/services/proxy/agentcp/msg/message_serialize.py +263 -0
- package/extensions/services/proxy/agentcp/msg/open_ai_message.py +88 -0
- package/extensions/services/proxy/agentcp/msg/session_manager.py +1062 -0
- package/extensions/services/proxy/agentcp/msg/stream_client.py +267 -0
- package/extensions/services/proxy/agentcp/msg/websocket_file_receiver.py +89 -0
- package/extensions/services/proxy/agentcp/msg/ws_logger.py +685 -0
- package/extensions/services/proxy/agentcp/msg/wss_binary_message.py +137 -0
- package/extensions/services/proxy/agentcp/requirements.txt +7 -0
- package/extensions/services/proxy/agentcp/samples/agent_graph/README.md +37 -0
- package/extensions/services/proxy/agentcp/samples/agent_graph/agentprofile.json +89 -0
- package/extensions/services/proxy/agentcp/samples/agent_graph/create_profile.py +138 -0
- package/extensions/services/proxy/agentcp/samples/agent_graph/main.py +164 -0
- package/extensions/services/proxy/agentcp/samples/agent_use/create_profile.py +123 -0
- package/extensions/services/proxy/agentcp/samples/agent_use/llm/create_profile.py +129 -0
- package/extensions/services/proxy/agentcp/samples/agent_use/llm/env.json +5 -0
- package/extensions/services/proxy/agentcp/samples/agent_use/llm/main.py +146 -0
- package/extensions/services/proxy/agentcp/samples/agent_use/main.py +123 -0
- package/extensions/services/proxy/agentcp/samples/agent_use/readme.md +379 -0
- package/extensions/services/proxy/agentcp/samples/agent_use/search/create_profile.py +129 -0
- package/extensions/services/proxy/agentcp/samples/agent_use/search/main.py +28 -0
- package/extensions/services/proxy/agentcp/samples/agent_use/tool/create_profile.py +129 -0
- package/extensions/services/proxy/agentcp/samples/agent_use/tool/main.py +20 -0
- package/extensions/services/proxy/agentcp/samples/ali_amap/README.md +97 -0
- package/extensions/services/proxy/agentcp/samples/ali_amap/amap_agent.py +88 -0
- package/extensions/services/proxy/agentcp/samples/ali_amap/create_profile.py +125 -0
- package/extensions/services/proxy/agentcp/samples/compute_agent/agent/powershell.py +228 -0
- package/extensions/services/proxy/agentcp/samples/compute_agent/agent/software.py +63 -0
- package/extensions/services/proxy/agentcp/samples/compute_agent/agent/tools.py +36 -0
- package/extensions/services/proxy/agentcp/samples/compute_agent/browser_user.py +41 -0
- package/extensions/services/proxy/agentcp/samples/deepseek/README.md +79 -0
- package/extensions/services/proxy/agentcp/samples/deepseek/create_profile.py +126 -0
- package/extensions/services/proxy/agentcp/samples/deepseek/deepseek.py +42 -0
- package/extensions/services/proxy/agentcp/samples/dify_chat/README.md +78 -0
- package/extensions/services/proxy/agentcp/samples/dify_chat/create_profile.py +126 -0
- package/extensions/services/proxy/agentcp/samples/dify_chat/dify_chat.py +47 -0
- package/extensions/services/proxy/agentcp/samples/dify_workflow/README.md +78 -0
- package/extensions/services/proxy/agentcp/samples/dify_workflow/create_profile.py +126 -0
- package/extensions/services/proxy/agentcp/samples/dify_workflow/dify_workflow.py +46 -0
- package/extensions/services/proxy/agentcp/samples/executor/README.md +44 -0
- package/extensions/services/proxy/agentcp/samples/executor/agentprofile.json +89 -0
- package/extensions/services/proxy/agentcp/samples/executor/create_profile.py +139 -0
- package/extensions/services/proxy/agentcp/samples/executor/main.py +160 -0
- package/extensions/services/proxy/agentcp/samples/filereader/README.md +45 -0
- package/extensions/services/proxy/agentcp/samples/filereader/agentprofile.json +90 -0
- package/extensions/services/proxy/agentcp/samples/filereader/create_profile.py +137 -0
- package/extensions/services/proxy/agentcp/samples/filereader/main.py +253 -0
- package/extensions/services/proxy/agentcp/samples/filewriter/README.md +38 -0
- package/extensions/services/proxy/agentcp/samples/filewriter/agentprofile.json +91 -0
- package/extensions/services/proxy/agentcp/samples/filewriter/create_profile.py +138 -0
- package/extensions/services/proxy/agentcp/samples/filewriter/main.py +289 -0
- package/extensions/services/proxy/agentcp/samples/hcp/README.md +85 -0
- package/extensions/services/proxy/agentcp/samples/hcp/acp_weather_agent.zip +0 -0
- package/extensions/services/proxy/agentcp/samples/hcp/create_profile.py +125 -0
- package/extensions/services/proxy/agentcp/samples/hcp/hcp.py +237 -0
- package/extensions/services/proxy/agentcp/samples/helloworld/README.md +68 -0
- package/extensions/services/proxy/agentcp/samples/helloworld/hello_world.py +40 -0
- package/extensions/services/proxy/agentcp/samples/llm_agent/MEADME.md +117 -0
- package/extensions/services/proxy/agentcp/samples/llm_agent/create_profile.py +125 -0
- package/extensions/services/proxy/agentcp/samples/llm_agent/qwen_agent.py +136 -0
- package/extensions/services/proxy/agentcp/samples/local_llm_agent/README.md +90 -0
- package/extensions/services/proxy/agentcp/samples/local_llm_agent/create_profile.py +125 -0
- package/extensions/services/proxy/agentcp/samples/local_llm_agent/main.py +49 -0
- package/extensions/services/proxy/agentcp/samples/query_llm_from_agent/README.md +55 -0
- package/extensions/services/proxy/agentcp/samples/query_llm_from_agent/create_profile.py +125 -0
- package/extensions/services/proxy/agentcp/samples/query_llm_from_agent/main.py +23 -0
- package/extensions/services/proxy/agentcp/samples/query_weather_api_agent/README.md +103 -0
- package/extensions/services/proxy/agentcp/samples/query_weather_api_agent/create_profile.py +125 -0
- package/extensions/services/proxy/agentcp/samples/query_weather_api_agent/main.py +69 -0
- package/extensions/services/proxy/agentcp/samples/query_weather_from_agent/README.md +58 -0
- package/extensions/services/proxy/agentcp/samples/query_weather_from_agent/create_profile.py +125 -0
- package/extensions/services/proxy/agentcp/samples/query_weather_from_agent/main.py +25 -0
- package/extensions/services/proxy/agentcp/samples/qwen3/README.md +71 -0
- package/extensions/services/proxy/agentcp/samples/qwen3/create_profile.py +126 -0
- package/extensions/services/proxy/agentcp/samples/qwen3/qwen3.py +37 -0
- package/extensions/services/proxy/agentcp/samples/qwen3_tools/README.md +133 -0
- package/extensions/services/proxy/agentcp/samples/qwen3_tools/create_profile.py +126 -0
- package/extensions/services/proxy/agentcp/samples/qwen3_tools/qwen3_tools.py +98 -0
- package/extensions/services/proxy/agentcp/samples/search/create_profile_qwen.py +125 -0
- package/extensions/services/proxy/agentcp/samples/search/create_profile_search.py +125 -0
- package/extensions/services/proxy/agentcp/samples/search/qwen_agent.py +136 -0
- package/extensions/services/proxy/agentcp/samples/search/search_agent.py +170 -0
- package/extensions/services/proxy/agentcp/samples/wrapper_agently_to_agent/README.md +89 -0
- package/extensions/services/proxy/agentcp/samples/wrapper_agently_to_agent/create_profile.py +125 -0
- package/extensions/services/proxy/agentcp/samples/wrapper_agently_to_agent/main.py +44 -0
- package/extensions/services/proxy/agentcp/utils/__init__.py +15 -0
- package/extensions/services/proxy/agentcp/utils/file_util.py +117 -0
- package/extensions/services/proxy/agentcp/utils/proxy_bypass.py +99 -0
- package/extensions/services/proxy/agentcp/workflow.py +203 -0
- package/extensions/services/proxy/console_auth.py +109 -0
- package/extensions/services/proxy/evol/__init__.py +1 -0
- package/extensions/services/proxy/evol/config.py +37 -0
- package/extensions/services/proxy/evol/http/__init__.py +1 -0
- package/extensions/services/proxy/evol/http/async_http.py +551 -0
- package/extensions/services/proxy/evol/log.py +28 -0
- package/extensions/services/proxy/evol/presenter/__init__.py +2 -0
- package/extensions/services/proxy/evol/presenter/agentIdPresenter.py +1031 -0
- package/extensions/services/proxy/evol/presenter/apikeyPresenter.py +106 -0
- package/extensions/services/proxy/evol/presenter/configPresenter.py +1281 -0
- package/extensions/services/proxy/evol/presenter/userPresenter.py +477 -0
- package/extensions/services/proxy/evol/server/__init__.py +1 -0
- package/extensions/services/proxy/evol/server/claude_proxy_async.py +3430 -0
- package/extensions/services/proxy/evol/server/openclaw_proxy.py +1861 -0
- package/extensions/services/proxy/evol/server/proxy_config.py +15 -0
- package/extensions/services/proxy/evol/server/proxy_engine.py +501 -0
- package/extensions/services/proxy/evol/version.py +24 -0
- package/extensions/services/proxy/logs/websocket.log +260 -0
- package/extensions/services/proxy/main.py +240 -0
- package/extensions/services/proxy/requirements.txt +13 -0
- package/extensions/services/proxy/server.py +271 -0
- package/extensions/services/watchdog/entry.py +215 -26
- package/extensions/services/watchdog/module.md +1 -0
- package/extensions/services/watchdog/monitor.py +178 -38
- package/extensions/services/web/WEBSOCKET_STATUS.md +143 -0
- package/extensions/services/web/config_example.py +35 -0
- package/extensions/services/web/config_loader.py +110 -0
- package/extensions/services/web/entry.py +114 -26
- package/extensions/services/web/module.md +35 -24
- package/extensions/services/web/pairing.py +250 -0
- package/extensions/services/web/pairing_codes.jsonl +16 -0
- package/extensions/services/web/relay.py +643 -0
- package/extensions/services/web/relay_config.json5 +67 -0
- package/extensions/services/web/routes/routes_management_ws.py +127 -0
- package/extensions/services/web/routes/routes_rpc.py +89 -0
- package/extensions/services/web/routes/routes_test.py +61 -0
- package/extensions/services/web/routes/schemas.py +0 -22
- package/extensions/services/web/server.py +434 -99
- package/extensions/services/web/static/css/style.css +67 -28
- package/extensions/services/web/static/index.html +234 -44
- package/extensions/services/web/static/js/app.js +1335 -48
- package/extensions/services/web/static/js/kernel-client-example.js +161 -0
- package/extensions/services/web/static/js/kernel-client.js +383 -0
- package/extensions/services/web/static/js/registry-tests.js +558 -0
- package/extensions/services/web/static/js/token-manager.js +175 -0
- package/extensions/services/web/static/pairing.html +248 -0
- package/extensions/services/web/static/test_registry.html +262 -0
- package/extensions/services/web/web_config.json5 +29 -0
- package/kernel/entry.py +120 -32
- package/kernel/event_hub.py +141 -16
- package/kernel/module.md +60 -33
- package/kernel/registry_store.py +45 -36
- package/kernel/rpc_router.py +152 -59
- package/kernel/server.py +322 -26
- package/kite_cli/__init__.py +3 -0
- package/kite_cli/__main__.py +5 -0
- package/kite_cli/commands/__init__.py +1 -0
- package/kite_cli/commands/clean.py +101 -0
- package/kite_cli/commands/deps_install.py +67 -0
- package/kite_cli/commands/doctor.py +35 -0
- package/kite_cli/commands/env_check.py +45 -0
- package/kite_cli/commands/history.py +111 -0
- package/kite_cli/commands/info.py +96 -0
- package/kite_cli/commands/install.py +313 -0
- package/kite_cli/commands/list.py +143 -0
- package/kite_cli/commands/log.py +81 -0
- package/kite_cli/commands/prepare.py +49 -0
- package/kite_cli/commands/rollback.py +88 -0
- package/kite_cli/commands/search.py +73 -0
- package/kite_cli/commands/uninstall.py +85 -0
- package/kite_cli/commands/update.py +118 -0
- package/kite_cli/commands/venv_setup.py +56 -0
- package/kite_cli/core/__init__.py +1 -0
- package/kite_cli/core/checker.py +142 -0
- package/kite_cli/core/dependency.py +229 -0
- package/kite_cli/core/downloader.py +209 -0
- package/kite_cli/core/install_info.py +40 -0
- package/kite_cli/core/tool_installer.py +397 -0
- package/kite_cli/core/validator.py +78 -0
- package/kite_cli/main.py +317 -0
- package/kite_cli/utils/__init__.py +1 -0
- package/kite_cli/utils/i18n.py +252 -0
- package/kite_cli/utils/interactive.py +63 -0
- package/kite_cli/utils/operation_log.py +77 -0
- package/kite_cli/utils/paths.py +34 -0
- package/kite_cli/utils/version.py +308 -0
- package/launcher/entry.py +1124 -178
- package/launcher/logging_setup.py +104 -0
- package/launcher/module.md +46 -37
- package/launcher/module_scanner.py +11 -1
- package/main.py +4 -1
- package/package.json +9 -1
- package/python_version.json +4 -0
- package/requirements.txt +38 -0
- package/scripts/env-manager.js +328 -0
- package/scripts/plan_manager.py +315 -0
- package/scripts/python-env.js +79 -0
- package/scripts/scan_dependencies.py +461 -0
- package/scripts/setup-python-env.js +191 -0
- package/extensions/services/web/routes/routes_modules.py +0 -249
|
@@ -0,0 +1,325 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
"""
|
|
3
|
+
时间序列指标存储
|
|
4
|
+
|
|
5
|
+
使用 SQLite 存储时间序列监控数据,支持历史查询和趋势分析
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import sqlite3
|
|
9
|
+
import time
|
|
10
|
+
import threading
|
|
11
|
+
from typing import List, Dict, Any, Optional
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class MetricsStore:
|
|
15
|
+
"""时间序列数据存储(基于SQLite)
|
|
16
|
+
|
|
17
|
+
特性:
|
|
18
|
+
- 轻量级,无需额外部署
|
|
19
|
+
- 支持高效的时间范围查询
|
|
20
|
+
- 自动清理过期数据
|
|
21
|
+
- 线程安全
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
def __init__(self, db_path: str):
|
|
25
|
+
"""初始化时间序列存储
|
|
26
|
+
|
|
27
|
+
Args:
|
|
28
|
+
db_path: SQLite 数据库文件路径
|
|
29
|
+
"""
|
|
30
|
+
self.db_path = db_path
|
|
31
|
+
self.lock = threading.Lock()
|
|
32
|
+
self._init_db()
|
|
33
|
+
|
|
34
|
+
def _init_db(self):
|
|
35
|
+
"""初始化数据库表结构"""
|
|
36
|
+
with self.lock:
|
|
37
|
+
conn = sqlite3.connect(self.db_path)
|
|
38
|
+
cursor = conn.cursor()
|
|
39
|
+
|
|
40
|
+
# 创建时间序列表
|
|
41
|
+
cursor.execute('''
|
|
42
|
+
CREATE TABLE IF NOT EXISTS metrics_timeseries (
|
|
43
|
+
timestamp INTEGER PRIMARY KEY,
|
|
44
|
+
agent_id TEXT NOT NULL,
|
|
45
|
+
received_total INTEGER DEFAULT 0,
|
|
46
|
+
dispatched_success INTEGER DEFAULT 0,
|
|
47
|
+
dispatched_failed INTEGER DEFAULT 0,
|
|
48
|
+
handler_success INTEGER DEFAULT 0,
|
|
49
|
+
handler_failed INTEGER DEFAULT 0,
|
|
50
|
+
dispatch_queue_size INTEGER DEFAULT 0,
|
|
51
|
+
avg_dispatch_latency_ms REAL DEFAULT 0.0,
|
|
52
|
+
avg_handler_latency_ms REAL DEFAULT 0.0,
|
|
53
|
+
p50_dispatch_latency_ms REAL DEFAULT 0.0,
|
|
54
|
+
p95_dispatch_latency_ms REAL DEFAULT 0.0,
|
|
55
|
+
p99_dispatch_latency_ms REAL DEFAULT 0.0,
|
|
56
|
+
throughput_per_second REAL DEFAULT 0.0,
|
|
57
|
+
success_rate REAL DEFAULT 0.0
|
|
58
|
+
)
|
|
59
|
+
''')
|
|
60
|
+
|
|
61
|
+
# 创建索引(优化查询性能)
|
|
62
|
+
cursor.execute('''
|
|
63
|
+
CREATE INDEX IF NOT EXISTS idx_timestamp
|
|
64
|
+
ON metrics_timeseries(timestamp)
|
|
65
|
+
''')
|
|
66
|
+
cursor.execute('''
|
|
67
|
+
CREATE INDEX IF NOT EXISTS idx_agent_id_timestamp
|
|
68
|
+
ON metrics_timeseries(agent_id, timestamp)
|
|
69
|
+
''')
|
|
70
|
+
|
|
71
|
+
conn.commit()
|
|
72
|
+
conn.close()
|
|
73
|
+
|
|
74
|
+
def insert_snapshot(self, metrics: dict):
|
|
75
|
+
"""插入一个时间点的指标快照(非阻塞)
|
|
76
|
+
|
|
77
|
+
Args:
|
|
78
|
+
metrics: 指标字典,必须包含以下字段:
|
|
79
|
+
- agent_id: AgentID 标识
|
|
80
|
+
- timestamp: 时间戳(可选,默认当前时间)
|
|
81
|
+
- received_total: 累计接收消息总数
|
|
82
|
+
- dispatched_success: 累计派发成功数
|
|
83
|
+
- dispatched_failed: 累计派发失败数
|
|
84
|
+
- handler_success: 累计处理成功数(可选)
|
|
85
|
+
- handler_failed: 累计处理失败数(可选)
|
|
86
|
+
- dispatch_queue_size: 当前派发队列大小
|
|
87
|
+
- avg_dispatch_latency_ms: 平均派发延迟(可选)
|
|
88
|
+
- avg_handler_latency_ms: 平均处理延迟(可选)
|
|
89
|
+
- p50_dispatch_latency_ms: P50延迟(可选)
|
|
90
|
+
- p95_dispatch_latency_ms: P95延迟(可选)
|
|
91
|
+
- p99_dispatch_latency_ms: P99延迟(可选)
|
|
92
|
+
"""
|
|
93
|
+
timestamp = metrics.get('timestamp', int(time.time()))
|
|
94
|
+
if isinstance(timestamp, float):
|
|
95
|
+
timestamp = int(timestamp)
|
|
96
|
+
|
|
97
|
+
# ✅ 使用 trylock 模式:如果锁被占用,跳过本次写入(不阻塞)
|
|
98
|
+
locked = self.lock.acquire(blocking=False)
|
|
99
|
+
if not locked:
|
|
100
|
+
# 锁被占用,跳过本次写入(避免阻塞主流程)
|
|
101
|
+
return
|
|
102
|
+
|
|
103
|
+
try:
|
|
104
|
+
conn = sqlite3.connect(self.db_path, timeout=1.0) # 1秒超时
|
|
105
|
+
cursor = conn.cursor()
|
|
106
|
+
|
|
107
|
+
try:
|
|
108
|
+
# 计算吞吐量和成功率
|
|
109
|
+
received_total = metrics.get('received_total', 0)
|
|
110
|
+
dispatched_success = metrics.get('dispatched_success', 0)
|
|
111
|
+
uptime = metrics.get('uptime_seconds', 1)
|
|
112
|
+
|
|
113
|
+
throughput = received_total / max(uptime, 1)
|
|
114
|
+
success_rate = (dispatched_success / max(received_total, 1)) * 100 if received_total > 0 else 0.0
|
|
115
|
+
|
|
116
|
+
cursor.execute('''
|
|
117
|
+
INSERT OR REPLACE INTO metrics_timeseries (
|
|
118
|
+
timestamp, agent_id, received_total, dispatched_success,
|
|
119
|
+
dispatched_failed, handler_success, handler_failed,
|
|
120
|
+
dispatch_queue_size, avg_dispatch_latency_ms, avg_handler_latency_ms,
|
|
121
|
+
p50_dispatch_latency_ms, p95_dispatch_latency_ms, p99_dispatch_latency_ms,
|
|
122
|
+
throughput_per_second, success_rate
|
|
123
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
124
|
+
''', (
|
|
125
|
+
timestamp,
|
|
126
|
+
metrics.get('agent_id', 'unknown'),
|
|
127
|
+
received_total,
|
|
128
|
+
dispatched_success,
|
|
129
|
+
metrics.get('dispatched_failed', 0),
|
|
130
|
+
metrics.get('handler_success', 0),
|
|
131
|
+
metrics.get('handler_failed', 0),
|
|
132
|
+
metrics.get('dispatch_queue_size', 0),
|
|
133
|
+
self._safe_float(metrics.get('avg_dispatch_latency_ms')),
|
|
134
|
+
self._safe_float(metrics.get('avg_handler_latency_ms')),
|
|
135
|
+
self._safe_float(metrics.get('p50_dispatch_latency_ms')),
|
|
136
|
+
self._safe_float(metrics.get('p95_dispatch_latency_ms')),
|
|
137
|
+
self._safe_float(metrics.get('p99_dispatch_latency_ms')),
|
|
138
|
+
throughput,
|
|
139
|
+
success_rate,
|
|
140
|
+
))
|
|
141
|
+
|
|
142
|
+
conn.commit()
|
|
143
|
+
except Exception as e:
|
|
144
|
+
print(f"❌ [MetricsStore] 插入数据失败: {e}")
|
|
145
|
+
conn.rollback()
|
|
146
|
+
finally:
|
|
147
|
+
conn.close()
|
|
148
|
+
finally:
|
|
149
|
+
# ✅ 确保释放锁(无论是否成功)
|
|
150
|
+
self.lock.release()
|
|
151
|
+
|
|
152
|
+
def _safe_float(self, value) -> float:
|
|
153
|
+
"""安全地转换为浮点数
|
|
154
|
+
|
|
155
|
+
Args:
|
|
156
|
+
value: 待转换的值
|
|
157
|
+
|
|
158
|
+
Returns:
|
|
159
|
+
转换后的浮点数,失败返回0.0
|
|
160
|
+
"""
|
|
161
|
+
if value is None:
|
|
162
|
+
return 0.0
|
|
163
|
+
if isinstance(value, str):
|
|
164
|
+
try:
|
|
165
|
+
return float(value)
|
|
166
|
+
except ValueError:
|
|
167
|
+
return 0.0
|
|
168
|
+
return float(value)
|
|
169
|
+
|
|
170
|
+
def query_range(
|
|
171
|
+
self,
|
|
172
|
+
from_ts: int,
|
|
173
|
+
to_ts: int,
|
|
174
|
+
agent_id: Optional[str] = None,
|
|
175
|
+
limit: int = 1000
|
|
176
|
+
) -> List[Dict[str, Any]]:
|
|
177
|
+
"""查询时间范围内的数据
|
|
178
|
+
|
|
179
|
+
Args:
|
|
180
|
+
from_ts: 起始时间戳
|
|
181
|
+
to_ts: 结束时间戳
|
|
182
|
+
agent_id: AgentID 过滤(可选)
|
|
183
|
+
limit: 最大返回记录数
|
|
184
|
+
|
|
185
|
+
Returns:
|
|
186
|
+
时间序列数据列表
|
|
187
|
+
"""
|
|
188
|
+
with self.lock:
|
|
189
|
+
conn = sqlite3.connect(self.db_path)
|
|
190
|
+
cursor = conn.cursor()
|
|
191
|
+
|
|
192
|
+
try:
|
|
193
|
+
if agent_id:
|
|
194
|
+
cursor.execute('''
|
|
195
|
+
SELECT * FROM metrics_timeseries
|
|
196
|
+
WHERE timestamp >= ? AND timestamp <= ? AND agent_id = ?
|
|
197
|
+
ORDER BY timestamp ASC
|
|
198
|
+
LIMIT ?
|
|
199
|
+
''', (from_ts, to_ts, agent_id, limit))
|
|
200
|
+
else:
|
|
201
|
+
cursor.execute('''
|
|
202
|
+
SELECT * FROM metrics_timeseries
|
|
203
|
+
WHERE timestamp >= ? AND timestamp <= ?
|
|
204
|
+
ORDER BY timestamp ASC
|
|
205
|
+
LIMIT ?
|
|
206
|
+
''', (from_ts, to_ts, limit))
|
|
207
|
+
|
|
208
|
+
rows = cursor.fetchall()
|
|
209
|
+
return [self._row_to_dict(row) for row in rows]
|
|
210
|
+
finally:
|
|
211
|
+
conn.close()
|
|
212
|
+
|
|
213
|
+
def query_latest(self, agent_id: Optional[str] = None, limit: int = 100) -> List[Dict[str, Any]]:
|
|
214
|
+
"""查询最新的数据点
|
|
215
|
+
|
|
216
|
+
Args:
|
|
217
|
+
agent_id: AgentID 过滤(可选)
|
|
218
|
+
limit: 最大返回记录数
|
|
219
|
+
|
|
220
|
+
Returns:
|
|
221
|
+
最新的时间序列数据列表
|
|
222
|
+
"""
|
|
223
|
+
with self.lock:
|
|
224
|
+
conn = sqlite3.connect(self.db_path)
|
|
225
|
+
cursor = conn.cursor()
|
|
226
|
+
|
|
227
|
+
try:
|
|
228
|
+
if agent_id:
|
|
229
|
+
cursor.execute('''
|
|
230
|
+
SELECT * FROM metrics_timeseries
|
|
231
|
+
WHERE agent_id = ?
|
|
232
|
+
ORDER BY timestamp DESC
|
|
233
|
+
LIMIT ?
|
|
234
|
+
''', (agent_id, limit))
|
|
235
|
+
else:
|
|
236
|
+
cursor.execute('''
|
|
237
|
+
SELECT * FROM metrics_timeseries
|
|
238
|
+
ORDER BY timestamp DESC
|
|
239
|
+
LIMIT ?
|
|
240
|
+
''', (limit,))
|
|
241
|
+
|
|
242
|
+
rows = cursor.fetchall()
|
|
243
|
+
return [self._row_to_dict(row) for row in rows]
|
|
244
|
+
finally:
|
|
245
|
+
conn.close()
|
|
246
|
+
|
|
247
|
+
def _row_to_dict(self, row) -> Dict[str, Any]:
|
|
248
|
+
"""将数据库行转换为字典
|
|
249
|
+
|
|
250
|
+
Args:
|
|
251
|
+
row: 数据库查询结果行
|
|
252
|
+
|
|
253
|
+
Returns:
|
|
254
|
+
包含所有字段的字典
|
|
255
|
+
"""
|
|
256
|
+
columns = [
|
|
257
|
+
'timestamp', 'agent_id', 'received_total', 'dispatched_success',
|
|
258
|
+
'dispatched_failed', 'handler_success', 'handler_failed',
|
|
259
|
+
'dispatch_queue_size', 'avg_dispatch_latency_ms', 'avg_handler_latency_ms',
|
|
260
|
+
'p50_dispatch_latency_ms', 'p95_dispatch_latency_ms', 'p99_dispatch_latency_ms',
|
|
261
|
+
'throughput_per_second', 'success_rate'
|
|
262
|
+
]
|
|
263
|
+
return dict(zip(columns, row))
|
|
264
|
+
|
|
265
|
+
def cleanup_old_data(self, retention_days: int = 7):
|
|
266
|
+
"""清理过期数据
|
|
267
|
+
|
|
268
|
+
Args:
|
|
269
|
+
retention_days: 数据保留天数(默认7天)
|
|
270
|
+
"""
|
|
271
|
+
cutoff = int(time.time()) - (retention_days * 86400)
|
|
272
|
+
|
|
273
|
+
with self.lock:
|
|
274
|
+
conn = sqlite3.connect(self.db_path)
|
|
275
|
+
cursor = conn.cursor()
|
|
276
|
+
|
|
277
|
+
try:
|
|
278
|
+
cursor.execute('DELETE FROM metrics_timeseries WHERE timestamp < ?', (cutoff,))
|
|
279
|
+
deleted_count = cursor.rowcount
|
|
280
|
+
conn.commit()
|
|
281
|
+
|
|
282
|
+
if deleted_count > 0:
|
|
283
|
+
print(f"🧹 [MetricsStore] 清理了 {deleted_count} 条过期数据 (>{retention_days}天)")
|
|
284
|
+
except Exception as e:
|
|
285
|
+
print(f"❌ [MetricsStore] 清理数据失败: {e}")
|
|
286
|
+
conn.rollback()
|
|
287
|
+
finally:
|
|
288
|
+
conn.close()
|
|
289
|
+
|
|
290
|
+
def get_stats(self) -> Dict[str, Any]:
|
|
291
|
+
"""获取数据库统计信息
|
|
292
|
+
|
|
293
|
+
Returns:
|
|
294
|
+
包含数据库统计信息的字典
|
|
295
|
+
"""
|
|
296
|
+
with self.lock:
|
|
297
|
+
conn = sqlite3.connect(self.db_path)
|
|
298
|
+
cursor = conn.cursor()
|
|
299
|
+
|
|
300
|
+
try:
|
|
301
|
+
# 查询总记录数
|
|
302
|
+
cursor.execute('SELECT COUNT(*) FROM metrics_timeseries')
|
|
303
|
+
total_records = cursor.fetchone()[0]
|
|
304
|
+
|
|
305
|
+
# 查询时间范围
|
|
306
|
+
cursor.execute('SELECT MIN(timestamp), MAX(timestamp) FROM metrics_timeseries')
|
|
307
|
+
min_ts, max_ts = cursor.fetchone()
|
|
308
|
+
|
|
309
|
+
# 查询不同 agent_id 数量
|
|
310
|
+
cursor.execute('SELECT COUNT(DISTINCT agent_id) FROM metrics_timeseries')
|
|
311
|
+
agent_count = cursor.fetchone()[0]
|
|
312
|
+
|
|
313
|
+
return {
|
|
314
|
+
'total_records': total_records,
|
|
315
|
+
'min_timestamp': min_ts,
|
|
316
|
+
'max_timestamp': max_ts,
|
|
317
|
+
'agent_count': agent_count,
|
|
318
|
+
'db_path': self.db_path,
|
|
319
|
+
}
|
|
320
|
+
finally:
|
|
321
|
+
conn.close()
|
|
322
|
+
|
|
323
|
+
def close(self):
|
|
324
|
+
"""关闭存储(预留接口,SQLite 会自动管理连接)"""
|
|
325
|
+
pass
|
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
"""
|
|
3
|
+
统一监控服务
|
|
4
|
+
|
|
5
|
+
集成滑动窗口统计和时间序列存储,提供完整的监控解决方案
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import threading
|
|
9
|
+
import time
|
|
10
|
+
from typing import Dict, Any, List, Optional
|
|
11
|
+
|
|
12
|
+
from .sliding_window import SlidingWindowMetrics
|
|
13
|
+
from .metrics_store import MetricsStore
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class MonitoringService:
|
|
17
|
+
"""统一监控服务
|
|
18
|
+
|
|
19
|
+
职责:
|
|
20
|
+
- 定期采集指标快照(每10秒)
|
|
21
|
+
- 更新滑动窗口统计
|
|
22
|
+
- 持久化到时间序列存储
|
|
23
|
+
- 提供实时和历史数据查询接口
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
def __init__(
|
|
27
|
+
self,
|
|
28
|
+
agent_id: str,
|
|
29
|
+
metrics_collector,
|
|
30
|
+
db_path: str,
|
|
31
|
+
snapshot_interval: int = 10
|
|
32
|
+
):
|
|
33
|
+
"""初始化监控服务
|
|
34
|
+
|
|
35
|
+
Args:
|
|
36
|
+
agent_id: AgentID 标识
|
|
37
|
+
metrics_collector: MessageMetrics 实例
|
|
38
|
+
db_path: 时间序列数据库路径
|
|
39
|
+
snapshot_interval: 快照间隔(秒),默认10秒
|
|
40
|
+
"""
|
|
41
|
+
self.agent_id = agent_id
|
|
42
|
+
self.metrics_collector = metrics_collector
|
|
43
|
+
self.snapshot_interval = snapshot_interval
|
|
44
|
+
|
|
45
|
+
# 初始化组件
|
|
46
|
+
self.sliding_windows = SlidingWindowMetrics()
|
|
47
|
+
self.metrics_store = MetricsStore(db_path)
|
|
48
|
+
|
|
49
|
+
# 线程控制
|
|
50
|
+
self._running = False
|
|
51
|
+
self._snapshot_thread: Optional[threading.Thread] = None
|
|
52
|
+
|
|
53
|
+
# 统计信息
|
|
54
|
+
self._snapshot_count = 0
|
|
55
|
+
self._last_cleanup_time = time.time()
|
|
56
|
+
|
|
57
|
+
def start(self):
|
|
58
|
+
"""启动监控服务"""
|
|
59
|
+
if self._running:
|
|
60
|
+
print(f"⚠️ [MonitoringService] 监控服务已在运行")
|
|
61
|
+
return
|
|
62
|
+
|
|
63
|
+
self._running = True
|
|
64
|
+
self._snapshot_thread = threading.Thread(
|
|
65
|
+
target=self._snapshot_loop,
|
|
66
|
+
daemon=True,
|
|
67
|
+
name=f"MetricsSnapshot-{self.agent_id}"
|
|
68
|
+
)
|
|
69
|
+
self._snapshot_thread.start()
|
|
70
|
+
print(f"📊 [MonitoringService] 已启动 (agent_id={self.agent_id}, interval={self.snapshot_interval}s)")
|
|
71
|
+
|
|
72
|
+
def stop(self, wait: bool = True):
|
|
73
|
+
"""停止监控服务
|
|
74
|
+
|
|
75
|
+
Args:
|
|
76
|
+
wait: 是否等待线程完全停止(默认True)
|
|
77
|
+
设为False可避免阻塞主流程
|
|
78
|
+
"""
|
|
79
|
+
if not self._running:
|
|
80
|
+
return
|
|
81
|
+
|
|
82
|
+
self._running = False
|
|
83
|
+
|
|
84
|
+
# 如果需要等待线程停止
|
|
85
|
+
if wait and self._snapshot_thread and self._snapshot_thread.is_alive():
|
|
86
|
+
self._snapshot_thread.join(timeout=5.0)
|
|
87
|
+
|
|
88
|
+
# 最后一次快照保存(仅在等待模式下执行)
|
|
89
|
+
if wait:
|
|
90
|
+
try:
|
|
91
|
+
self._take_snapshot()
|
|
92
|
+
print(f"📊 [MonitoringService] 已停止 (共采集 {self._snapshot_count} 次快照)")
|
|
93
|
+
except Exception as e:
|
|
94
|
+
print(f"⚠️ [MonitoringService] 最终快照失败: {e}")
|
|
95
|
+
else:
|
|
96
|
+
print(f"📊 [MonitoringService] 停止信号已发送(非阻塞模式)")
|
|
97
|
+
|
|
98
|
+
if wait:
|
|
99
|
+
self._snapshot_thread = None
|
|
100
|
+
|
|
101
|
+
def _snapshot_loop(self):
|
|
102
|
+
"""快照循环 - 每N秒收集一次数据"""
|
|
103
|
+
while self._running:
|
|
104
|
+
try:
|
|
105
|
+
self._take_snapshot()
|
|
106
|
+
|
|
107
|
+
# 定期清理旧数据(每小时一次)
|
|
108
|
+
now = time.time()
|
|
109
|
+
if now - self._last_cleanup_time > 3600:
|
|
110
|
+
self._cleanup_old_data()
|
|
111
|
+
self._last_cleanup_time = now
|
|
112
|
+
|
|
113
|
+
except Exception as e:
|
|
114
|
+
print(f"❌ [MonitoringService] 快照失败: {e}")
|
|
115
|
+
import traceback
|
|
116
|
+
traceback.print_exc()
|
|
117
|
+
|
|
118
|
+
# 等待下一次快照
|
|
119
|
+
time.sleep(self.snapshot_interval)
|
|
120
|
+
|
|
121
|
+
def _take_snapshot(self):
|
|
122
|
+
"""执行一次快照采集(非阻塞)"""
|
|
123
|
+
try:
|
|
124
|
+
# 1. 获取当前指标(使用 timeout 防止阻塞)
|
|
125
|
+
current_metrics = self.metrics_collector.get_summary()
|
|
126
|
+
current_metrics['agent_id'] = self.agent_id
|
|
127
|
+
current_metrics['timestamp'] = time.time()
|
|
128
|
+
except Exception as e:
|
|
129
|
+
# 获取指标失败,跳过本次快照(不影响核心流程)
|
|
130
|
+
print(f"⚠️ [MonitoringService] 获取指标失败,跳过本次快照: {e}")
|
|
131
|
+
return
|
|
132
|
+
|
|
133
|
+
# 解析字符串格式的指标(兼容现有 MessageMetrics)
|
|
134
|
+
self._parse_metrics(current_metrics)
|
|
135
|
+
|
|
136
|
+
# 2. 更新滑动窗口
|
|
137
|
+
self.sliding_windows.update(current_metrics)
|
|
138
|
+
|
|
139
|
+
# 3. 存储到时间序列数据库
|
|
140
|
+
self.metrics_store.insert_snapshot(current_metrics)
|
|
141
|
+
|
|
142
|
+
self._snapshot_count += 1
|
|
143
|
+
|
|
144
|
+
# 调试日志(可选)
|
|
145
|
+
if self._snapshot_count % 6 == 0: # 每1分钟打印一次
|
|
146
|
+
print(
|
|
147
|
+
f"📊 [MonitoringService] 快照 #{self._snapshot_count}: "
|
|
148
|
+
f"received={current_metrics.get('received_total', 0)}, "
|
|
149
|
+
f"queue={current_metrics.get('dispatch_queue_size', 0)}"
|
|
150
|
+
)
|
|
151
|
+
|
|
152
|
+
def _parse_metrics(self, metrics: dict):
|
|
153
|
+
"""解析和标准化指标数据
|
|
154
|
+
|
|
155
|
+
处理现有 MessageMetrics 返回的字符串格式指标
|
|
156
|
+
"""
|
|
157
|
+
# 解析延迟数据(从嵌套字典中提取)
|
|
158
|
+
if 'dispatch_latency' in metrics and isinstance(metrics['dispatch_latency'], dict):
|
|
159
|
+
dispatch_latency = metrics['dispatch_latency']
|
|
160
|
+
metrics['avg_dispatch_latency_ms'] = self._parse_float(dispatch_latency.get('avg_ms', '0'))
|
|
161
|
+
metrics['p50_dispatch_latency_ms'] = self._parse_float(dispatch_latency.get('p50_ms', '0'))
|
|
162
|
+
metrics['p95_dispatch_latency_ms'] = self._parse_float(dispatch_latency.get('p95_ms', '0'))
|
|
163
|
+
metrics['p99_dispatch_latency_ms'] = self._parse_float(dispatch_latency.get('p99_ms', '0'))
|
|
164
|
+
|
|
165
|
+
if 'handler_latency' in metrics and isinstance(metrics['handler_latency'], dict):
|
|
166
|
+
handler_latency = metrics['handler_latency']
|
|
167
|
+
metrics['avg_handler_latency_ms'] = self._parse_float(handler_latency.get('avg_ms', '0'))
|
|
168
|
+
|
|
169
|
+
# 解析运行时间
|
|
170
|
+
if 'uptime_seconds' in metrics:
|
|
171
|
+
metrics['uptime_seconds'] = self._parse_float(metrics['uptime_seconds'])
|
|
172
|
+
|
|
173
|
+
def _parse_float(self, value) -> float:
|
|
174
|
+
"""安全地解析浮点数"""
|
|
175
|
+
if isinstance(value, (int, float)):
|
|
176
|
+
return float(value)
|
|
177
|
+
if isinstance(value, str):
|
|
178
|
+
try:
|
|
179
|
+
return float(value)
|
|
180
|
+
except ValueError:
|
|
181
|
+
return 0.0
|
|
182
|
+
return 0.0
|
|
183
|
+
|
|
184
|
+
def _cleanup_old_data(self):
|
|
185
|
+
"""清理旧数据"""
|
|
186
|
+
try:
|
|
187
|
+
self.metrics_store.cleanup_old_data(retention_days=7)
|
|
188
|
+
except Exception as e:
|
|
189
|
+
print(f"⚠️ [MonitoringService] 清理旧数据失败: {e}")
|
|
190
|
+
|
|
191
|
+
def get_realtime_metrics(self) -> Dict[str, Any]:
|
|
192
|
+
"""获取实时指标(包括所有时间窗口)
|
|
193
|
+
|
|
194
|
+
Returns:
|
|
195
|
+
包含以下内容的字典:
|
|
196
|
+
- agent_id: AgentID 标识
|
|
197
|
+
- timestamp: 当前时间戳
|
|
198
|
+
- cumulative: 累计指标(来自 MessageMetrics)
|
|
199
|
+
- windows: 所有时间窗口的统计数据
|
|
200
|
+
"""
|
|
201
|
+
base_metrics = self.metrics_collector.get_summary()
|
|
202
|
+
window_stats = self.sliding_windows.get_all_windows()
|
|
203
|
+
|
|
204
|
+
return {
|
|
205
|
+
'agent_id': self.agent_id,
|
|
206
|
+
'timestamp': time.time(),
|
|
207
|
+
'cumulative': base_metrics, # 累计指标
|
|
208
|
+
'windows': window_stats, # 时间窗口指标
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
def get_window_metrics(self, window_names: List[str]) -> Dict[str, Dict[str, Any]]:
|
|
212
|
+
"""获取指定时间窗口的指标
|
|
213
|
+
|
|
214
|
+
Args:
|
|
215
|
+
window_names: 窗口名称列表,如 ['1m', '3m', '5m']
|
|
216
|
+
|
|
217
|
+
Returns:
|
|
218
|
+
窗口统计数据字典
|
|
219
|
+
"""
|
|
220
|
+
all_windows = self.sliding_windows.get_all_windows()
|
|
221
|
+
return {
|
|
222
|
+
name: all_windows.get(name, {})
|
|
223
|
+
for name in window_names
|
|
224
|
+
if name in all_windows
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
def get_history(self, from_ts: int, to_ts: int, limit: int = 1000) -> List[Dict[str, Any]]:
|
|
228
|
+
"""获取历史数据
|
|
229
|
+
|
|
230
|
+
Args:
|
|
231
|
+
from_ts: 起始时间戳
|
|
232
|
+
to_ts: 结束时间戳
|
|
233
|
+
limit: 最大返回记录数
|
|
234
|
+
|
|
235
|
+
Returns:
|
|
236
|
+
历史数据列表
|
|
237
|
+
"""
|
|
238
|
+
return self.metrics_store.query_range(from_ts, to_ts, self.agent_id, limit)
|
|
239
|
+
|
|
240
|
+
def get_latest_history(self, limit: int = 100) -> List[Dict[str, Any]]:
|
|
241
|
+
"""获取最新的历史数据
|
|
242
|
+
|
|
243
|
+
Args:
|
|
244
|
+
limit: 最大返回记录数
|
|
245
|
+
|
|
246
|
+
Returns:
|
|
247
|
+
最新的历史数据列表
|
|
248
|
+
"""
|
|
249
|
+
return self.metrics_store.query_latest(self.agent_id, limit)
|
|
250
|
+
|
|
251
|
+
def get_service_info(self) -> Dict[str, Any]:
|
|
252
|
+
"""获取监控服务信息
|
|
253
|
+
|
|
254
|
+
Returns:
|
|
255
|
+
包含服务状态和统计信息的字典
|
|
256
|
+
"""
|
|
257
|
+
store_stats = self.metrics_store.get_stats()
|
|
258
|
+
|
|
259
|
+
return {
|
|
260
|
+
'agent_id': self.agent_id,
|
|
261
|
+
'running': self._running,
|
|
262
|
+
'snapshot_interval': self.snapshot_interval,
|
|
263
|
+
'snapshot_count': self._snapshot_count,
|
|
264
|
+
'store_stats': store_stats,
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
def reset_windows(self):
|
|
268
|
+
"""重置所有时间窗口(用于测试)"""
|
|
269
|
+
self.sliding_windows.reset()
|