// file: crates/ksp-app-config-desk/src/logging_runtime.rs // version: 2 //! Runtime Logging metadata, launch identity and explicit profile application for Config Desk. use ts_rs::TS; // rust-rules: derive-import /// Metadata for one currently active persistent Logging file output. #[derive(Clone, Debug, serde::Serialize, TS)] #[serde(rename_all = "camelCase")] #[ts(export, export_to = "../frontend/ts/bindings/ksp_app_config_desk/logging_runtime/LoggingRuntimeFileDto.ts")] pub(crate) struct LoggingRuntimeFileDto { /// Stable configured output identifier. pub(crate) output_id: String, /// Resolved runtime directory. pub(crate) directory: String, /// Effective per-launch filename prefix passed to the rolling appender. pub(crate) file_name_prefix: String, /// Effective file rotation cadence. pub(crate) rotation: String, } /// Safe observable state of the currently active KSP Logging runtime. #[derive(Clone, Debug, serde::Serialize, TS)] #[serde(rename_all = "camelCase")] #[ts(export, export_to = "../frontend/ts/bindings/ksp_app_config_desk/logging_runtime/LoggingRuntimeStatusDto.ts")] pub(crate) struct LoggingRuntimeStatusDto { /// Active profile identifier, or `None` while fallback Logging is active. pub(crate) active_profile: std::option::Option, /// Source that selected the active runtime profile. pub(crate) selection_source: String, /// Monotonic runtime generation. pub(crate) generation: u32, /// Whether transient fallback Logging is active. pub(crate) fallback_active: bool, /// Stable application identifier embedded in launch-specific file names. pub(crate) application_id: String, /// Stable launch timestamp token reused by all hot reloads in this process. pub(crate) launch_timestamp: String, /// Whether the currently active console sink is enabled. pub(crate) console_enabled: bool, /// Cumulative console lines dropped by non-blocking outputs. pub(crate) dropped_console_lines: u64, /// Cumulative file lines dropped by non-blocking outputs. pub(crate) dropped_file_lines: u64, /// Cumulative lines dropped across all outputs. pub(crate) dropped_total_lines: u64, /// Active persistent file outputs and their launch-specific prefixes. pub(crate) files: std::vec::Vec, } /// Creates the stable runtime identity for this Config Desk process launch. pub(crate) fn launch_identity() -> ksp_core_lib::Result { let timestamp = format!("{}-p{}", chrono::Utc::now().format("%Y%m%d-%H%M%S%.3fZ"), std::process::id()); return ksp_logging_lib::LoggingRuntimeIdentity::new(crate::TRACING_TARGET, timestamp); } /// Returns safe metadata for the currently active Logging runtime. pub(crate) fn status(state: &crate::AppState) -> ksp_core_lib::Result { return state.logging_runtime_status(); } /// Applies one persisted Logging profile explicitly without changing `default_profile` or the source document. pub(crate) fn apply_profile(state: &crate::AppState, profile_id: &str) -> ksp_core_lib::Result { let environment = ksp_config_lib::ConfigEnvironment::load(); let environment = match environment { std::result::Result::Ok(value) => value, std::result::Result::Err(error) => return std::result::Result::Err(error), }; let resolved = state.config_management().engine().load_resolved_logging_config(std::option::Option::Some(profile_id), &environment); let resolved = match resolved { std::result::Result::Ok(value) => value, std::result::Result::Err(error) => return std::result::Result::Err(error), }; let active_profile = resolved.profile_id().to_owned(); let settings = resolved.into_settings(); let generation = state.reinitialize_logging_runtime(active_profile.as_str(), "explicit", &settings); if let std::result::Result::Err(error) = generation { return std::result::Result::Err(error); } ksp_logging_lib::debug!( target: crate::TRACING_TARGET, domain = crate::TRACING_DOMAIN_LOGGING_RUNTIME, active_profile = active_profile.as_str(), selection_source = "explicit", "persisted Logging profile applied explicitly to runtime" ); return state.logging_runtime_status(); } pub(crate) fn project_file(metadata: &ksp_logging_lib::RuntimeFileMetadata) -> LoggingRuntimeFileDto { return LoggingRuntimeFileDto { output_id: metadata.output_id().to_owned(), directory: metadata.directory().display().to_string(), file_name_prefix: metadata.file_name_prefix().to_owned(), rotation: rotation_label(metadata.rotation()).to_owned(), }; } pub(crate) const fn rotation_label(rotation: ksp_logging_lib::FileRotation) -> &'static str { return match rotation { ksp_logging_lib::FileRotation::Never => "never", ksp_logging_lib::FileRotation::Hourly => "hourly", ksp_logging_lib::FileRotation::Daily => "daily", }; } pub(crate) fn count_to_u64(value: usize) -> u64 { let converted = u64::try_from(value); return match converted { std::result::Result::Ok(value) => value, std::result::Result::Err(_) => u64::MAX, }; } #[cfg(test)] #[path = "../unit_tests/logging_runtime.rs"] mod tests;