diff --git a/codex-rs/otel/src/config.rs b/codex-rs/otel/src/config.rs index 28365905de..a228c6581c 100644 --- a/codex-rs/otel/src/config.rs +++ b/codex-rs/otel/src/config.rs @@ -69,6 +69,8 @@ pub struct OtelSettings { #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] pub struct StatsigMetricsSettings { pub environment: String, + #[serde(default)] + pub respect_system_proxy: bool, } #[derive(Clone, Debug)] @@ -109,7 +111,9 @@ pub enum OtelExporter { #[cfg(test)] mod tests { use super::OtelExporter; + use super::StatsigMetricsSettings; use super::resolve_exporter; + use pretty_assertions::assert_eq; #[test] fn statsig_default_metrics_exporter_is_disabled_in_debug_builds() { @@ -119,4 +123,29 @@ mod tests { )); } + #[test] + fn statsig_settings_default_missing_proxy_policy_for_older_payloads() { + let settings: StatsigMetricsSettings = + serde_json::from_str(r#"{"environment":"prod"}"#).expect("legacy settings"); + + assert_eq!( + settings, + StatsigMetricsSettings { + environment: "prod".to_string(), + respect_system_proxy: false, + } + ); + } + + #[test] + fn statsig_settings_preserve_system_proxy_policy() { + let settings = StatsigMetricsSettings { + environment: "prod".to_string(), + respect_system_proxy: true, + }; + let json = serde_json::to_string(&settings).expect("serialize settings"); + let restored = serde_json::from_str(&json).expect("deserialize settings"); + + assert_eq!(settings, restored); + } } diff --git a/codex-rs/otel/src/provider.rs b/codex-rs/otel/src/provider.rs index 420546ba08..6ff0f6fecb 100644 --- a/codex-rs/otel/src/provider.rs +++ b/codex-rs/otel/src/provider.rs @@ -7,6 +7,7 @@ use crate::metrics::MetricsConfig; use crate::targets::is_log_export_target; use crate::targets::is_trace_safe_target; use codex_http_client::HttpClientFactory; +use codex_http_client::OutboundProxyPolicy; use gethostname::gethostname; use opentelemetry::Context; use opentelemetry::KeyValue; @@ -278,6 +279,8 @@ impl OtelProvider { if matches!(settings.metrics_exporter, OtelExporter::Statsig) { crate::metrics::install_global_statsig_settings(StatsigMetricsSettings { environment: settings.environment.clone(), + respect_system_proxy: settings.http_client_factory.outbound_proxy_policy() + == OutboundProxyPolicy::RespectSystemProxy, }); } } @@ -614,7 +617,6 @@ mod shutdown_tests; #[cfg(test)] mod tests { use super::*; - use codex_http_client::OutboundProxyPolicy; use crate::metrics::API_CALL_COUNT_METRIC; use crate::metrics::API_CALL_DURATION_METRIC; use crate::metrics::MetricsExporter; diff --git a/codex-rs/windows-sandbox-rs/src/bin/setup_main/win.rs b/codex-rs/windows-sandbox-rs/src/bin/setup_main/win.rs index dc43abd922..d1c518a9ee 100644 --- a/codex-rs/windows-sandbox-rs/src/bin/setup_main/win.rs +++ b/codex-rs/windows-sandbox-rs/src/bin/setup_main/win.rs @@ -1098,6 +1098,25 @@ mod tests { payload.otel, Some(StatsigMetricsSettings { environment: "prod".to_string(), + respect_system_proxy: false, + }) + ); + } + + #[test] + fn payload_preserves_otel_system_proxy_policy() { + let mut payload = payload_json(); + payload["otel"] = json!({ + "environment": "prod", + "respect_system_proxy": true, + }); + let payload: Payload = serde_json::from_value(payload).expect("payload"); + + assert_eq!( + payload.otel, + Some(StatsigMetricsSettings { + environment: "prod".to_string(), + respect_system_proxy: true, }) ); } diff --git a/codex-rs/windows-sandbox-rs/src/wfp_setup.rs b/codex-rs/windows-sandbox-rs/src/wfp_setup.rs index 3edc8e9bc9..78ceae1345 100644 --- a/codex-rs/windows-sandbox-rs/src/wfp_setup.rs +++ b/codex-rs/windows-sandbox-rs/src/wfp_setup.rs @@ -56,7 +56,11 @@ fn build_wfp_metrics_provider( exporter: OtelExporter::None, trace_exporter: OtelExporter::None, metrics_exporter: OtelExporter::Statsig, - http_client_factory: HttpClientFactory::new(OutboundProxyPolicy::ReqwestDefault), + http_client_factory: HttpClientFactory::new(if otel.respect_system_proxy { + OutboundProxyPolicy::RespectSystemProxy + } else { + OutboundProxyPolicy::ReqwestDefault + }), runtime_metrics: false, span_attributes: BTreeMap::new(), tracestate: BTreeMap::new(),