跳转到内容

遥测系统与统一规划

Dline 的目标是一套 canonical telemetry mechanism。loopback OTLP、本地 journal、账户身份日志、otel.dline.cc、diagnostic bundle 和 Issue diagnostics 都是同一接纳与隐私系统的 sink、视图或 profile overlay。目前 otel.dline.cc 接收使用计数以及错误和运行时诊断,经由当前远端 usage 投递所述的专用路径。

面向用户的遥测合同见遥测与 Issue 诊断,隐私合同见 Dline 隐私政策。

  • 使用统计和错误报告是独立 consent;unset 不等于同意。
  • account 通道服从 usage consent,但与普通 usage record 分离。
  • distinct_id 只表示设备/安装,登录或切换账户不能改写。
  • account/organization identity 不进入普通 Event/Metric attributes。
  • 组织、宿主、服务端和 kill switch 只能收紧 consent。
  • content、credential、raw artifact 和自由文本异常正文不进入 canonical telemetry。
  • 投递失败不改变产品结果。
  • transport outbox 是 sink 状态,不是另一遥测源。
  • RuntimeSessionLedger 是 crash capsule,不是 Task 生命周期权威。
层Owner职责
FacadeTelemetryService.ts产品级 capture API
Recorderevents/、instrumentation/、Task observability产生类型化事实
Early admissionservice/pipeline-port.ts有界 bootstrap 和 runtime recording predicate
Consentservice/channel-policy.tsusage/account 映射 usage consent;error/runtime 映射 error consent
Contextcontext/telemetry-context.ts只附加 host metadata,不保存 account identity
Deliveryservice/provider-registry.tslazy 物化属性并分发 capability
Canonical local journaljournal/OTLP 形态 Event、Metric、Trace partition
Runtime diagnosticsruntime/runtime producer、sampler、analysis、兼容 journal、bundle source
Crash capsuleruntime/session-ledger.ts有界的下一次启动 process reconciliation

registry 包含 usage、account、error、runtime、raw-artifact channel。account 是专用 identify delivery,sink 必须显式 opt in。

src/services/logging/distinctId.ts 只拥有设备级值。production 代码只能在初始化时设置;setDistinctIdForTesting() 只供测试。

TelemetrySignalDispatcher.identifyUser() 不再改写设备身份,也不把账户信息放入 TelemetryContext。普通 metric 只包含 host metadata 和自身维度。

默认 loopback registration 声明支持 account。OpenTelemetryTelemetryProvider.identifyUser() 在每次账户切换时发出一个 account.identified log,只包含 account_id、telemetry_channel=account,不包含 distinct_id、display name、email、organization 或 membership。普通 OTel event 继续使用设备 distinct_id。

账号识别从不改写或 alias 设备 ID。组织配置的 OTLP registration 没有 opt in account,因此不会收到 account record。Dline 没有 PostHog registration。

LocalJournalProvider 写 usage-*、metrics-*、traces-*,各自有 4 MiB tail budget。错误报告开启时,runtime/transports/session-journal.ts 还会写无前缀的 1 MiB runtime tail。

现有 cleanup 扫描共享目录全部 .jsonl,只排除精确匹配的活动无前缀 runtime 文件,把其他每个文件视为一个 item,最多保留 8 个符合条件文件,并删除超过 3 天的文件。它只在 error lifecycle 启动时运行。禁止把它描述成 8-session 或全局 byte bound。

canonical registry 每次从 StateManager 读取 consent。runtime 兼容 lifecycle 保存自己的 enabled 状态,只在 activation 和显式 error-setting 更新时变化。live organization disable 会通过 state replacement 影响 canonical registry,但当前不会调用 runtime lifecycle transition。统一 resolver 迁移必须在远端诊断发布前补齐。远端 usage 投递不依赖该 lifecycle:它在每个周期以及每次 consent 或组织设置变化时重新读取 policy 输入。

启动错误诊断当前会确保存在 owner-only legacy pairing credential,但没有现有 transport 消费。Issue diagnostics 必须迁移或丢弃它,并要求新的单 Issue 显式操作。

otel.dline.cc 经 /usage 接收 usage profile,经 OTLP/JSON 的 /v1/logs、/v1/metrics 和 /v1/traces 接收 production profile 的错误和运行时诊断;每个请求都带 X-Dline-Contract: 5。启动时删除早期合同留下的状态(LegacyTelemetryState),只在 remote quarantine 目录保留元数据形式的 loss evidence。usage 路径的所有权如下:

层Owner职责
Settlement portsrc/core/task/telemetry/UsageSettlement.ts每个已结算的服务商请求产生一条类型化记录:purpose、outcome、新输入与缓存 token、时长、流式耗时、重试、失败类别,以及服务该请求的 provider 和模型(含是否为自定义模型)
Policyremote/policy/usagePolicy.ts、RemotePolicyRepository把使用情况设置(默认开启)、组织、宿主等级和服务端停止解析为机器级 policy epoch,并在决策变化时记录日志
请求体remote/usage/attemptBucket.ts、remote/contracts/usageBody.ts、remote/contracts/usageBodySchema.ts已终结的 attempt 合并为 bucket,再构建为一个 schema 5 请求体;保存前按合同在本地校验
Spool 与 outboxUsageObservationSpool、UsageOutboxRepository按进程分片的 observation;发送租约、投递闸门、待发分钟和 exact-bytes inflight 在同一把锁下修改
投递UsageDeliveryWorker、RemoteUsageCoordinator窗口、批次、重放、延后与停止处理;policy 离开允许状态时删除未发送数据
凭据与传输DeviceCredentialRepository、DeviceTokenBroker、DlineOtelHttpClientowner-only 设备密钥、single-flight 令牌交换、经 @shared/net 的固定 origin
组合remote/remoteUsageRuntime.ts在 src/common.ts 的 initialize() 中启动,在 tearDown() 中停止

