From 584fed15ff6f7904ae66189b737bfbdc167a4ce5 Mon Sep 17 00:00:00 2001 From: Owen Lin Date: Mon, 9 Mar 2026 11:03:35 -0700 Subject: [PATCH] chore: update telemetry-related docs --- codex-rs/app-server/README.md | 40 +++++++++++++++++++++++++++++++- codex-rs/otel/README.md | 43 +++++++++++++++++++++++++++++++++++ 2 files changed, 82 insertions(+), 1 deletion(-) diff --git a/codex-rs/app-server/README.md b/codex-rs/app-server/README.md index da6362b4db..0339b5f355 100644 --- a/codex-rs/app-server/README.md +++ b/codex-rs/app-server/README.md @@ -15,6 +15,7 @@ - [Skills](#skills) - [Apps](#apps) - [Auth endpoints](#auth-endpoints) +- [Telemetry](#telemetry) - [Experimental API Opt-in](#experimental-api-opt-in) ## Protocol @@ -185,7 +186,7 @@ Start a fresh thread when you need a new Codex conversation. "approvalPolicy": "never", "sandbox": "workspaceWrite", "personality": "friendly", - "serviceName": "my_app_server_client", // optional metrics tag (`service_name`) + "serviceName": "desktop_app", // optional session-level metrics tag (`service_name`) // Experimental: requires opt-in "dynamicTools": [ { @@ -1251,6 +1252,43 @@ Field notes: - `windowDurationMins` is the quota window length. - `resetsAt` is a Unix timestamp (seconds) for the next reset. +## Telemetry + +`codex app-server` exposes a few different telemetry inputs, and they operate at +different scopes: + +- Session-scoped metrics tags attached when a thread is created or resumed. +- Connection-scoped client identity established during `initialize`. +- Turn and request activity emitted by the app-server runtime itself. + +For crate-level OTEL routing, target families, and privacy boundaries, see +`codex-rs/otel/README.md`. + +### Client-provided telemetry inputs + +- `thread/start.serviceName` sets the session-level `service_name` metrics tag. + Use this for the stable name of the integration or surface that owns the + thread, such as `desktop_app` or `codex_vscode`. +- `initialize.clientInfo.name` identifies the app-server client on that + connection. This is used for request and session metadata, and it is also the + client identifier used for upstream compliance logging. +- `initialize.clientInfo.version` records the client version for that + connection's request metadata. + +### Current attribution model + +`thread/start.serviceName` is not the same thing as the app-server client's +identity. It feeds the existing session-scoped `service_name` metric dimension. + +App-server client identity comes from `initialize.clientInfo.name` on each +connection. That signal is connection-scoped and is used by request/session +telemetry emitted by the app-server runtime. + +Per-turn client attribution for turn-bound metrics such as TTFT and TTFM is a +separate follow-up. Do not treat `serviceName` as if it already provides +per-turn `client.name` attribution semantics. + + ## Experimental API Opt-in Some app-server methods and fields are intentionally gated behind an experimental capability with no backwards-compatible guarantees. This lets clients choose between: diff --git a/codex-rs/otel/README.md b/codex-rs/otel/README.md index be90d61416..9f5a6dfa8a 100644 --- a/codex-rs/otel/README.md +++ b/codex-rs/otel/README.md @@ -8,6 +8,24 @@ - Low-level metrics APIs via `codex_otel::metrics`. - Trace-context helpers via `codex_otel::trace_context` and crate-root re-exports. +## Ownership rules + +`codex-otel` is intentionally split by telemetry family: + +- `SessionTelemetry` owns session-scoped business events that need shared + metadata and explicit log-only versus trace-safe field selection. +- `metrics` owns low-level counters, histograms, and timers that do not need + session metadata. +- `trace_context` owns W3C trace propagation and parent-setting helpers. +- Domain-owned audit events may stay with the subsystem that emits them instead + of being forced through `SessionTelemetry`. + +Current example of a domain-owned audit emitter: + +- `codex-network-proxy` emits policy audit events on the + `codex_otel.network_proxy` target. See + `codex-rs/network-proxy/README.md` for the event family details. + ## Tracing and logs Create an OTEL provider from `OtelSettings`. The provider also configures @@ -49,6 +67,31 @@ if let Some(provider) = OtelProvider::from(&settings)? { } ``` +## Target families and routing + +`codex-otel` reserves the following target families: + +- `codex_otel.log_only` for session events whose rich fields should stay on the + OTEL log lane only. +- `codex_otel.trace_safe` for session events whose fields are safe to attach to + exported traces. +- `codex_otel.` for approved domain-owned audit emitters such as + `codex_otel.network_proxy`. + +Current routing behavior: + +- Log export accepts any `codex_otel.*` target except the + `codex_otel.trace_safe` family. +- Trace export accepts `codex_otel.trace_safe` events plus all spans. + +This means adding a new `codex_otel.` target is immediately +export-visible on the OTEL log lane unless provider filters change. Treat new +domain-owned targets as an explicit review point. + +This refactor does not make arbitrary spans trace-safe. Direct spans outside +`SessionTelemetry` are still exported by the trace filter, so any span fields on +those paths still need separate privacy review. + ## SessionTelemetry (events) `SessionTelemetry` adds consistent metadata to tracing events and helps record