mirror of
https://github.com/openai/codex.git
synced 2026-10-24 18:18:41 +00:00
exec-server: initialize OpenTelemetry at startup
This commit is contained in:
@@ -41,6 +41,9 @@ use owo_colors::OwoColorize;
|
||||
use std::io::IsTerminal;
|
||||
use std::path::PathBuf;
|
||||
use supports_color::Stream;
|
||||
use tracing::Instrument;
|
||||
use tracing_subscriber::EnvFilter;
|
||||
use tracing_subscriber::prelude::*;
|
||||
|
||||
#[cfg(any(target_os = "macos", target_os = "windows"))]
|
||||
mod app_cmd;
|
||||
@@ -570,6 +573,10 @@ struct ExecServerCommand {
|
||||
use_agent_identity_auth: bool,
|
||||
}
|
||||
|
||||
const EXEC_SERVER_DEFAULT_ANALYTICS_ENABLED: bool = false;
|
||||
const EXEC_SERVER_DEFAULT_LOG_FILTER: &str = "error,opentelemetry_sdk=off,opentelemetry_otlp=off";
|
||||
const EXEC_SERVER_OTEL_SERVICE_NAME: &str = "codex-exec-server";
|
||||
|
||||
#[derive(Debug, clap::Subcommand)]
|
||||
#[allow(clippy::enum_variant_names)]
|
||||
enum AppServerSubcommand {
|
||||
@@ -1628,6 +1635,7 @@ async fn run_exec_server_command(
|
||||
.environment_id
|
||||
.ok_or_else(|| anyhow::anyhow!("--environment-id is required when --remote is set"))?;
|
||||
let config = load_exec_server_config(root_config_overrides, strict_config).await?;
|
||||
let _otel = init_exec_server_tracing(Some(&config));
|
||||
let auth_provider =
|
||||
load_exec_server_remote_auth_provider(&config, &base_url, cmd.use_agent_identity_auth)
|
||||
.await?;
|
||||
@@ -1639,25 +1647,73 @@ async fn run_exec_server_command(
|
||||
if let Some(name) = cmd.name {
|
||||
remote_config.name = name;
|
||||
}
|
||||
codex_exec_server::run_remote_environment(remote_config, runtime_paths).await?;
|
||||
codex_exec_server::run_remote_environment(remote_config, runtime_paths)
|
||||
.instrument(codex_exec_server::runtime_span())
|
||||
.await?;
|
||||
Ok(())
|
||||
} else {
|
||||
if strict_config {
|
||||
// Local exec-server startup does not consume Config, but strict
|
||||
// mode should still reject unknown fields before opening a listener.
|
||||
let _validated_config =
|
||||
load_exec_server_config(root_config_overrides, strict_config).await?;
|
||||
}
|
||||
let config = if strict_config {
|
||||
Some(load_exec_server_config(root_config_overrides, strict_config).await?)
|
||||
} else {
|
||||
load_exec_server_config(root_config_overrides, /*strict_config*/ false)
|
||||
.await
|
||||
.ok()
|
||||
};
|
||||
let _otel = init_exec_server_tracing(config.as_ref());
|
||||
let listen_url = cmd
|
||||
.listen
|
||||
.as_deref()
|
||||
.unwrap_or(codex_exec_server::DEFAULT_LISTEN_URL);
|
||||
codex_exec_server::run_main(listen_url, runtime_paths)
|
||||
.instrument(codex_exec_server::runtime_span())
|
||||
.await
|
||||
.map_err(anyhow::Error::from_boxed)
|
||||
}
|
||||
}
|
||||
|
||||
fn init_exec_server_tracing(config: Option<&codex_core::config::Config>) -> impl Send + Sync {
|
||||
let fmt_layer = tracing_subscriber::fmt::layer()
|
||||
.with_writer(std::io::stderr)
|
||||
.with_filter(exec_server_stderr_env_filter());
|
||||
let otel = config.and_then(|config| {
|
||||
match std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
|
||||
codex_core::otel_init::build_provider(
|
||||
config,
|
||||
env!("CARGO_PKG_VERSION"),
|
||||
Some(EXEC_SERVER_OTEL_SERVICE_NAME),
|
||||
EXEC_SERVER_DEFAULT_ANALYTICS_ENABLED,
|
||||
)
|
||||
})) {
|
||||
Ok(Ok(otel)) => otel,
|
||||
Ok(Err(err)) => {
|
||||
eprintln!("Could not create otel exporter: {err}");
|
||||
None
|
||||
}
|
||||
Err(_) => {
|
||||
eprintln!("Could not create otel exporter: panicked during initialization");
|
||||
None
|
||||
}
|
||||
}
|
||||
});
|
||||
codex_core::otel_init::record_process_start(otel.as_ref(), EXEC_SERVER_OTEL_SERVICE_NAME);
|
||||
|
||||
let otel_logger_layer = otel.as_ref().and_then(|otel| otel.logger_layer());
|
||||
let otel_tracing_layer = otel.as_ref().and_then(|otel| otel.tracing_layer());
|
||||
let _ = tracing_subscriber::registry()
|
||||
.with(fmt_layer)
|
||||
.with(otel_tracing_layer)
|
||||
.with(otel_logger_layer)
|
||||
.try_init();
|
||||
tracing::callsite::rebuild_interest_cache();
|
||||
otel
|
||||
}
|
||||
|
||||
fn exec_server_stderr_env_filter() -> EnvFilter {
|
||||
EnvFilter::try_from_default_env()
|
||||
.or_else(|_| EnvFilter::try_new(EXEC_SERVER_DEFAULT_LOG_FILTER))
|
||||
.unwrap_or_else(|_| EnvFilter::new("error"))
|
||||
}
|
||||
|
||||
async fn load_exec_server_remote_auth_provider(
|
||||
config: &codex_core::config::Config,
|
||||
base_url: &str,
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
use std::path::Path;
|
||||
|
||||
use anyhow::Result;
|
||||
use predicates::prelude::PredicateBooleanExt;
|
||||
use predicates::str::contains;
|
||||
use tempfile::TempDir;
|
||||
|
||||
@@ -33,3 +34,17 @@ foo = "bar"
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn local_exec_server_ignores_invalid_config_without_strict_config() -> Result<()> {
|
||||
let codex_home = TempDir::new()?;
|
||||
std::fs::write(codex_home.path().join("config.toml"), "not valid toml = [")?;
|
||||
|
||||
let mut cmd = codex_command(codex_home.path())?;
|
||||
cmd.args(["exec-server", "--listen", "stdio"])
|
||||
.assert()
|
||||
.success()
|
||||
.stderr(contains("not valid toml").not());
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user