OpenSandbox SDK Telemetry 详解:沙箱创建耗时指标的上报链路、服务端落地与禁用方式
2026/9/14 15:07:33 网站建设 项目流程

OpenSandbox SDK Telemetry 详解:沙箱创建耗时指标的上报链路、服务端落地与禁用方式

【免费下载链接】OpenSandboxSecure, Fast, and Extensible Sandbox runtime for AI agents.项目地址: https://gitcode.com/GitHub_Trending/ope/OpenSandbox

OpenSandbox 的各语言 SDK 会"尽力而为"地将沙箱创建耗时(sandbox creation latency)上报到生命周期服务端,用于构建端到端的创建延迟直方图。本文基于官方指南 SDK Telemetry,完整梳理其上报机制、版本要求、载荷结构、服务端 OTEL 落地细节与禁用方式,并结合仓库源码说明 fire-and-forget 实现原理,帮助你在生产环境正确启用、观测或关闭这套遥测能力。

设计定位:best-effort 且不携带用户内容

SDK 遥测只有一个核心指标:sandbox.create事件的创建耗时。其设计原则在官方文档中表述得非常明确:

  • 上报是 best-effort 的:任何上报失败(网络错误、TLS 失败、超时、服务端 404)都不会影响Sandbox.create的行为,也不会向用户抛出可见错误;
  • 载荷不含用户内容:上报体只有沙箱 ID、镜像、耗时与成败标志,不包含命令、文件等任何用户数据。

这一"fire-and-forget"(发射后不管)语义是贯穿全部 SDK 的一致性约定,也是 SDK 与服务端可以独立升级(版本 skew)的前提。

版本要求与版本漂移(Version skew)

POST /v1/metrics/events端点与各 SDK 上报器要求如下最低版本。低于这些版本的 SDK 直接不发送事件,旧服务端则会以404拒绝未知路由,SDK 会静默吞掉该响应:

