reorganize

This commit is contained in:
Owen Lin
2026-06-10 13:03:20 -07:00
parent 5c0b571f93
commit e8ffc7dc6f
7 changed files with 113 additions and 102 deletions

View File

@@ -1,5 +1,3 @@
use crate::event_sink::AnalyticsEvent;
use crate::event_sink::AnalyticsEventSink;
use crate::events::AppServerRpcTransport;
use crate::events::GuardianReviewAnalyticsResult;
use crate::events::GuardianReviewTrackContext;
@@ -22,9 +20,11 @@ use crate::facts::TurnCodexErrorFact;
use crate::facts::TurnProfileFact;
use crate::facts::TurnResolvedConfigFact;
use crate::facts::TurnTokenUsageFact;
use crate::local_sink::SharedLocalAnalyticsSink;
use crate::local_sink::local_analytics_sink_from_env;
use crate::reducer::AnalyticsReducer;
use crate::sinks::AnalyticsEvent;
use crate::sinks::AnalyticsEventSink;
use crate::sinks::SharedLocalAnalyticsSink;
use crate::sinks::local_analytics_sink_from_env;
use codex_app_server_protocol::ClientRequest;
use codex_app_server_protocol::ClientResponsePayload;
use codex_app_server_protocol::InitializeParams;
@@ -42,7 +42,7 @@ use std::sync::Mutex;
use tokio::sync::mpsc;
#[cfg(test)]
use crate::local_sink::local_analytics_sink_for_path;
use crate::sinks::local_analytics_sink_for_path;
#[cfg(test)]
use std::path::PathBuf;

View File

@@ -1,10 +1,9 @@
mod accepted_lines;
mod client;
mod event_sink;
mod events;
mod facts;
mod local_sink;
mod reducer;
mod sinks;
use std::time::SystemTime;
use std::time::UNIX_EPOCH;
@@ -50,9 +49,9 @@ pub use facts::TurnSteerRequestError;
pub use facts::TurnSteerResult;
pub use facts::TurnTokenUsageFact;
pub use facts::build_track_events_context;
pub use local_sink::LOCAL_ANALYTICS_SCHEMA_VERSION;
pub use local_sink::LocalAnalyticsRecord;
pub use local_sink::LocalAnalyticsRecordType;
pub use sinks::LOCAL_ANALYTICS_SCHEMA_VERSION;
pub use sinks::LocalAnalyticsRecord;
pub use sinks::LocalAnalyticsRecordType;
#[cfg(test)]
mod analytics_client_tests;

View File

@@ -0,0 +1,87 @@
use crate::events::TrackEventRequest;
use crate::events::TrackEventsRequest;
use codex_login::AuthManager;
use codex_login::CodexAuth;
use codex_login::default_client::create_client;
use std::time::Duration;
const ANALYTICS_EVENTS_TIMEOUT: Duration = Duration::from_secs(10);
pub(super) async fn write(
auth_manager: &AuthManager,
base_url: &str,
events: &[&TrackEventRequest],
) {
if events.is_empty() {
return;
}
let Some(auth) = auth_manager.auth().await else {
return;
};
if !auth.uses_codex_backend() {
return;
}
let base_url = base_url.trim_end_matches('/');
let url = format!("{base_url}/codex/analytics-events/events");
for events in track_event_request_batches(events) {
send_track_events_request(&auth, &url, events).await;
}
}
fn track_event_request_batches<'a>(
events: &'a [&'a TrackEventRequest],
) -> Vec<&'a [&'a TrackEventRequest]> {
let mut batches = Vec::new();
let mut current_batch_start = 0;
for (index, event) in events.iter().enumerate() {
if event.should_send_in_isolated_request() {
if current_batch_start < index {
batches.push(&events[current_batch_start..index]);
}
batches.push(&events[index..=index]);
current_batch_start = index + 1;
}
}
if current_batch_start < events.len() {
batches.push(&events[current_batch_start..]);
}
batches
}
async fn send_track_events_request(auth: &CodexAuth, url: &str, events: &[&TrackEventRequest]) {
if events.is_empty() {
return;
}
let payload = TrackEventsRequest { events };
let response = create_client()
.post(url)
.timeout(ANALYTICS_EVENTS_TIMEOUT)
.headers(codex_model_provider::auth_provider_from_auth(auth).to_auth_headers())
.header("Content-Type", "application/json")
.json(&payload)
.send()
.await;
match response {
Ok(response) if response.status().is_success() => {}
Ok(response) => {
let status = response.status();
let body = response.text().await.unwrap_or_default();
tracing::warn!("events failed with status {status}: {body}");
}
Err(err) => {
tracing::warn!("failed to send events request: {err}");
}
}
}
#[cfg(test)]
#[path = "codex_backend_tests.rs"]
mod tests;