remote/ 路径位于 src/services/telemetry/ 下;repository 位于 src/core/storage/telemetry-remote/。

错误和运行时诊断由 remote/diagnostics/、remote/remoteDiagnosticsRuntime.ts 和共享的 DiagnosticOutboxRepository 负责;发送的记录与上限见用户文档。

该路径尚未达到下文目标:settlement 绕过了 provider-registry.ts 和 canonical channel catalog。隐私由构造保证:settlement 类型没有正文字段,请求体结构固定,批次属性经过 allowlist,并在发送前按 wire 合同校验。把该路径纳入 canonical admission boundary 仍是待完成工作。

DLINE_OTEL_ENDPOINT 只能把 origin 替换为 loopback origin,用于针对本地 mock 服务的契约测试;其他值会被忽略并记录警告。

normal signal ingress ─┐
authoritative usage ingress ─┤
account identity ingress ────┘
-> one consent/profile resolver
-> one channel/severity catalog
-> canonicalization and baseline content policy
-> sink-specific narrowing
-> one provider registry
-> one local journal owner
-> loopback OTLP
-> account-capable sink
-> otel.dline.cc
-> tests
-> diagnostic bundle read view

在目标形态中,权威 usage settlement 因为需要 awaited durable handoff,继续使用类型化 durable ingress,但它必须服从相同 consent、policy epoch、channel catalog、privacy admission 和审计规则,不构成第二套遥测系统。

本地 journal 迁移必须先复现当前 file size、cleanup selection、顺序、崩溃证据、取消、bundle export 和 restart recovery,parity 通过后才能停止兼容写入。任何 grouping、count、age、active-file protection 或 byte budget 变化都需要独立批准的 storage 约定。

  • usage(当前):不含正文的 Provider token、缓存和耗时 settlement,聚合为上文的 schema_version: 2 请求体。
  • production(logs 已启用):经过内容过滤的 error/runtime log 记录;不发送 metrics 和 traces。
  • issue_diagnostic:需要 error consent 与 active per-Issue grant 的有时限诊断密度。
  • development(计划):独立的开发流。目前 development 构建以 usage profile 发送使用统计并带 is_dev=true,自动化测试运行不发送。

issue_diagnostic 仍是计划。

Dline remote provider 接入现有 registry,禁止新增 remote-only catalog 或 consent system。remote diagnostics 同时排除设备 distinct_id 和 account identity。未来 account 目的地必须是单独声明的 account-capable sink。

远端 HTTP 使用共享且支持代理的 transport、固定 HTTPS origin、拒绝 redirect、有界 response read、有限 timeout、AbortSignal 和脱敏错误。outbox 按 count/byte/age 有界,并按 profile、credential/token generation、grant、signal、policy revision 分区;禁止从 forensic journal 重建 payload。

关闭通道时先持久化更严格 policy epoch,再停止 capture/send、取消 in-flight,并删除该通道未发送 outbox 和本地 remote token;不能删除服务端已接受数据。

host 负责 create、attach/check 和本地停止。pairing secret、support code、consent marker、Issue token、journal 和 bundle bytes 都不进入模型上下文。

普通 Issue 提交继续独立。Issue diagnostics 发布前,ReportBugHandler 必须停止要求并自动把 api_request_output 放入 Issue logs 字段。

授权检查由用户触发,不做轮询。维护者批准的服务端 grant 带 expiry,UI 显示剩余时间。无效或失败检查保持 Issue stream 关闭,并保留基础 production profile。本地停止、过期、consent 关闭、宿主/组织限制或 kill switch 都删除本地 Issue credential/outbox 并停止投递。

服务端当前没有 client revoke endpoint。本地停止不能表述成远端 grant 已撤销,也不能删除已上传数据。在 high-density scope enforcement 和服务端 retention/access/deletion policy 验证前,Issue rollout 保持阻塞。

  1. 注册稳定 event 或 metric 名称。
  2. 在 canonical catalog 分配 channel 和 severity。
  3. 通过 facade 或类型化 canonical ingress 记录。
  4. 字段保持有界且不含正文。
  5. 显式决定 account-capable sink 是否可接收。
  6. 按需增加 consent、identity boundary、privacy canary、journal、retry 和 recovery 测试。

相关测试包括 TelemetryChannelPolicy.test.ts、TelemetryService.test.ts、OpenTelemetryTelemetryProvider.test.ts、distinctId.test.ts、LocalJournalProvider.test.ts、consent-boundary.test.ts、session-journal.test.ts 和 bundle-builder.test.ts。