mirror of
https://github.com/pchuan98/codex.git
synced 2026-07-01 00:31:56 +08:00
feat(core): add configurable log_dir (#10678)
Adds a top-level `log_dir` config key (defaults to `$CODEX_HOME/log`) so one-off runs can redirect `codex-tui.log` via `-c`, e.g.: codex -c log_dir=./.codex-log Also resolves relative paths in CLI `-c/--config` overrides for `AbsolutePathBuf` values against the effective cwd (when available). Tests: - cargo test -p codex-core
This commit is contained in:
@@ -271,6 +271,9 @@ pub struct Config {
|
||||
/// overridden by the `CODEX_HOME` environment variable).
|
||||
pub codex_home: PathBuf,
|
||||
|
||||
/// Directory where Codex writes log files (defaults to `$CODEX_HOME/log`).
|
||||
pub log_dir: PathBuf,
|
||||
|
||||
/// Settings that govern if and what will be written to `~/.codex/history.jsonl`.
|
||||
pub history: History,
|
||||
|
||||
@@ -896,6 +899,10 @@ pub struct ConfigToml {
|
||||
#[serde(default)]
|
||||
pub history: Option<History>,
|
||||
|
||||
/// Directory where Codex writes log files, for example `codex-tui.log`.
|
||||
/// Defaults to `$CODEX_HOME/log`.
|
||||
pub log_dir: Option<AbsolutePathBuf>,
|
||||
|
||||
/// Optional URI-based file opener. If set, citations to files in the model
|
||||
/// output will be hyperlinked using the specified URI scheme.
|
||||
pub file_opener: Option<UriBasedFileOpener>,
|
||||
@@ -1560,6 +1567,16 @@ impl Config {
|
||||
|
||||
let check_for_update_on_startup = cfg.check_for_update_on_startup.unwrap_or(true);
|
||||
|
||||
let log_dir = cfg
|
||||
.log_dir
|
||||
.as_ref()
|
||||
.map(AbsolutePathBuf::to_path_buf)
|
||||
.unwrap_or_else(|| {
|
||||
let mut p = codex_home.clone();
|
||||
p.push("log");
|
||||
p
|
||||
});
|
||||
|
||||
// Ensure that every field of ConfigRequirements is applied to the final
|
||||
// Config.
|
||||
let ConfigRequirements {
|
||||
@@ -1626,6 +1643,7 @@ impl Config {
|
||||
tool_output_token_limit: cfg.tool_output_token_limit,
|
||||
agent_max_threads,
|
||||
codex_home,
|
||||
log_dir,
|
||||
config_layer_stack,
|
||||
history,
|
||||
ephemeral: ephemeral.unwrap_or_default(),
|
||||
@@ -1816,9 +1834,7 @@ pub fn find_codex_home() -> std::io::Result<PathBuf> {
|
||||
/// Returns the path to the folder where Codex logs are stored. Does not verify
|
||||
/// that the directory exists.
|
||||
pub fn log_dir(cfg: &Config) -> std::io::Result<PathBuf> {
|
||||
let mut p = cfg.codex_home.clone();
|
||||
p.push("log");
|
||||
Ok(p)
|
||||
Ok(cfg.log_dir.clone())
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
@@ -3842,6 +3858,7 @@ model_verbosity = "high"
|
||||
tool_output_token_limit: None,
|
||||
agent_max_threads: DEFAULT_AGENT_MAX_THREADS,
|
||||
codex_home: fixture.codex_home(),
|
||||
log_dir: fixture.codex_home().join("log"),
|
||||
config_layer_stack: Default::default(),
|
||||
history: History::default(),
|
||||
ephemeral: false,
|
||||
@@ -3927,6 +3944,7 @@ model_verbosity = "high"
|
||||
tool_output_token_limit: None,
|
||||
agent_max_threads: DEFAULT_AGENT_MAX_THREADS,
|
||||
codex_home: fixture.codex_home(),
|
||||
log_dir: fixture.codex_home().join("log"),
|
||||
config_layer_stack: Default::default(),
|
||||
history: History::default(),
|
||||
ephemeral: false,
|
||||
@@ -4027,6 +4045,7 @@ model_verbosity = "high"
|
||||
tool_output_token_limit: None,
|
||||
agent_max_threads: DEFAULT_AGENT_MAX_THREADS,
|
||||
codex_home: fixture.codex_home(),
|
||||
log_dir: fixture.codex_home().join("log"),
|
||||
config_layer_stack: Default::default(),
|
||||
history: History::default(),
|
||||
ephemeral: false,
|
||||
@@ -4113,6 +4132,7 @@ model_verbosity = "high"
|
||||
tool_output_token_limit: None,
|
||||
agent_max_threads: DEFAULT_AGENT_MAX_THREADS,
|
||||
codex_home: fixture.codex_home(),
|
||||
log_dir: fixture.codex_home().join("log"),
|
||||
config_layer_stack: Default::default(),
|
||||
history: History::default(),
|
||||
ephemeral: false,
|
||||
|
||||
@@ -144,7 +144,15 @@ pub async fn load_config_layers_state(
|
||||
let cli_overrides_layer = if cli_overrides.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(overrides::build_cli_overrides_layer(cli_overrides))
|
||||
let cli_overrides_layer = overrides::build_cli_overrides_layer(cli_overrides);
|
||||
let base_dir = cwd
|
||||
.as_ref()
|
||||
.map(AbsolutePathBuf::as_path)
|
||||
.unwrap_or(codex_home);
|
||||
Some(resolve_relative_paths_in_config_toml(
|
||||
cli_overrides_layer,
|
||||
base_dir,
|
||||
)?)
|
||||
};
|
||||
|
||||
// Include an entry for the "system" config folder, loading its config.toml,
|
||||
|
||||
@@ -56,6 +56,30 @@ async fn make_config_for_test(
|
||||
.await
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn cli_overrides_resolve_relative_paths_against_cwd() -> std::io::Result<()> {
|
||||
let codex_home = tempdir().expect("tempdir");
|
||||
let cwd_dir = tempdir().expect("tempdir");
|
||||
let cwd_path = cwd_dir.path().to_path_buf();
|
||||
|
||||
let config = ConfigBuilder::default()
|
||||
.codex_home(codex_home.path().to_path_buf())
|
||||
.cli_overrides(vec![(
|
||||
"log_dir".to_string(),
|
||||
TomlValue::String("run-logs".to_string()),
|
||||
)])
|
||||
.harness_overrides(ConfigOverrides {
|
||||
cwd: Some(cwd_path.clone()),
|
||||
..Default::default()
|
||||
})
|
||||
.build()
|
||||
.await?;
|
||||
|
||||
let expected = AbsolutePathBuf::resolve_path_against_base("run-logs", cwd_path)?;
|
||||
assert_eq!(config.log_dir, expected.to_path_buf());
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn returns_config_error_for_invalid_user_config_toml() {
|
||||
let tmp = tempdir().expect("tempdir");
|
||||
|
||||
Reference in New Issue
Block a user