mirror of
https://github.com/pchuan98/codex.git
synced 2026-07-01 00:31:56 +08:00
fa1242c83b
## Summary This PR fixes OTLP HTTP trace export in runtimes where the previous exporter setup was unreliable, especially around app-server usage. It also removes the old `codex_otel::otel_provider` compatibility shim and switches remaining call sites over to the crate-root `codex_otel::OtelProvider` export. ## What changed - Use a runtime-safe OTLP HTTP trace exporter path for Tokio runtimes. - Add an async HTTP client path for trace export when we are already inside a multi-thread Tokio runtime. - Make provider shutdown flush traces before tearing down the tracer provider. - Add loopback coverage that verifies traces are actually sent to `/v1/traces`: - outside Tokio - inside a multi-thread Tokio runtime - inside a current-thread Tokio runtime - Remove the `codex_otel::otel_provider` shim and update remaining imports. ## Why I hit cases where spans were being created correctly but never made it to the collector. The issue turned out to be in exporter/runtime behavior rather than the span plumbing itself. This PR narrows that gap and gives us regression coverage for the actual export path.
100 lines
3.4 KiB
Rust
100 lines
3.4 KiB
Rust
use crate::config::Config;
|
|
use crate::config::types::OtelExporterKind as Kind;
|
|
use crate::config::types::OtelHttpProtocol as Protocol;
|
|
use crate::default_client::originator;
|
|
use crate::features::Feature;
|
|
use codex_otel::OtelProvider;
|
|
use codex_otel::config::OtelExporter;
|
|
use codex_otel::config::OtelHttpProtocol;
|
|
use codex_otel::config::OtelSettings;
|
|
use codex_otel::config::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.clone(),
|
|
environment: config.otel.environment.to_string(),
|
|
exporter,
|
|
trace_exporter,
|
|
metrics_exporter,
|
|
runtime_metrics,
|
|
})
|
|
}
|
|
|
|
/// 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")
|
|
}
|