Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions .sce/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,7 @@
"pi"
]
},
"log_file": "context/tmp/sce.log",
"log_file_mode": "append",
"log_dir": "context/tmp",
"log_level": "error",
"policies": {
"attribution_hooks": {
Expand Down
19 changes: 6 additions & 13 deletions cli/assets/generated/config/schema/sce-config.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,16 +25,14 @@
"json"
]
},
"log_file": {
"log_dir": {
"type": "string",
"minLength": 1
},
"log_file_mode": {
"type": "string",
"enum": [
"truncate",
"append"
]
"log_file_retention_limit": {
"default": 10,
"type": "integer",
"minimum": 1
},
"timeout_ms": {
"type": "integer",
Expand Down Expand Up @@ -376,10 +374,5 @@
"additionalProperties": false
}
},
"additionalProperties": false,
"dependentRequired": {
"log_file_mode": [
"log_file"
]
}
"additionalProperties": false
}
2 changes: 2 additions & 0 deletions cli/src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -356,6 +356,7 @@ where
"sce.app.start",
"Starting command dispatch",
&[("component", services::observability::NAME)],
None,
);
let Some(command_args) = args.take() else {
return Err(ClassifiedError::runtime(REPEATED_COMMAND_DISPATCH_ERROR));
Expand All @@ -380,6 +381,7 @@ where
"sce.command.parsed",
"Command parsed",
&[("command", command.name().as_ref())],
None,
);
Ok(command)
}
7 changes: 6 additions & 1 deletion cli/src/services/app_support.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,13 +88,15 @@ pub(crate) fn log_startup_configuration(
("path", loaded_path.path.to_string_lossy().as_ref()),
("source", loaded_path.source.as_str()),
],
None,
);
}
for validation_error in &observability_config.validation_errors {
logger.warn(
INVALID_CONFIG_WARNING_EVENT_ID,
"Invalid discovered config skipped; using degraded defaults",
&[("error", validation_error.as_str())],
None,
);
}
}
Expand All @@ -112,20 +114,23 @@ where
"sce.command.dispatch_start",
"Dispatching command",
&[("command", command_name.as_ref())],
None,
);
let dispatch_result = command.execute(context);
if dispatch_result.is_ok() {
logger.debug(
"sce.command.dispatch_end",
"Command dispatch completed",
&[("command", command_name.as_ref())],
None,
);
}
dispatch_result.inspect(|_payload| {
logger.info(
"sce.command.completed",
"Command completed",
&[("command", command_name.as_ref())],
None,
);
})
}
Expand All @@ -136,7 +141,7 @@ where
W: Write,
{
if let Some(log) = logger {
log.log_classified_error(error);
log.log_classified_error(error, None);
}
write_error_diagnostic(stderr, error);
ExitCode::from(error.class().exit_code())
Expand Down
16 changes: 8 additions & 8 deletions cli/src/services/config/render.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,10 +66,10 @@ pub(super) fn format_show_output(runtime: &RuntimeConfig, report_format: ReportF
runtime.log_format.value.as_str(),
runtime.log_format.source,
),
"log_file": format_optional_resolved_value_json(&runtime.log_file),
"log_file_mode": format_resolved_value_json(
runtime.log_file_mode.value.as_str(),
runtime.log_file_mode.source,
"log_dir": format_optional_resolved_value_json(&runtime.log_dir),
"log_file_retention_limit": format_resolved_value_json(
runtime.log_file_retention_limit.value,
runtime.log_file_retention_limit.source,
),
"timeout_ms": {
"value": runtime.timeout_ms.value,
Expand Down Expand Up @@ -220,11 +220,11 @@ fn format_observability_text_lines(runtime: &RuntimeConfig) -> Vec<String> {
runtime.log_format.value.as_str(),
runtime.log_format.source,
),
format_optional_resolved_value_text("log_file", &runtime.log_file),
format_optional_resolved_value_text("log_dir", &runtime.log_dir),
format_resolved_value_text(
"log_file_mode",
runtime.log_file_mode.value.as_str(),
runtime.log_file_mode.source,
"log_file_retention_limit",
&runtime.log_file_retention_limit.value.to_string(),
runtime.log_file_retention_limit.source,
),
]
}
Expand Down
99 changes: 50 additions & 49 deletions cli/src/services/config/resolver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,18 @@ use std::path::{Path, PathBuf};

use anyhow::{anyhow, bail, Context, Result};

use crate::services::default_paths::{resolve_sce_default_locations, RepoPaths};
use crate::services::default_paths::{
observability_log_dir, resolve_sce_default_locations, RepoPaths,
};

use super::policy::{build_validation_warnings, resolve_bash_policy_config, BashPolicyConfig};
use super::schema;
use super::types::{
parse_bool_value_from, ConfigPathSource, ConfigRequest, DatabaseRetryConfig, LoadedConfigPath,
LogFileMode, LogFormat, LogLevel, ReportFormat, ResolvedAgentTraceStorageRuntimeConfig,
LogFormat, LogLevel, ReportFormat, ResolvedAgentTraceStorageRuntimeConfig,
ResolvedAuthRuntimeConfig, ResolvedHookRuntimeConfig, ResolvedObservabilityRuntimeConfig,
ResolvedOptionalValue, ResolvedValue, ValueSource, ENV_ATTRIBUTION_HOOKS_DISABLED,
ENV_LOG_FILE, ENV_LOG_FILE_MODE, ENV_LOG_FORMAT, ENV_LOG_LEVEL,
ResolvedOptionalValue, ResolvedValue, ValueSource, DEFAULT_LOG_FILE_RETENTION_LIMIT,
ENV_ATTRIBUTION_HOOKS_DISABLED, ENV_LOG_DIR, ENV_LOG_FORMAT, ENV_LOG_LEVEL,
};

const DEFAULT_TIMEOUT_MS: u64 = 30000;
Expand Down Expand Up @@ -59,8 +61,8 @@ pub(super) struct RuntimeConfig {
pub(super) loaded_config_paths: Vec<LoadedConfigPath>,
pub(super) log_level: ResolvedValue<LogLevel>,
pub(super) log_format: ResolvedValue<LogFormat>,
pub(super) log_file: ResolvedOptionalValue<String>,
pub(super) log_file_mode: ResolvedValue<LogFileMode>,
pub(super) log_dir: ResolvedOptionalValue<String>,
pub(super) log_file_retention_limit: ResolvedValue<usize>,
pub(super) timeout_ms: ResolvedValue<u64>,
pub(super) attribution_hooks_enabled: ResolvedValue<bool>,
pub(super) workos_client_id: ResolvedOptionalValue<String>,
Expand Down Expand Up @@ -220,8 +222,8 @@ where
Ok(ResolvedObservabilityRuntimeConfig {
log_level: runtime.log_level.value,
log_format: runtime.log_format.value,
log_file: runtime.log_file.value,
log_file_mode: runtime.log_file_mode.value,
log_dir: runtime.log_dir.value,
log_file_retention_limit: runtime.log_file_retention_limit.value,
loaded_config_paths: runtime.loaded_config_paths,
validation_errors: runtime.validation_errors,
})
Expand Down Expand Up @@ -297,8 +299,8 @@ where
let mut file_config = schema::FileConfig {
log_level: None,
log_format: None,
log_file: None,
log_file_mode: None,
log_dir: None,
log_file_retention_limit: None,
timeout_ms: None,
attribution_hooks_enabled: None,
workos_client_id: None,
Expand Down Expand Up @@ -326,11 +328,11 @@ where
if let Some(log_format) = layer.log_format {
file_config.log_format = Some(log_format);
}
if let Some(log_file) = layer.log_file {
file_config.log_file = Some(log_file);
if let Some(log_dir) = layer.log_dir {
file_config.log_dir = Some(log_dir);
}
if let Some(log_file_mode) = layer.log_file_mode {
file_config.log_file_mode = Some(log_file_mode);
if let Some(log_file_retention_limit) = layer.log_file_retention_limit {
file_config.log_file_retention_limit = Some(log_file_retention_limit);
}
if let Some(timeout_ms) = layer.timeout_ms {
file_config.timeout_ms = Some(timeout_ms);
Expand Down Expand Up @@ -401,44 +403,30 @@ where
};
}

let mut resolved_log_file = ResolvedOptionalValue {
value: file_config
.log_file
.as_ref()
.map(|value| value.value.clone()),
source: file_config
.log_file
.as_ref()
.map(|value| ValueSource::ConfigFile(value.source)),
};
if let Some(raw) = env_lookup(ENV_LOG_FILE) {
resolved_log_file = ResolvedOptionalValue {
let resolved_log_dir = if let Some(raw) = env_lookup(ENV_LOG_DIR) {
ResolvedOptionalValue {
value: Some(raw),
source: Some(ValueSource::Env),
};
}

let mut resolved_log_file_mode = ResolvedValue {
value: LogFileMode::Truncate,
source: ValueSource::Default,
}
} else if let Some(value) = file_config.log_dir.as_ref() {
ResolvedOptionalValue {
value: Some(value.value.clone()),
source: Some(ValueSource::ConfigFile(value.source)),
}
} else {
default_observability_log_dir()?
};
if let Some(value) = file_config.log_file_mode {
resolved_log_file_mode = ResolvedValue {

let resolved_log_file_retention_limit = match file_config.log_file_retention_limit {
Some(value) => ResolvedValue {
value: value.value,
source: ValueSource::ConfigFile(value.source),
};
}
if let Some(raw) = env_lookup(ENV_LOG_FILE_MODE) {
resolved_log_file_mode = ResolvedValue {
value: LogFileMode::parse(&raw, ENV_LOG_FILE_MODE)?,
source: ValueSource::Env,
};
}
if resolved_log_file.value.is_none() && resolved_log_file_mode.source != ValueSource::Default {
bail!(
"{ENV_LOG_FILE_MODE} requires {ENV_LOG_FILE}. Try: set {ENV_LOG_FILE} to a file path or unset {ENV_LOG_FILE_MODE}."
);
}
},
None => ResolvedValue {
value: DEFAULT_LOG_FILE_RETENTION_LIMIT,
source: ValueSource::Default,
},
};

let mut resolved_timeout_ms = ResolvedValue {
value: DEFAULT_TIMEOUT_MS,
Expand Down Expand Up @@ -527,8 +515,8 @@ where
loaded_config_paths,
log_level: resolved_log_level,
log_format: resolved_log_format,
log_file: resolved_log_file,
log_file_mode: resolved_log_file_mode,
log_dir: resolved_log_dir,
log_file_retention_limit: resolved_log_file_retention_limit,
timeout_ms: resolved_timeout_ms,
attribution_hooks_enabled: resolved_attribution_hooks_enabled,
workos_client_id: resolved_workos_client_id,
Expand Down Expand Up @@ -576,6 +564,19 @@ where
}
}

fn default_observability_log_dir() -> Result<ResolvedOptionalValue<String>> {
let path = observability_log_dir().with_context(|| {
format!(
"Failed to resolve default observability log directory for {ENV_LOG_DIR}; set {ENV_LOG_DIR} or config log_dir explicitly."
)
})?;

Ok(ResolvedOptionalValue {
value: Some(path.to_string_lossy().into_owned()),
source: Some(ValueSource::Default),
})
}

fn resolve_config_paths<FEnv, FGlobalPath>(
request: &ConfigRequest,
cwd: &Path,
Expand Down
36 changes: 14 additions & 22 deletions cli/src/services/config/schema.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ use serde_json::Value;

use super::policy::{parse_bash_policy_presets, parse_custom_bash_policies, CustomBashPolicyEntry};
use super::types::{
ConfigPathSource, DatabaseRetryConfig, IntegrationTargetId, IntegrationsConfig, LogFileMode,
LogFormat, LogLevel,
ConfigPathSource, DatabaseRetryConfig, IntegrationTargetId, IntegrationsConfig, LogFormat,
LogLevel,
};
use crate::services::resilience::RetryPolicy;

Expand All @@ -32,8 +32,8 @@ pub(crate) const TOP_LEVEL_CONFIG_KEYS: &[&str] = &[
CONFIG_SCHEMA_DECLARATION_KEY,
"log_level",
"log_format",
"log_file",
"log_file_mode",
"log_dir",
"log_file_retention_limit",
"timeout_ms",
super::resolver::WORKOS_CLIENT_ID_KEY.config_key,
"agent_trace",
Expand All @@ -42,7 +42,7 @@ pub(crate) const TOP_LEVEL_CONFIG_KEYS: &[&str] = &[
];

pub(crate) const TOP_LEVEL_CONFIG_KEYS_DESCRIPTION: &str =
"$schema, log_level, log_format, log_file, log_file_mode, timeout_ms, workos_client_id, agent_trace, policies, integrations";
"$schema, log_level, log_format, timeout_ms, workos_client_id, agent_trace, policies, integrations, log_dir, log_file_retention_limit";

static CONFIG_SCHEMA_VALIDATOR: OnceLock<Validator> = OnceLock::new();

Expand All @@ -68,8 +68,8 @@ pub(crate) struct ParsedFileConfigDocument {
pub(crate) _schema: Option<String>,
pub(crate) log_level: Option<String>,
pub(crate) log_format: Option<String>,
pub(crate) log_file: Option<String>,
pub(crate) log_file_mode: Option<String>,
pub(crate) log_dir: Option<String>,
pub(crate) log_file_retention_limit: Option<usize>,
pub(crate) timeout_ms: Option<u64>,
pub(crate) workos_client_id: Option<String>,
pub(crate) agent_trace: Option<ParsedAgentTraceConfigDocument>,
Expand Down Expand Up @@ -151,8 +151,8 @@ pub(crate) struct FileConfigValue<T> {
pub(crate) struct FileConfig {
pub(crate) log_level: Option<FileConfigValue<LogLevel>>,
pub(crate) log_format: Option<FileConfigValue<LogFormat>>,
pub(crate) log_file: Option<FileConfigValue<String>>,
pub(crate) log_file_mode: Option<FileConfigValue<LogFileMode>>,
pub(crate) log_dir: Option<FileConfigValue<String>>,
pub(crate) log_file_retention_limit: Option<FileConfigValue<usize>>,
pub(crate) timeout_ms: Option<FileConfigValue<u64>>,
pub(crate) attribution_hooks_enabled: Option<FileConfigValue<bool>>,
pub(crate) workos_client_id: Option<FileConfigValue<String>>,
Expand Down Expand Up @@ -286,18 +286,10 @@ pub(crate) fn parse_file_config(
})
})
.transpose()?;
let log_file = typed
.log_file
let log_dir = typed.log_dir.map(|value| FileConfigValue { value, source });
let log_file_retention_limit = typed
.log_file_retention_limit
.map(|value| FileConfigValue { value, source });
let log_file_mode = typed
.log_file_mode
.map(|raw| -> Result<FileConfigValue<LogFileMode>> {
Ok(FileConfigValue {
value: LogFileMode::parse(&raw, &format!("config file '{}'", path.display()))?,
source,
})
})
.transpose()?;
let timeout_ms = typed
.timeout_ms
.map(|value| FileConfigValue { value, source });
Expand All @@ -313,8 +305,8 @@ pub(crate) fn parse_file_config(
Ok(FileConfig {
log_level,
log_format,
log_file,
log_file_mode,
log_dir,
log_file_retention_limit,
timeout_ms,
attribution_hooks_enabled,
workos_client_id,
Expand Down
Loading
Loading