229 lines
11 KiB
Rust
229 lines
11 KiB
Rust
// file: crates/ksp-app-raw-transaction-ingest-desk/src/bootstrap.rs
|
|
// version: 2
|
|
|
|
//! Config composite and Logging bootstrap for Raw Transaction Ingest Desk.
|
|
|
|
/// Crate-internal Logging startup state shared by the application state.
|
|
pub(crate) struct LoggingStartup {
|
|
/// Guard that keeps the installed Logging runtime alive.
|
|
pub(crate) guard: ksp_logging_lib::LoggingGuard,
|
|
/// Active managed profile when Config resolved one successfully.
|
|
pub(crate) active_profile_id: std::option::Option<String>,
|
|
/// Whether a transient in-memory fallback was installed.
|
|
pub(crate) fallback_active: bool,
|
|
/// Safe startup diagnostic retained for the shell.
|
|
pub(crate) startup_diagnostic: std::option::Option<crate::CommandErrorDto>,
|
|
}
|
|
|
|
enum LoggingStartupPlan {
|
|
Managed {
|
|
active_profile_id: String,
|
|
settings: ksp_logging_lib::LoggingSettings,
|
|
},
|
|
Fallback {
|
|
initial_error: ksp_core_lib::Error,
|
|
diagnostic: crate::CommandErrorDto,
|
|
settings: ksp_logging_lib::LoggingSettings,
|
|
},
|
|
}
|
|
|
|
/// Builds the Config management facade from the common KSP CLI bootstrap contract.
|
|
pub(crate) fn config_management(arguments: &[std::ffi::OsString]) -> ksp_core_lib::Result<ksp_config_lib::ConfigManagement> {
|
|
let bootstrap = ksp_config_lib::ConfigBootstrapOptions::from_args(arguments);
|
|
let bootstrap = match bootstrap {
|
|
std::result::Result::Ok(value) => value,
|
|
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
|
};
|
|
let registry = ksp_config_lib::ConfigFileRegistry::from_args(arguments);
|
|
let registry = match registry {
|
|
std::result::Result::Ok(value) => value,
|
|
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
|
};
|
|
let engine = ksp_config_lib::ConfigDocumentEngine::new(bootstrap, registry);
|
|
return std::result::Result::Ok(ksp_config_lib::ConfigManagement::new(engine));
|
|
}
|
|
|
|
/// Loads the concrete Raw Transaction Ingest Desk Config composite using its registered logical `file_id` and autonomous default profile.
|
|
pub(crate) fn load_raw_transaction_ingest_desk_composite(
|
|
management: &ksp_config_lib::ConfigManagement,
|
|
) -> ksp_core_lib::Result<ksp_config_lib::ResolvedConfigComposite> {
|
|
return crate::load_raw_transaction_ingest_desk_composite_profile(management, std::option::Option::None);
|
|
}
|
|
|
|
/// Loads one explicit or default Raw Transaction Ingest Desk composite profile by registered logical file identifier.
|
|
pub(crate) fn load_raw_transaction_ingest_desk_composite_profile(
|
|
management: &ksp_config_lib::ConfigManagement,
|
|
requested_profile: std::option::Option<&str>,
|
|
) -> ksp_core_lib::Result<ksp_config_lib::ResolvedConfigComposite> {
|
|
let file_id = ksp_config_lib::ConfigFileId::new(ksp_config_lib::FILE_ID_COMPOSITE_KSP_APP_RAW_TRANSACTION_INGEST_DESK);
|
|
let file_id = match file_id {
|
|
std::result::Result::Ok(value) => value,
|
|
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
|
};
|
|
return management.engine().load_resolved_composite(&file_id, requested_profile);
|
|
}
|
|
|
|
/// Returns one required standard profile from the Raw Transaction Ingest Desk composite after validating the referenced logical `file_id`.
|
|
pub(crate) fn required_composite_component_profile(
|
|
composite: &ksp_config_lib::ResolvedConfigComposite,
|
|
component_id: &str,
|
|
expected_file_id: &str,
|
|
) -> ksp_core_lib::Result<ksp_config_lib::ResolvedConfigProfile> {
|
|
let component = composite.component(component_id);
|
|
let component = match component {
|
|
std::option::Option::Some(value) => value,
|
|
std::option::Option::None => {
|
|
return std::result::Result::Err(
|
|
ksp_core_lib::Error::new(crate::ERROR_CODE_CONFIG_COMPOSITE_INVALID, "Raw Transaction Ingest Desk composite is missing a required component")
|
|
.with_context("composite_file_id", composite.file_id().as_str())
|
|
.with_context("composite_profile_id", composite.profile_id())
|
|
.with_context("component_id", component_id),
|
|
);
|
|
},
|
|
};
|
|
if component.resolved().file_id().as_str() != expected_file_id {
|
|
return std::result::Result::Err(
|
|
ksp_core_lib::Error::new(
|
|
crate::ERROR_CODE_CONFIG_COMPOSITE_INVALID,
|
|
"Raw Transaction Ingest Desk composite component references an unexpected Config document",
|
|
)
|
|
.with_context("composite_file_id", composite.file_id().as_str())
|
|
.with_context("composite_profile_id", composite.profile_id())
|
|
.with_context("component_id", component_id)
|
|
.with_context("expected_file_id", expected_file_id)
|
|
.with_context("actual_file_id", component.resolved().file_id().as_str()),
|
|
);
|
|
}
|
|
return std::result::Result::Ok(component.resolved().clone());
|
|
}
|
|
|
|
/// Initializes Logging from the Raw Transaction Ingest Desk composite, with a trace-level development fallback.
|
|
pub(crate) fn initialize_logging(
|
|
management: &ksp_config_lib::ConfigManagement,
|
|
runtime_identity: &ksp_logging_lib::LoggingRuntimeIdentity,
|
|
) -> ksp_core_lib::Result<crate::LoggingStartup> {
|
|
let plan = resolve_logging_startup(management);
|
|
return match plan {
|
|
LoggingStartupPlan::Managed { active_profile_id, settings } => {
|
|
let guard = ksp_logging_lib::initialize_with_identity(&settings, runtime_identity);
|
|
match guard {
|
|
std::result::Result::Ok(guard) => {
|
|
ksp_logging_lib::info!(
|
|
target: crate::TRACING_TARGET,
|
|
domain = crate::TRACING_DOMAIN_BOOTSTRAP,
|
|
active_profile = active_profile_id.as_str(),
|
|
"initialized Raw Transaction Ingest Desk logging from composite-managed configuration"
|
|
);
|
|
std::result::Result::Ok(LoggingStartup {
|
|
guard,
|
|
active_profile_id: std::option::Option::Some(active_profile_id),
|
|
fallback_active: false,
|
|
startup_diagnostic: std::option::Option::None,
|
|
})
|
|
},
|
|
std::result::Result::Err(error) => initialize_fallback_logging(error, runtime_identity),
|
|
}
|
|
},
|
|
LoggingStartupPlan::Fallback { initial_error, diagnostic, settings } => {
|
|
initialize_planned_fallback_logging(initial_error, diagnostic, settings, runtime_identity)
|
|
},
|
|
};
|
|
}
|
|
|
|
fn fallback_logging_settings() -> ksp_logging_lib::LoggingSettings {
|
|
return ksp_logging_lib::LoggingSettings::new(
|
|
ksp_logging_lib::LogFilterLevel::Trace,
|
|
ksp_logging_lib::SpanEvents::Off,
|
|
std::option::Option::Some(ksp_logging_lib::ConsoleSettings::stderr()),
|
|
std::vec::Vec::new(),
|
|
);
|
|
}
|
|
|
|
fn resolve_logging_startup(management: &ksp_config_lib::ConfigManagement) -> LoggingStartupPlan {
|
|
let environment = ksp_config_lib::ConfigEnvironment::load();
|
|
let environment = match environment {
|
|
std::result::Result::Ok(value) => value,
|
|
std::result::Result::Err(error) => return fallback_startup_plan(error),
|
|
};
|
|
let composite = crate::load_raw_transaction_ingest_desk_composite(management);
|
|
let composite = match composite {
|
|
std::result::Result::Ok(value) => value,
|
|
std::result::Result::Err(error) => return fallback_startup_plan(error),
|
|
};
|
|
let logging_profile = crate::required_composite_component_profile(&composite, crate::COMPOSITE_COMPONENT_ID_LOGGING, ksp_config_lib::FILE_ID_STD_LOGGING);
|
|
let logging_profile = match logging_profile {
|
|
std::result::Result::Ok(value) => value,
|
|
std::result::Result::Err(error) => return fallback_startup_plan(error),
|
|
};
|
|
let transport_profile =
|
|
crate::required_composite_component_profile(&composite, crate::COMPOSITE_COMPONENT_ID_TRANSPORT, ksp_config_lib::FILE_ID_STD_TRANSPORT);
|
|
if let std::result::Result::Err(error) = transport_profile {
|
|
return fallback_startup_plan(error);
|
|
}
|
|
let store_profile = crate::required_composite_component_profile(&composite, crate::COMPOSITE_COMPONENT_ID_STORE, ksp_config_lib::FILE_ID_STD_STORE);
|
|
if let std::result::Result::Err(error) = store_profile {
|
|
return fallback_startup_plan(error);
|
|
}
|
|
let resolved = management.engine().resolve_logging_config_profile(&logging_profile, &environment);
|
|
let resolved = match resolved {
|
|
std::result::Result::Ok(value) => value,
|
|
std::result::Result::Err(error) => return fallback_startup_plan(error),
|
|
};
|
|
return LoggingStartupPlan::Managed { active_profile_id: resolved.profile_id().to_owned(), settings: resolved.into_settings() };
|
|
}
|
|
|
|
fn fallback_startup_plan(initial_error: ksp_core_lib::Error) -> LoggingStartupPlan {
|
|
let diagnostic = crate::CommandErrorDto::from_error(&initial_error);
|
|
return LoggingStartupPlan::Fallback { initial_error, diagnostic, settings: fallback_logging_settings() };
|
|
}
|
|
|
|
fn initialize_fallback_logging(
|
|
initial_error: ksp_core_lib::Error,
|
|
runtime_identity: &ksp_logging_lib::LoggingRuntimeIdentity,
|
|
) -> ksp_core_lib::Result<crate::LoggingStartup> {
|
|
let diagnostic = crate::CommandErrorDto::from_error(&initial_error);
|
|
return initialize_planned_fallback_logging(initial_error, diagnostic, fallback_logging_settings(), runtime_identity);
|
|
}
|
|
|
|
fn initialize_planned_fallback_logging(
|
|
initial_error: ksp_core_lib::Error,
|
|
diagnostic: crate::CommandErrorDto,
|
|
settings: ksp_logging_lib::LoggingSettings,
|
|
runtime_identity: &ksp_logging_lib::LoggingRuntimeIdentity,
|
|
) -> ksp_core_lib::Result<crate::LoggingStartup> {
|
|
let guard = ksp_logging_lib::initialize_with_identity(&settings, runtime_identity);
|
|
let guard = match guard {
|
|
std::result::Result::Ok(value) => value,
|
|
std::result::Result::Err(fallback_error) => {
|
|
return std::result::Result::Err(
|
|
ksp_core_lib::Error::new(crate::ERROR_CODE_LOGGING_BOOTSTRAP_FAILED, "Cannot initialize Raw Transaction Ingest Desk fallback Logging runtime")
|
|
.with_context("initial_error_domain", initial_error.code().domain())
|
|
.with_context("initial_error_code", initial_error.code().code())
|
|
.with_source(fallback_error),
|
|
);
|
|
},
|
|
};
|
|
ksp_logging_lib::warn!(
|
|
target: crate::TRACING_TARGET,
|
|
domain = crate::TRACING_DOMAIN_BOOTSTRAP,
|
|
error_domain = diagnostic.domain.as_str(),
|
|
error_code = diagnostic.code.as_str(),
|
|
"managed Logging configuration is unavailable; using transient trace-level development fallback"
|
|
);
|
|
return std::result::Result::Ok(LoggingStartup {
|
|
guard,
|
|
active_profile_id: std::option::Option::None,
|
|
fallback_active: true,
|
|
startup_diagnostic: std::option::Option::Some(diagnostic),
|
|
});
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
#[test]
|
|
fn development_fallback_keeps_trace_level_enabled() {
|
|
let settings = super::fallback_logging_settings();
|
|
assert_eq!(settings.default_filter(), ksp_logging_lib::LogFilterLevel::Trace);
|
|
}
|
|
}
|