mirror of
https://github.com/openai/codex.git
synced 2026-09-16 12:13:30 +00:00
add chatgpt user id into OTLP metric tags
This commit is contained in:
@@ -262,6 +262,12 @@ impl CodexAuth {
|
||||
self.get_current_token_data().and_then(|t| t.id_token.email)
|
||||
}
|
||||
|
||||
/// Returns `None` if `is_chatgpt_auth()` is false.
|
||||
pub fn get_chatgpt_user_id(&self) -> Option<String> {
|
||||
self.get_current_token_data()
|
||||
.and_then(|t| t.id_token.chatgpt_user_id)
|
||||
}
|
||||
|
||||
/// Account-facing plan classification derived from the current token.
|
||||
/// Returns a high-level `AccountPlanType` (e.g., Free/Plus/Pro/Team/…)
|
||||
/// mapped from the ID token's internal plan value. Prefer this when you
|
||||
|
||||
@@ -1269,6 +1269,7 @@ impl Session {
|
||||
let auth_mode = auth.map(CodexAuth::auth_mode).map(TelemetryAuthMode::from);
|
||||
let account_id = auth.and_then(CodexAuth::get_account_id);
|
||||
let account_email = auth.and_then(CodexAuth::get_account_email);
|
||||
let chatgpt_user_id = auth.and_then(CodexAuth::get_chatgpt_user_id);
|
||||
let originator = crate::default_client::originator().value;
|
||||
let terminal_type = terminal::user_agent();
|
||||
let session_model = session_configuration.collaboration_mode.model().to_string();
|
||||
@@ -1284,6 +1285,9 @@ impl Session {
|
||||
terminal_type.clone(),
|
||||
session_configuration.session_source.clone(),
|
||||
);
|
||||
if let Some(chatgpt_user_id) = chatgpt_user_id.as_deref() {
|
||||
otel_manager = otel_manager.with_chatgpt_user_id(chatgpt_user_id);
|
||||
}
|
||||
if let Some(service_name) = session_configuration.metrics_service_name.as_deref() {
|
||||
otel_manager = otel_manager.with_metrics_service_name(service_name);
|
||||
}
|
||||
|
||||
@@ -44,6 +44,7 @@ pub struct OtelEventMetadata {
|
||||
pub(crate) auth_mode: Option<String>,
|
||||
pub(crate) account_id: Option<String>,
|
||||
pub(crate) account_email: Option<String>,
|
||||
pub(crate) chatgpt_user_id: Option<String>,
|
||||
pub(crate) originator: String,
|
||||
pub(crate) service_name: Option<String>,
|
||||
pub(crate) session_source: String,
|
||||
@@ -73,6 +74,11 @@ impl OtelManager {
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_chatgpt_user_id(mut self, chatgpt_user_id: &str) -> Self {
|
||||
self.metadata.chatgpt_user_id = Some(sanitize_metric_tag_value(chatgpt_user_id));
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_metrics(mut self, metrics: MetricsClient) -> Self {
|
||||
self.metrics = Some(metrics);
|
||||
self.metrics_use_metadata_tags = true;
|
||||
@@ -203,7 +209,7 @@ impl OtelManager {
|
||||
if !self.metrics_use_metadata_tags {
|
||||
return Ok(Vec::new());
|
||||
}
|
||||
let mut tags = Vec::with_capacity(7);
|
||||
let mut tags = Vec::with_capacity(9);
|
||||
Self::push_metadata_tag(&mut tags, "auth_mode", self.metadata.auth_mode.as_deref())?;
|
||||
Self::push_metadata_tag(
|
||||
&mut tags,
|
||||
@@ -222,6 +228,18 @@ impl OtelManager {
|
||||
)?;
|
||||
Self::push_metadata_tag(&mut tags, "model", Some(self.metadata.model.as_str()))?;
|
||||
Self::push_metadata_tag(&mut tags, "app.version", Some(self.metadata.app_version))?;
|
||||
// Emit both tag names for the same public ChatGPT user id until we confirm
|
||||
// which downstream metrics pipeline reads: `enduser.id` or `user_id`.
|
||||
Self::push_metadata_tag(
|
||||
&mut tags,
|
||||
"enduser.id",
|
||||
self.metadata.chatgpt_user_id.as_deref(),
|
||||
)?;
|
||||
Self::push_metadata_tag(
|
||||
&mut tags,
|
||||
"user_id",
|
||||
self.metadata.chatgpt_user_id.as_deref(),
|
||||
)?;
|
||||
Ok(tags)
|
||||
}
|
||||
|
||||
|
||||
@@ -78,6 +78,7 @@ impl OtelManager {
|
||||
auth_mode: auth_mode.map(|m| m.to_string()),
|
||||
account_id,
|
||||
account_email,
|
||||
chatgpt_user_id: None,
|
||||
originator: sanitize_metric_tag_value(originator.as_str()),
|
||||
service_name: None,
|
||||
session_source: session_source.to_string(),
|
||||
|
||||
@@ -153,3 +153,45 @@ fn manager_attaches_optional_service_name_tag() -> Result<()> {
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn manager_attaches_chatgpt_user_id_tags_to_metrics() -> Result<()> {
|
||||
let (metrics, exporter) = build_metrics_with_defaults(&[])?;
|
||||
let manager = OtelManager::new(
|
||||
ThreadId::new(),
|
||||
"gpt-5.1",
|
||||
"gpt-5.1",
|
||||
Some("account-id".to_string()),
|
||||
None,
|
||||
Some(TelemetryAuthMode::Chatgpt),
|
||||
"test_originator".to_string(),
|
||||
false,
|
||||
"tty".to_string(),
|
||||
SessionSource::Cli,
|
||||
)
|
||||
.with_chatgpt_user_id("user-12345")
|
||||
.with_metrics(metrics);
|
||||
|
||||
manager.counter("codex.session_started", 1, &[]);
|
||||
manager.shutdown_metrics()?;
|
||||
|
||||
let resource_metrics = latest_metrics(&exporter);
|
||||
let metric =
|
||||
find_metric(&resource_metrics, "codex.session_started").expect("counter metric missing");
|
||||
let attrs = match metric.data() {
|
||||
AggregatedMetrics::U64(data) => match data {
|
||||
MetricData::Sum(sum) => {
|
||||
let points: Vec<_> = sum.data_points().collect();
|
||||
assert_eq!(points.len(), 1);
|
||||
attributes_to_map(points[0].attributes())
|
||||
}
|
||||
_ => panic!("unexpected counter aggregation"),
|
||||
},
|
||||
_ => panic!("unexpected counter data type"),
|
||||
};
|
||||
|
||||
assert_eq!(attrs.get("enduser.id"), Some(&"user-12345".to_string()));
|
||||
assert_eq!(attrs.get("user_id"), Some(&"user-12345".to_string()));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -1366,7 +1366,8 @@ impl App {
|
||||
let auth_mode = auth_ref
|
||||
.map(CodexAuth::auth_mode)
|
||||
.map(TelemetryAuthMode::from);
|
||||
let otel_manager = OtelManager::new(
|
||||
let chatgpt_user_id = auth_ref.and_then(CodexAuth::get_chatgpt_user_id);
|
||||
let mut otel_manager = OtelManager::new(
|
||||
ThreadId::new(),
|
||||
model.as_str(),
|
||||
model.as_str(),
|
||||
@@ -1378,6 +1379,9 @@ impl App {
|
||||
codex_core::terminal::user_agent(),
|
||||
SessionSource::Cli,
|
||||
);
|
||||
if let Some(chatgpt_user_id) = chatgpt_user_id.as_deref() {
|
||||
otel_manager = otel_manager.with_chatgpt_user_id(chatgpt_user_id);
|
||||
}
|
||||
if config
|
||||
.tui_status_line
|
||||
.as_ref()
|
||||
|
||||
Reference in New Issue
Block a user