Files
codex/codex-rs/core/src/otel_init.rs
T
arnavpatidar-OAI bea47c06df Redact OTEL exporter headers in app-server config responses (#57654)
## Why

OTEL exporter headers can contain credentials. Configuration responses exposed these values in effective config, source layers, managed requirements, and write-override metadata.

## What changed

Replace header values with `[redacted]` across these responses for log, trace, and metrics exporters while preserving header names. Keep the original values available to runtime exporters, and redact them in debug output. Update protocol schemas and generated client documentation to describe the redacted values.

## Testing

Add coverage for effective config and source-layer redaction, managed requirements, and single and batch write-override metadata, including header names containing dots. Extend telemetry integration coverage to verify that runtime requests still carry the configured header value.

GitOrigin-RevId: ad24e8b91e615bd36c03c4c0ca205ac64bbd8cbf
2026-10-28 05:46:04 +00:00

114 lines
4.1 KiB
Rust

use crate::config::Config;
use codex_config::types::OtelExporterKind as Kind;
use codex_config::types::OtelHttpProtocol as Protocol;
use codex_features::Feature;
use codex_login::default_client::originator;
use codex_otel::OtelExporter;
use codex_otel::OtelHttpProtocol;
use codex_otel::OtelProvider;
use codex_otel::OtelSettings;
use codex_otel::OtelTlsConfig as OtelTlsSettings;
use std::error::Error;
/// Build an OpenTelemetry provider from the app Config.
///
/// Returns `None` when OTEL export is disabled.
pub fn build_provider(
config: &Config,
service_version: &str,
service_name_override: Option<&str>,
default_analytics_enabled: bool,
) -> Result<Option<OtelProvider>, Box<dyn Error>> {
let to_otel_exporter = |kind: &Kind| match kind {
Kind::None => OtelExporter::None,
Kind::Statsig => OtelExporter::Statsig,
Kind::OtlpHttp {
endpoint,
headers,
protocol,
tls,
} => {
let protocol = match protocol {
Protocol::Json => OtelHttpProtocol::Json,
Protocol::Binary => OtelHttpProtocol::Binary,
};
OtelExporter::OtlpHttp {
endpoint: endpoint.clone(),
headers: headers
.iter()
.map(|(name, value)| (name.clone(), value.as_str().to_owned()))
.collect(),
protocol,
tls: tls.as_ref().map(|config| OtelTlsSettings {
ca_certificate: config.ca_certificate.clone(),
client_certificate: config.client_certificate.clone(),
client_private_key: config.client_private_key.clone(),
}),
}
}
Kind::OtlpGrpc {
endpoint,
headers,
tls,
} => OtelExporter::OtlpGrpc {
endpoint: endpoint.clone(),
headers: headers
.iter()
.map(|(name, value)| (name.clone(), value.as_str().to_owned()))
.collect(),
tls: tls.as_ref().map(|config| OtelTlsSettings {
ca_certificate: config.ca_certificate.clone(),
client_certificate: config.client_certificate.clone(),
client_private_key: config.client_private_key.clone(),
}),
},
};
let exporter = to_otel_exporter(&config.otel.exporter);
let trace_exporter = to_otel_exporter(&config.otel.trace_exporter);
// Analytics consent controls the built-in exporter, not explicit OTLP collectors.
let metrics_exporter = if matches!(config.otel.metrics_exporter, Kind::Statsig)
&& !config
.analytics_enabled
.unwrap_or(default_analytics_enabled)
{
OtelExporter::None
} else {
to_otel_exporter(&config.otel.metrics_exporter)
};
let originator = originator();
let service_name = service_name_override.unwrap_or(originator.value.as_str());
let runtime_metrics = config.features.enabled(Feature::RuntimeMetrics);
OtelProvider::try_new(&OtelSettings {
http_client_factory: config.http_client_factory(),
service_name: service_name.to_string(),
service_version: service_version.to_string(),
codex_home: config.codex_home.to_path_buf(),
environment: config.otel.environment.to_string(),
exporter,
trace_exporter,
metrics_exporter,
runtime_metrics,
span_attributes: config.otel.span_attributes.clone(),
tracestate: config.otel.tracestate.clone(),
})
}
pub fn record_process_start(otel: Option<&OtelProvider>, originator: &str) {
let Some(metrics) = otel.and_then(OtelProvider::metrics) else {
return;
};
let _ = codex_otel::record_process_start_once(metrics, originator);
}
pub fn install_sqlite_telemetry(otel: Option<&OtelProvider>, originator: &str) {
let Some(metrics) = otel.and_then(OtelProvider::metrics) else {
return;
};
let telemetry = codex_rollout::sqlite_telemetry_recorder(metrics.clone(), originator);
let _ = codex_state::install_process_db_telemetry(telemetry);
}