组件最低版本
Server(opensandbox-server0.2.2
Python SDK(opensandbox0.1.15
JavaScript / TypeScript SDK(@alibaba-group/opensandbox0.1.11
Go SDK(github.com/alibaba/OpenSandbox/sdks/sandbox/go1.0.5
C# SDK(Alibaba.OpenSandbox0.1.5
Kotlin / Java SDK(com.alibaba.opensandbox:sandbox1.0.17

由于每个 SDK 中的上报都是后台任务/线程中的 fire-and-forget,任何异常或非 2xx 响应都会被捕获并仅在 debug 级别记录日志,因此可以独立升级 SDK 与服务端:

  • 新 SDK + 旧服务端(< 0.2.2):服务端对/v1/metrics/events返回404,SDK 忽略该响应,Sandbox.create行为不变,唯一副作用是每次 create 多一条 debug 日志;
  • 旧 SDK + 新服务端:SDK 不发送事件,服务端直方图对该客户端不记录任何样本;
  • 网络错误、TLS 失败、超时:行为与 404 一致——被吞掉,Sandbox.create不受影响。

上报载荷:POST /v1/metrics/events

create 成功或失败后,SDK 会以后台方式向POST /v1/metrics/events发送如下 JSON:

{ "eventType": "sandbox.create", "sandboxId": "sbx_...", "image": "python:3.12", "createDurationMs": 1842, "success": true }

结合服务端请求模型 MetricsEvent,各字段的约束可以进一步确认:

字段类型/约束说明
eventType必填,固定字面量"sandbox.create"当前阶段唯一的指标事件类型(schema 注释标注为 Phase 1)
sandboxId可选字符串创建失败在早期阶段时可能缺省
image可选字符串容器镜像 URI,或快照启动的来源标签
createDurationMs必填,整数且>= 0从 create 开始到就绪或失败的墙钟耗时(毫秒)
success必填布尔create + readiness 是否全部成功完成

另外两点容易忽略的细节:

  1. SDK 语言与版本不放在 body 里,而是来自 HTTPUser-Agent头(例如OpenSandbox-Python-SDK/0.1.15)。服务端在 metrics.py 中用正则OpenSandbox-([A-Za-z0-9]+)-SDK/([^\s]+)解析出(language, version),解析失败则回退为unknown/unknown
  2. sandboxId/image在创建早期失败时可能整体缺省,因此 schema 中两者均为Optional

服务端接受事件后返回204 No Content;当服务端的[otel]配置启用时,会额外记录一条 OTEL 直方图样本(见下一节)。

服务端落地:从 HTTP 事件到 OTEL 直方图

服务端的处理链路非常短,全部实现在 server/opensandbox_server/api/metrics.py:

  1. 端点 report_metrics_event 校验MetricsEvent载荷,从User-Agent头解析 SDK 语言与版本;
  2. 当事件类型为sandbox.create时,调用 record_sandbox_create_duration 记录样本;
  3. 以 debug 级别记录一行sandbox_id / image / duration_ms / sdk / success摘要日志;
  4. 返回204

直方图指标本身定义在 server/opensandbox_server/integrations/otel/metrics.py,关键参数为:

  • 指标名opensandbox.sandbox.create.duration,单位ms
  • 显式桶边界(ExplicitBucketHistogramAggregation)100, 250, 500, 1000, 2500, 5000, 10000, 30000, 60000(毫秒),即从百毫秒级到分钟级覆盖典型沙箱创建延迟区间;
  • 属性标签sdk.languagesdk.versionsuccess,可用于按 SDK 语言/版本切分延迟分布;
  • 导出[otel] enabled=true时通过 OTLP HTTP 导出器 +PeriodicExportingMetricReader周期导出(见 server 配置文档);enabled=false时 histogram 为Nonerecord_sandbox_create_duration直接 no-op 返回——事件端点本身仍正常接受并返回204

从源码结构看,服务端还有一个值得注意的健壮性细节:即使全局MeterProvider已存在(例如宿主进程自带 OTel 初始化),服务端也会把 instrument 绑定到自建 provider 以保证走自己的 OTLP reader,且record_sandbox_create_duration内部对hist.record的异常做了兜底捕获,"Never raises"。

触发时机:各 SDK 分别在何时上报

官方文档给出了每个 SDK 的触发点,这里完整继承:

SDK触发时机
Python(async + sync)Sandbox.create/ 同步 create 完成或抛出异常后
JavaScript / TypeScriptSandbox.create完成或失败后
GoCreateSandbox完成或失败后
C#Sandbox.CreateAsync完成或失败后
Kotlin独立Sandbox.builder()...build()或池 direct-create 兜底路径完成或失败后

Kotlin 分阶段(staged)池预热是有意例外:Kotlin staged warmup 刻意发送sandbox.create事件。原因是其 create 阶段在就绪轮询、可选准备、post-prepare 校验、续期与 idle commit 之前就已返回,若把这个不完整阶段当作端到端创建延迟上报,会让该指标的含义与独立 create 的直方图不一致。该排除仅针对 staged warmup 路径——独立 create 与池 direct-create 兜底仍正常上报;要观测完整的 staged-warmup 生命周期,应使用池的结构化 summary 日志和可选的 warmup tracing(见 SDK Tracing 指南)。

源码纵深:fire-and-forget 是如何保证"绝不影响 create"的

以 Python SDK 的上报器 lifecycle_metrics.py 为例,可以看到 best-effort 语义的具体实现手法,其余 SDK(Go lifecycle_metrics.go、C# LifecycleMetricsReporter.cs、Kotlin LifecycleMetricsReporter.kt、JS/TS lifecycleMetrics.ts)结构同构:

  1. 双层开关判断_metrics_disabled(config)同时检查连接配置的disable_metrics字段与环境变量OPENSANDBOX_DISABLE_METRICS(值为"1"时生效),任一命中即直接返回;
  2. 顶层 try/except 包住整个函数体:文档注释明确解释了这样做的动机——该函数同样被Sandbox.create失败路径调用,如果上报器自身抛异常(哪怕只是构造 payload 失败),遥测异常会"替换"掉原始的 create 失败。因此 payload 构造与任务/线程调度全部纳入顶层保护;
  3. 事件循环内用asyncio.Task,线程上下文用守护线程report_sandbox_create_metric通过asyncio.get_running_loop()判断运行环境——在事件循环中创建后台 task,否则启动threading.Thread(daemon=True)同步 POST,两种路径都只记录 debug 日志;
  4. 强引用防止任务被 GC:模块级_pending: set[asyncio.Task]保存所有在飞任务,task 完成时通过add_done_callback自动摘除,避免 fire-and-forget 任务在中途被垃圾回收;
  5. 不复用 SDK 共享 transport:同步路径故意新建独立的httpx.Client,注释说明复用共享 transport 会在关闭 client 时连带关闭其他 adapter 的连接;
  6. 鉴权头透传:请求头包含Content-Type: application/json,透传配置中的自定义 headers,并自动附带OPEN-SANDBOX-API-KEYUser-Agent(后者正是服务端解析 SDK 语言/版本的依据)。

超时则直接复用连接配置的request_timeout。整体效果是:遥测路径上的任何故障(DNS、TLS、超时、4xx/5xx)都止步于一条 debug 日志。

如何禁用遥测

遥测默认开启,可通过两种方式退出(opt out):

方式一:环境变量(所有 SDK 通用)

export OPENSANDBOX_DISABLE_METRICS=1

方式二:连接配置字段(按语言设置)

Python:

from opensandbox import ConnectionConfig, Sandbox config = ConnectionConfig(disable_metrics=True) sandbox = await Sandbox.create("python:3.12", connection_config=config)

JavaScript / TypeScript:

import { ConnectionConfig, Sandbox } from "@alibaba-group/opensandbox"; const connectionConfig = new ConnectionConfig({ disableMetrics: true }); const sandbox = await Sandbox.create({ image: "python:3.12", connectionConfig, });

Go:

cfg := opensandbox.ConnectionConfig{DisableMetrics: true} sandbox, err := opensandbox.CreateSandbox(ctx, cfg, opensandbox.SandboxCreateOptions{ Image: "python:3.12", })

C#:

using OpenSandbox; using OpenSandbox.Config; var connectionConfig = new ConnectionConfig(new ConnectionConfigOptions { DisableMetrics = true, }); var sandbox = await Sandbox.CreateAsync(new SandboxCreateOptions { Image = "python:3.12", ConnectionConfig = connectionConfig, });

Kotlin:

import com.alibaba.opensandbox.sandbox.Sandbox import com.alibaba.opensandbox.sandbox.config.ConnectionConfig val connectionConfig = ConnectionConfig.builder() .disableMetrics(true) .build() val sandbox = Sandbox.builder() .image("python:3.12") .connectionConfig(connectionConfig) .build()

适用场景:在气隙/本地部署(air-gapped / on-prem)环境中不希望 SDK 发出任何额外 HTTP 流量,或企业出口流量审计(egress logging)中不希望出现遥测请求时,应使用上述 opt-out 配置。

测试与验证入口

仓库内为这套链路提供了多层测试,便于在升级或改造时回归验证:

  • 服务端端点单测:test_metrics_api.py(覆盖sandbox.create事件处理、User-Agent 解析与 204 响应);
  • 各 SDK 上报器单测:Python test_lifecycle_metrics.py、Go lifecycle_metrics_test.go、C# LifecycleMetricsReporterTests.cs、Kotlin LifecycleMetricsReporterTest.kt;
  • 端到端测试:Python test_lifecycle_metrics_e2e.py、Go lifecycle_metrics_e2e_test.go、JavaScript test_lifecycle_metrics_e2e.test.ts,分别覆盖正常上报与OPENSANDBOX_DISABLE_METRICS=1下不上报的行为。

小结

OpenSandbox 的 SDK 遥测是一条极简而严谨的链路:SDK 在 create 完成/失败后以 fire-and-forget 方式 POST 一个不含用户内容的 JSON 事件到/v1/metrics/events,服务端以204应答并按[otel]配置将样本落入opensandbox.sandbox.create.duration直方图(按 SDK 语言、版本与成败打标签)。全链路以"绝不影响沙箱创建"为硬约束,版本漂移安全,且可用环境变量或连接配置一键关闭。理解其触发时机(尤其是 Kotlin staged warmup 的有意排除)与直方图桶边界,你就能正确解读这份创建延迟指标,并在自建监控中做对应聚合。

【免费下载链接】OpenSandboxSecure, Fast, and Extensible Sandbox runtime for AI agents.项目地址: https://gitcode.com/GitHub_Trending/ope/OpenSandbox

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询