mirror of
https://github.com/openai/codex.git
synced 2026-05-17 17:53:06 +00:00
Add Codex config for static trace span attributes and structured W3C tracestate field upserts. The config flows through OtelSettings so callers can attach trace metadata without touching every span call site. Apply span attributes with an SDK span processor so every exported trace span carries the configured metadata. Model tracestate as nested member fields so configured keys can be upserted while unrelated propagated state in the same member is preserved. Validate configured tracestate before installing provider-global state, including header-unsafe values the SDK does not reject by itself. This keeps Codex from propagating malformed trace context from config. Update the config schema, public docs, and OTLP loopback coverage for config parsing, span export, propagation, and invalid-header rejection.
102 lines
3.5 KiB
Rust
102 lines
3.5 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(|(k, v)| (k.clone(), v.clone()))
|
|
.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(|(k, v)| (k.clone(), v.clone()))
|
|
.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);
|
|
let metrics_exporter = if config
|
|
.analytics_enabled
|
|
.unwrap_or(default_analytics_enabled)
|
|
{
|
|
to_otel_exporter(&config.otel.metrics_exporter)
|
|
} else {
|
|
OtelExporter::None
|
|
};
|
|
|
|
let originator = originator();
|
|
let service_name = service_name_override.unwrap_or(originator.value.as_str());
|
|
let runtime_metrics = config.features.enabled(Feature::RuntimeMetrics);
|
|
|
|
OtelProvider::from(&OtelSettings {
|
|
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(),
|
|
})
|
|
}
|
|
|
|
/// Filter predicate for exporting only Codex-owned events via OTEL.
|
|
/// Keeps events that originated from codex_otel module
|
|
pub fn codex_export_filter(meta: &tracing::Metadata<'_>) -> bool {
|
|
meta.target().starts_with("codex_otel")
|
|
}
|