[codex-analytics] add protocol-native turn timestamps (#16638)

---
[//]: # (BEGIN SAPLING FOOTER)
Stack created with [Sapling](https://sapling-scm.com). Best reviewed
with [ReviewStack](https://reviewstack.dev/openai/codex/pull/16638).
* #16870
* #16706
* #16659
* #16641
* #16640
* __->__ #16638
This commit is contained in:
rhan-oai
2026-04-06 16:22:59 -07:00
committed by GitHub
parent e88c2cf4d7
commit 756c45ec61
58 changed files with 1134 additions and 36 deletions

View File

@@ -1,5 +1,7 @@
use std::time::Duration;
use std::time::Instant;
use std::time::SystemTime;
use std::time::UNIX_EPOCH;
use codex_otel::metrics::names::TURN_TTFM_DURATION_METRIC;
use codex_otel::metrics::names::TURN_TTFT_DURATION_METRIC;
@@ -45,6 +47,7 @@ pub(crate) struct TurnTimingState {
#[derive(Debug, Default)]
struct TurnTimingStateInner {
started_at: Option<Instant>,
started_at_unix_secs: Option<i64>,
first_token_at: Option<Instant>,
first_message_at: Option<Instant>,
}
@@ -53,10 +56,24 @@ impl TurnTimingState {
pub(crate) async fn mark_turn_started(&self, started_at: Instant) {
let mut state = self.state.lock().await;
state.started_at = Some(started_at);
state.started_at_unix_secs = Some(now_unix_timestamp_secs());
state.first_token_at = None;
state.first_message_at = None;
}
pub(crate) async fn started_at_unix_secs(&self) -> Option<i64> {
self.state.lock().await.started_at_unix_secs
}
pub(crate) async fn completed_at_and_duration_ms(&self) -> (Option<i64>, Option<i64>) {
let state = self.state.lock().await;
let completed_at = Some(now_unix_timestamp_secs());
let duration_ms = state
.started_at
.map(|started_at| i64::try_from(started_at.elapsed().as_millis()).unwrap_or(i64::MAX));
(completed_at, duration_ms)
}
pub(crate) async fn record_ttft_for_response_event(
&self,
event: &ResponseEvent,
@@ -77,6 +94,13 @@ impl TurnTimingState {
}
}
fn now_unix_timestamp_secs() -> i64 {
let duration = SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap_or_default();
i64::try_from(duration.as_secs()).unwrap_or(i64::MAX)
}
impl TurnTimingStateInner {
fn record_turn_ttft(&mut self) -> Option<Duration> {
if self.first_token_at.is_some() {