mirror of
https://github.com/openai/codex.git
synced 2026-04-24 14:45:27 +00:00
- add event for thread initialization - thread/start, thread/fork, thread/resume - feature flagged behind `FeatureFlag::GeneralAnalytics` - does not yet support threads started by subagents PR stack: - --> [[telemetry] thread events #15690](https://github.com/openai/codex/pull/15690) - [[telemetry] subagent events #15915](https://github.com/openai/codex/pull/15915) - [[telemetry] turn events #15591](https://github.com/openai/codex/pull/15591) - [[telemetry] steer events #15697](https://github.com/openai/codex/pull/15697) - [[telemetry] queued prompt data #15804](https://github.com/openai/codex/pull/15804) Sample extracted logs in Codex-backend ``` INFO | 2026-03-29 16:39:37 | codex_backend.routers.analytics_events | analytics_events.track_analytics_events:398 | Tracked analytics event codex_thread_initialized thread_id=019d3bf7-9f5f-7f82-9877-6d48d1052531 product_surface=codex product_client_id=CODEX_CLI client_name=codex-tui client_version=0.0.0 rpc_transport=in_process experimental_api_enabled=True codex_rs_version=0.0.0 runtime_os=macos runtime_os_version=26.4.0 runtime_arch=aarch64 model=gpt-5.3-codex ephemeral=False thread_source=user initialization_mode=new subagent_source=None parent_thread_id=None created_at=1774827577 | INFO | 2026-03-29 16:45:46 | codex_backend.routers.analytics_events | analytics_events.track_analytics_events:398 | Tracked analytics event codex_thread_initialized thread_id=019d3b84-5731-79d0-9b3b-9c6efe5f5066 product_surface=codex product_client_id=CODEX_CLI client_name=codex-tui client_version=0.0.0 rpc_transport=in_process experimental_api_enabled=True codex_rs_version=0.0.0 runtime_os=macos runtime_os_version=26.4.0 runtime_arch=aarch64 model=gpt-5.3-codex ephemeral=False thread_source=user initialization_mode=resumed subagent_source=None parent_thread_id=None created_at=1774820022 | INFO | 2026-03-29 16:45:49 | codex_backend.routers.analytics_events | analytics_events.track_analytics_events:398 | Tracked analytics event codex_thread_initialized thread_id=019d3bfd-4cd6-7c12-a13e-48cef02e8c4d product_surface=codex product_client_id=CODEX_CLI client_name=codex-tui client_version=0.0.0 rpc_transport=in_process experimental_api_enabled=True codex_rs_version=0.0.0 runtime_os=macos runtime_os_version=26.4.0 runtime_arch=aarch64 model=gpt-5.3-codex ephemeral=False thread_source=user initialization_mode=forked subagent_source=None parent_thread_id=None created_at=1774827949 | INFO | 2026-03-29 17:20:29 | codex_backend.routers.analytics_events | analytics_events.track_analytics_events:398 | Tracked analytics event codex_thread_initialized thread_id=019d3c1d-0412-7ed2-ad24-c9c0881a36b0 product_surface=codex product_client_id=CODEX_SERVICE_EXEC client_name=codex_exec client_version=0.0.0 rpc_transport=in_process experimental_api_enabled=True codex_rs_version=0.0.0 runtime_os=macos runtime_os_version=26.4.0 runtime_arch=aarch64 model=gpt-5.3-codex ephemeral=False thread_source=user initialization_mode=new subagent_source=None parent_thread_id=None created_at=1774830027 | ``` Notes - `product_client_id` gets canonicalized in codex-backend - subagent threads are addressed in a following pr
231 lines
7.3 KiB
Rust
231 lines
7.3 KiB
Rust
use crate::facts::AppInvocation;
|
|
use crate::facts::InvocationType;
|
|
use crate::facts::PluginState;
|
|
use crate::facts::TrackEventsContext;
|
|
use codex_login::default_client::originator;
|
|
use codex_plugin::PluginTelemetryMetadata;
|
|
use codex_protocol::protocol::SessionSource;
|
|
use serde::Serialize;
|
|
|
|
#[derive(Clone, Copy, Debug, Serialize)]
|
|
#[serde(rename_all = "snake_case")]
|
|
pub enum AppServerRpcTransport {
|
|
Stdio,
|
|
Websocket,
|
|
InProcess,
|
|
}
|
|
|
|
#[derive(Clone, Copy, Debug, Serialize)]
|
|
#[serde(rename_all = "snake_case")]
|
|
pub(crate) enum ThreadInitializationMode {
|
|
New,
|
|
Forked,
|
|
Resumed,
|
|
}
|
|
|
|
#[derive(Serialize)]
|
|
pub(crate) struct TrackEventsRequest {
|
|
pub(crate) events: Vec<TrackEventRequest>,
|
|
}
|
|
|
|
#[derive(Serialize)]
|
|
#[serde(untagged)]
|
|
pub(crate) enum TrackEventRequest {
|
|
SkillInvocation(SkillInvocationEventRequest),
|
|
ThreadInitialized(ThreadInitializedEvent),
|
|
AppMentioned(CodexAppMentionedEventRequest),
|
|
AppUsed(CodexAppUsedEventRequest),
|
|
PluginUsed(CodexPluginUsedEventRequest),
|
|
PluginInstalled(CodexPluginEventRequest),
|
|
PluginUninstalled(CodexPluginEventRequest),
|
|
PluginEnabled(CodexPluginEventRequest),
|
|
PluginDisabled(CodexPluginEventRequest),
|
|
}
|
|
|
|
#[derive(Serialize)]
|
|
pub(crate) struct SkillInvocationEventRequest {
|
|
pub(crate) event_type: &'static str,
|
|
pub(crate) skill_id: String,
|
|
pub(crate) skill_name: String,
|
|
pub(crate) event_params: SkillInvocationEventParams,
|
|
}
|
|
|
|
#[derive(Serialize)]
|
|
pub(crate) struct SkillInvocationEventParams {
|
|
pub(crate) product_client_id: Option<String>,
|
|
pub(crate) skill_scope: Option<String>,
|
|
pub(crate) repo_url: Option<String>,
|
|
pub(crate) thread_id: Option<String>,
|
|
pub(crate) invoke_type: Option<InvocationType>,
|
|
pub(crate) model_slug: Option<String>,
|
|
}
|
|
|
|
#[derive(Clone, Serialize)]
|
|
pub(crate) struct CodexAppServerClientMetadata {
|
|
pub(crate) product_client_id: String,
|
|
pub(crate) client_name: Option<String>,
|
|
pub(crate) client_version: Option<String>,
|
|
pub(crate) rpc_transport: AppServerRpcTransport,
|
|
pub(crate) experimental_api_enabled: Option<bool>,
|
|
}
|
|
|
|
#[derive(Clone, Serialize)]
|
|
pub(crate) struct CodexRuntimeMetadata {
|
|
pub(crate) codex_rs_version: String,
|
|
pub(crate) runtime_os: String,
|
|
pub(crate) runtime_os_version: String,
|
|
pub(crate) runtime_arch: String,
|
|
}
|
|
|
|
#[derive(Serialize)]
|
|
pub(crate) struct ThreadInitializedEventParams {
|
|
pub(crate) thread_id: String,
|
|
pub(crate) app_server_client: CodexAppServerClientMetadata,
|
|
pub(crate) runtime: CodexRuntimeMetadata,
|
|
pub(crate) model: String,
|
|
pub(crate) ephemeral: bool,
|
|
pub(crate) thread_source: Option<&'static str>,
|
|
pub(crate) initialization_mode: ThreadInitializationMode,
|
|
pub(crate) subagent_source: Option<String>,
|
|
pub(crate) parent_thread_id: Option<String>,
|
|
pub(crate) created_at: u64,
|
|
}
|
|
|
|
#[derive(Serialize)]
|
|
pub(crate) struct ThreadInitializedEvent {
|
|
pub(crate) event_type: &'static str,
|
|
pub(crate) event_params: ThreadInitializedEventParams,
|
|
}
|
|
|
|
#[derive(Serialize)]
|
|
pub(crate) struct CodexAppMetadata {
|
|
pub(crate) connector_id: Option<String>,
|
|
pub(crate) thread_id: Option<String>,
|
|
pub(crate) turn_id: Option<String>,
|
|
pub(crate) app_name: Option<String>,
|
|
pub(crate) product_client_id: Option<String>,
|
|
pub(crate) invoke_type: Option<InvocationType>,
|
|
pub(crate) model_slug: Option<String>,
|
|
}
|
|
|
|
#[derive(Serialize)]
|
|
pub(crate) struct CodexAppMentionedEventRequest {
|
|
pub(crate) event_type: &'static str,
|
|
pub(crate) event_params: CodexAppMetadata,
|
|
}
|
|
|
|
#[derive(Serialize)]
|
|
pub(crate) struct CodexAppUsedEventRequest {
|
|
pub(crate) event_type: &'static str,
|
|
pub(crate) event_params: CodexAppMetadata,
|
|
}
|
|
|
|
#[derive(Serialize)]
|
|
pub(crate) struct CodexPluginMetadata {
|
|
pub(crate) plugin_id: Option<String>,
|
|
pub(crate) plugin_name: Option<String>,
|
|
pub(crate) marketplace_name: Option<String>,
|
|
pub(crate) has_skills: Option<bool>,
|
|
pub(crate) mcp_server_count: Option<usize>,
|
|
pub(crate) connector_ids: Option<Vec<String>>,
|
|
pub(crate) product_client_id: Option<String>,
|
|
}
|
|
|
|
#[derive(Serialize)]
|
|
pub(crate) struct CodexPluginUsedMetadata {
|
|
#[serde(flatten)]
|
|
pub(crate) plugin: CodexPluginMetadata,
|
|
pub(crate) thread_id: Option<String>,
|
|
pub(crate) turn_id: Option<String>,
|
|
pub(crate) model_slug: Option<String>,
|
|
}
|
|
|
|
#[derive(Serialize)]
|
|
pub(crate) struct CodexPluginEventRequest {
|
|
pub(crate) event_type: &'static str,
|
|
pub(crate) event_params: CodexPluginMetadata,
|
|
}
|
|
|
|
#[derive(Serialize)]
|
|
pub(crate) struct CodexPluginUsedEventRequest {
|
|
pub(crate) event_type: &'static str,
|
|
pub(crate) event_params: CodexPluginUsedMetadata,
|
|
}
|
|
|
|
pub(crate) fn plugin_state_event_type(state: PluginState) -> &'static str {
|
|
match state {
|
|
PluginState::Installed => "codex_plugin_installed",
|
|
PluginState::Uninstalled => "codex_plugin_uninstalled",
|
|
PluginState::Enabled => "codex_plugin_enabled",
|
|
PluginState::Disabled => "codex_plugin_disabled",
|
|
}
|
|
}
|
|
|
|
pub(crate) fn codex_app_metadata(
|
|
tracking: &TrackEventsContext,
|
|
app: AppInvocation,
|
|
) -> CodexAppMetadata {
|
|
CodexAppMetadata {
|
|
connector_id: app.connector_id,
|
|
thread_id: Some(tracking.thread_id.clone()),
|
|
turn_id: Some(tracking.turn_id.clone()),
|
|
app_name: app.app_name,
|
|
product_client_id: Some(originator().value),
|
|
invoke_type: app.invocation_type,
|
|
model_slug: Some(tracking.model_slug.clone()),
|
|
}
|
|
}
|
|
|
|
pub(crate) fn codex_plugin_metadata(plugin: PluginTelemetryMetadata) -> CodexPluginMetadata {
|
|
let capability_summary = plugin.capability_summary;
|
|
CodexPluginMetadata {
|
|
plugin_id: Some(plugin.plugin_id.as_key()),
|
|
plugin_name: Some(plugin.plugin_id.plugin_name),
|
|
marketplace_name: Some(plugin.plugin_id.marketplace_name),
|
|
has_skills: capability_summary
|
|
.as_ref()
|
|
.map(|summary| summary.has_skills),
|
|
mcp_server_count: capability_summary
|
|
.as_ref()
|
|
.map(|summary| summary.mcp_server_names.len()),
|
|
connector_ids: capability_summary.map(|summary| {
|
|
summary
|
|
.app_connector_ids
|
|
.into_iter()
|
|
.map(|connector_id| connector_id.0)
|
|
.collect()
|
|
}),
|
|
product_client_id: Some(originator().value),
|
|
}
|
|
}
|
|
|
|
pub(crate) fn codex_plugin_used_metadata(
|
|
tracking: &TrackEventsContext,
|
|
plugin: PluginTelemetryMetadata,
|
|
) -> CodexPluginUsedMetadata {
|
|
CodexPluginUsedMetadata {
|
|
plugin: codex_plugin_metadata(plugin),
|
|
thread_id: Some(tracking.thread_id.clone()),
|
|
turn_id: Some(tracking.turn_id.clone()),
|
|
model_slug: Some(tracking.model_slug.clone()),
|
|
}
|
|
}
|
|
|
|
pub(crate) fn thread_source_name(thread_source: &SessionSource) -> Option<&'static str> {
|
|
match thread_source {
|
|
SessionSource::Cli | SessionSource::VSCode | SessionSource::Exec => Some("user"),
|
|
SessionSource::SubAgent(_) => Some("subagent"),
|
|
SessionSource::Mcp | SessionSource::Custom(_) | SessionSource::Unknown => None,
|
|
}
|
|
}
|
|
|
|
pub(crate) fn current_runtime_metadata() -> CodexRuntimeMetadata {
|
|
let os_info = os_info::get();
|
|
CodexRuntimeMetadata {
|
|
codex_rs_version: env!("CARGO_PKG_VERSION").to_string(),
|
|
runtime_os: std::env::consts::OS.to_string(),
|
|
runtime_os_version: os_info.version().to_string(),
|
|
runtime_arch: std::env::consts::ARCH.to_string(),
|
|
}
|
|
}
|