View File

@@ -149,5 +149,5 @@ fn string_field(value: Option<&JsonValue>, field: &str) -> Option<String> {
}
#[cfg(test)]
#[path = "local_sink_tests.rs"]
#[path = "local_tests.rs"]
mod tests;

View File

@@ -1,14 +1,18 @@
use crate::events::TrackEventRequest;
use crate::events::TrackEventsRequest;
use crate::local_sink::SharedLocalAnalyticsSink;
use crate::local_sink::append_codex_analytics_event_best_effort;
use codex_login::AuthManager;
use codex_login::CodexAuth;
use codex_login::default_client::create_client;
use std::sync::Arc;
use std::time::Duration;
mod codex_backend;
mod local;
use crate::events::TrackEventRequest;
use codex_login::AuthManager;
use std::sync::Arc;
pub use local::LOCAL_ANALYTICS_SCHEMA_VERSION;
pub use local::LocalAnalyticsRecord;
pub use local::LocalAnalyticsRecordType;
pub(crate) use local::SharedLocalAnalyticsSink;
#[cfg(test)]
pub(crate) use local::local_analytics_sink_for_path;
pub(crate) use local::local_analytics_sink_from_env;
const ANALYTICS_EVENTS_TIMEOUT: Duration = Duration::from_secs(10);
const CODEX_ANALYTICS_EVENT_SINKS: AnalyticsEventSinkSet =
AnalyticsEventSinkSet::CODEX_BACKEND.union(AnalyticsEventSinkSet::LOCAL);
@@ -50,13 +54,13 @@ impl AnalyticsEventSink {
AnalyticsEvent::CodexAnalytics(event) => event,
})
.collect::<Vec<_>>();
send_track_events(auth_manager, base_url, &events).await;
codex_backend::write(auth_manager, base_url, &events).await;
}
Self::Local(sink) => {
for event in writable_events(events, self.kind()) {
match event {
AnalyticsEvent::CodexAnalytics(event) => {
append_codex_analytics_event_best_effort(sink, event);
local::append_codex_analytics_event_best_effort(sink, event);
}
}
}
@@ -111,82 +115,3 @@ fn writable_events(
.iter()
.filter(move |event| event.writable_sinks().contains(sink))
}
async fn send_track_events(
auth_manager: &AuthManager,
base_url: &str,
events: &[&TrackEventRequest],
) {
if events.is_empty() {
return;
}
let Some(auth) = auth_manager.auth().await else {
return;
};
if !auth.uses_codex_backend() {
return;
}
let base_url = base_url.trim_end_matches('/');
let url = format!("{base_url}/codex/analytics-events/events");
for events in track_event_request_batches(events) {
send_track_events_request(&auth, &url, events).await;
}
}
fn track_event_request_batches<'a>(
events: &'a [&'a TrackEventRequest],
) -> Vec<&'a [&'a TrackEventRequest]> {
let mut batches = Vec::new();
let mut current_batch_start = 0;
for (index, event) in events.iter().enumerate() {
if event.should_send_in_isolated_request() {
if current_batch_start < index {
batches.push(&events[current_batch_start..index]);
}
batches.push(&events[index..=index]);
current_batch_start = index + 1;
}
}
if current_batch_start < events.len() {
batches.push(&events[current_batch_start..]);
}
batches
}
async fn send_track_events_request(auth: &CodexAuth, url: &str, events: &[&TrackEventRequest]) {
if events.is_empty() {
return;
}
let payload = TrackEventsRequest { events };
let response = create_client()
.post(url)
.timeout(ANALYTICS_EVENTS_TIMEOUT)
.headers(codex_model_provider::auth_provider_from_auth(auth).to_auth_headers())
.header("Content-Type", "application/json")
.json(&payload)
.send()
.await;
match response {
Ok(response) if response.status().is_success() => {}
Ok(response) => {
let status = response.status();
let body = response.text().await.unwrap_or_default();
tracing::warn!("events failed with status {status}: {body}");
}
Err(err) => {
tracing::warn!("failed to send events request: {err}");
}
}
}
#[cfg(test)]
#[path = "event_sink_tests.rs"]
mod tests;