v0.1.4-pre.016
This commit is contained in:
@@ -1,11 +1,12 @@
|
||||
// file: crates/ksp-app-config-desk/src/app_state.rs
|
||||
// version: 5
|
||||
// version: 6
|
||||
|
||||
//! Shared backend state owned by the Tauri application.
|
||||
|
||||
struct LoggingRuntimeState {
|
||||
guard: ksp_logging_lib::LoggingGuard,
|
||||
active_profile_id: std::option::Option<String>,
|
||||
selection_source: String,
|
||||
generation: u32,
|
||||
fallback_active: bool,
|
||||
startup_diagnostic: std::option::Option<crate::CommandErrorDto>,
|
||||
@@ -27,7 +28,12 @@ impl AppState {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
||||
};
|
||||
let logging_startup = crate::initialize_logging(&config_management);
|
||||
let runtime_identity = crate::logging_runtime::launch_identity();
|
||||
let runtime_identity = match runtime_identity {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
||||
};
|
||||
let logging_startup = crate::initialize_logging(&config_management, &runtime_identity);
|
||||
let logging_startup = match logging_startup {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
||||
@@ -61,6 +67,7 @@ impl AppState {
|
||||
logging_runtime: std::sync::Mutex::new(LoggingRuntimeState {
|
||||
guard: logging_startup.guard,
|
||||
active_profile_id: logging_startup.active_profile_id,
|
||||
selection_source: logging_startup.selection_source,
|
||||
generation: 1,
|
||||
fallback_active: logging_startup.fallback_active,
|
||||
startup_diagnostic: logging_startup.startup_diagnostic,
|
||||
@@ -111,7 +118,12 @@ impl AppState {
|
||||
}
|
||||
|
||||
/// Replaces the active Logging runtime with freshly resolved settings and advances the runtime generation only after success.
|
||||
pub(crate) fn reinitialize_logging_runtime(&self, profile_id: &str, settings: &ksp_logging_lib::LoggingSettings) -> ksp_core_lib::Result<u32> {
|
||||
pub(crate) fn reinitialize_logging_runtime(
|
||||
&self,
|
||||
profile_id: &str,
|
||||
selection_source: &str,
|
||||
settings: &ksp_logging_lib::LoggingSettings,
|
||||
) -> ksp_core_lib::Result<u32> {
|
||||
let runtime = self.logging_runtime.lock();
|
||||
let mut runtime = match runtime {
|
||||
std::result::Result::Ok(value) => value,
|
||||
@@ -127,12 +139,59 @@ impl AppState {
|
||||
return std::result::Result::Err(error);
|
||||
}
|
||||
runtime.active_profile_id = std::option::Option::Some(profile_id.to_owned());
|
||||
runtime.selection_source = selection_source.to_owned();
|
||||
runtime.generation = runtime.generation.saturating_add(1);
|
||||
runtime.fallback_active = false;
|
||||
runtime.startup_diagnostic = std::option::Option::None;
|
||||
return std::result::Result::Ok(runtime.generation);
|
||||
}
|
||||
|
||||
/// Returns a safe observable snapshot of the currently active Logging runtime.
|
||||
pub(crate) fn logging_runtime_status(&self) -> ksp_core_lib::Result<crate::LoggingRuntimeStatusDto> {
|
||||
let runtime = self.logging_runtime.lock();
|
||||
let runtime = match runtime {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(_) => {
|
||||
return std::result::Result::Err(ksp_core_lib::Error::new(
|
||||
crate::ERROR_CODE_APP_STATE_LOCK_FAILED,
|
||||
"Config Desk Logging runtime state lock is poisoned",
|
||||
));
|
||||
},
|
||||
};
|
||||
let identity = runtime.guard.runtime_identity();
|
||||
let identity = match identity {
|
||||
std::option::Option::Some(value) => value,
|
||||
std::option::Option::None => {
|
||||
return std::result::Result::Err(ksp_core_lib::Error::new(
|
||||
crate::ERROR_CODE_APP_STATE_INVALID,
|
||||
"Config Desk Logging runtime is missing its application launch identity",
|
||||
));
|
||||
},
|
||||
};
|
||||
let console_enabled = match runtime.guard.settings().console() {
|
||||
std::option::Option::Some(console) => console.enabled(),
|
||||
std::option::Option::None => false,
|
||||
};
|
||||
let dropped = runtime.guard.dropped_lines();
|
||||
let mut files = std::vec::Vec::<crate::LoggingRuntimeFileDto>::new();
|
||||
for metadata in runtime.guard.active_file_outputs() {
|
||||
files.push(crate::logging_runtime::project_file(&metadata));
|
||||
}
|
||||
return std::result::Result::Ok(crate::LoggingRuntimeStatusDto {
|
||||
active_profile: runtime.active_profile_id.clone(),
|
||||
selection_source: runtime.selection_source.clone(),
|
||||
generation: runtime.generation,
|
||||
fallback_active: runtime.fallback_active,
|
||||
application_id: identity.application_id().to_owned(),
|
||||
launch_timestamp: identity.launch_timestamp().to_owned(),
|
||||
console_enabled,
|
||||
dropped_console_lines: crate::logging_runtime::count_to_u64(dropped.console()),
|
||||
dropped_file_lines: crate::logging_runtime::count_to_u64(dropped.file()),
|
||||
dropped_total_lines: crate::logging_runtime::count_to_u64(dropped.total()),
|
||||
files,
|
||||
});
|
||||
}
|
||||
|
||||
/// Returns the resolved splash timings captured during application bootstrap.
|
||||
#[must_use]
|
||||
pub(crate) const fn splash_settings(&self) -> crate::SplashSettings {
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
// file: crates/ksp-app-config-desk/src/bootstrap.rs
|
||||
// version: 1
|
||||
// version: 2
|
||||
|
||||
//! Config and Logging bootstrap for the desktop application.
|
||||
|
||||
pub(crate) struct LoggingStartup {
|
||||
pub(crate) guard: ksp_logging_lib::LoggingGuard,
|
||||
pub(crate) active_profile_id: std::option::Option<String>,
|
||||
pub(crate) selection_source: String,
|
||||
pub(crate) fallback_active: bool,
|
||||
pub(crate) startup_diagnostic: std::option::Option<crate::CommandErrorDto>,
|
||||
}
|
||||
@@ -25,20 +26,23 @@ pub(crate) fn config_management(arguments: &[std::ffi::OsString]) -> ksp_core_li
|
||||
return std::result::Result::Ok(ksp_config_lib::ConfigManagement::new(engine));
|
||||
}
|
||||
|
||||
pub(crate) fn initialize_logging(management: &ksp_config_lib::ConfigManagement) -> ksp_core_lib::Result<LoggingStartup> {
|
||||
pub(crate) fn initialize_logging(
|
||||
management: &ksp_config_lib::ConfigManagement,
|
||||
runtime_identity: &ksp_logging_lib::LoggingRuntimeIdentity,
|
||||
) -> ksp_core_lib::Result<LoggingStartup> {
|
||||
let environment = ksp_config_lib::ConfigEnvironment::load();
|
||||
let environment = match environment {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(error) => return initialize_fallback_logging(error),
|
||||
std::result::Result::Err(error) => return initialize_fallback_logging(error, runtime_identity),
|
||||
};
|
||||
let resolved = management.engine().load_resolved_logging_config(std::option::Option::None, &environment);
|
||||
let resolved = match resolved {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(error) => return initialize_fallback_logging(error),
|
||||
std::result::Result::Err(error) => return initialize_fallback_logging(error, runtime_identity),
|
||||
};
|
||||
let active_profile_id = resolved.profile_id().to_owned();
|
||||
let settings = resolved.into_settings();
|
||||
let guard = ksp_logging_lib::initialize(&settings);
|
||||
let guard = ksp_logging_lib::initialize_with_identity(&settings, runtime_identity);
|
||||
return match guard {
|
||||
std::result::Result::Ok(guard) => {
|
||||
ksp_logging_lib::info!(
|
||||
@@ -50,18 +54,22 @@ pub(crate) fn initialize_logging(management: &ksp_config_lib::ConfigManagement)
|
||||
std::result::Result::Ok(LoggingStartup {
|
||||
guard,
|
||||
active_profile_id: std::option::Option::Some(active_profile_id),
|
||||
selection_source: "default_profile".to_owned(),
|
||||
fallback_active: false,
|
||||
startup_diagnostic: std::option::Option::None,
|
||||
})
|
||||
},
|
||||
std::result::Result::Err(error) => initialize_fallback_logging(error),
|
||||
std::result::Result::Err(error) => initialize_fallback_logging(error, runtime_identity),
|
||||
};
|
||||
}
|
||||
|
||||
fn initialize_fallback_logging(initial_error: ksp_core_lib::Error) -> ksp_core_lib::Result<LoggingStartup> {
|
||||
fn initialize_fallback_logging(
|
||||
initial_error: ksp_core_lib::Error,
|
||||
runtime_identity: &ksp_logging_lib::LoggingRuntimeIdentity,
|
||||
) -> ksp_core_lib::Result<LoggingStartup> {
|
||||
let diagnostic = crate::CommandErrorDto::from_error(&initial_error);
|
||||
let settings = fallback_logging_settings();
|
||||
let guard = ksp_logging_lib::initialize(&settings);
|
||||
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) => {
|
||||
@@ -83,6 +91,7 @@ fn initialize_fallback_logging(initial_error: ksp_core_lib::Error) -> ksp_core_l
|
||||
return std::result::Result::Ok(LoggingStartup {
|
||||
guard,
|
||||
active_profile_id: std::option::Option::None,
|
||||
selection_source: "fallback".to_owned(),
|
||||
fallback_active: true,
|
||||
startup_diagnostic: std::option::Option::Some(diagnostic),
|
||||
});
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// file: crates/ksp-app-config-desk/src/constants.rs
|
||||
// version: 7
|
||||
// version: 8
|
||||
|
||||
//! Application-owned tracing targets and domains.
|
||||
|
||||
@@ -27,3 +27,5 @@ pub(crate) const TRACING_DOMAIN_ENVIRONMENT: &str = "config.environment";
|
||||
pub(crate) const TRACING_DOMAIN_SECRETS: &str = "config.secrets";
|
||||
/// Structured domain for typed Logging editor inspection.
|
||||
pub(crate) const TRACING_DOMAIN_LOGGING_EDITOR: &str = "config.logging_editor";
|
||||
/// Structured domain for active Logging runtime metadata and explicit profile application.
|
||||
pub(crate) const TRACING_DOMAIN_LOGGING_RUNTIME: &str = "config.logging_runtime";
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// file: crates/ksp-app-config-desk/src/lib.rs
|
||||
// version: 12
|
||||
// version: 13
|
||||
|
||||
//! Tauri desktop application for managing and validating KSP configuration.
|
||||
|
||||
@@ -16,6 +16,7 @@ mod environment;
|
||||
mod errors;
|
||||
mod frontend_logging;
|
||||
mod logging_editor;
|
||||
mod logging_runtime;
|
||||
mod profiles;
|
||||
mod secrets;
|
||||
mod splash;
|
||||
@@ -34,6 +35,7 @@ pub(crate) use self::constants::TRACING_DOMAIN_DOCUMENTS;
|
||||
pub(crate) use self::constants::TRACING_DOMAIN_ENVIRONMENT;
|
||||
pub(crate) use self::constants::TRACING_DOMAIN_FRONTEND;
|
||||
pub(crate) use self::constants::TRACING_DOMAIN_LOGGING_EDITOR;
|
||||
pub(crate) use self::constants::TRACING_DOMAIN_LOGGING_RUNTIME;
|
||||
pub(crate) use self::constants::TRACING_DOMAIN_PROFILES;
|
||||
pub(crate) use self::constants::TRACING_DOMAIN_SECRETS;
|
||||
pub(crate) use self::constants::TRACING_DOMAIN_WINDOWS;
|
||||
@@ -70,6 +72,7 @@ pub(crate) use self::frontend_logging::emit_frontend_log_event;
|
||||
pub(crate) use self::logging_editor::LoggingDocumentCandidateDto;
|
||||
pub(crate) use self::logging_editor::LoggingDocumentDto;
|
||||
pub(crate) use self::logging_editor::LoggingDocumentSaveResultDto;
|
||||
pub(crate) use self::logging_runtime::{LoggingRuntimeFileDto, LoggingRuntimeStatusDto};
|
||||
pub(crate) use self::profiles::ConfigProfileDetailDto;
|
||||
pub(crate) use self::profiles::ConfigProfileDocumentDto;
|
||||
pub(crate) use self::secrets::SecretRevealRequestDto;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// file: crates/ksp-app-config-desk/src/logging_editor.rs
|
||||
// version: 3
|
||||
// version: 4
|
||||
|
||||
//! Typed Logging document projection and validated persistence for the Config Desk Logging editor.
|
||||
|
||||
@@ -207,7 +207,7 @@ fn apply_persisted_runtime(state: &crate::AppState) -> ksp_core_lib::Result<(Str
|
||||
};
|
||||
let profile_id = resolved.profile_id().to_owned();
|
||||
let settings = resolved.into_settings();
|
||||
let generation = state.reinitialize_logging_runtime(profile_id.as_str(), &settings);
|
||||
let generation = state.reinitialize_logging_runtime(profile_id.as_str(), "default_profile", &settings);
|
||||
return match generation {
|
||||
std::result::Result::Ok(value) => std::result::Result::Ok((profile_id, value)),
|
||||
std::result::Result::Err(error) => std::result::Result::Err(error),
|
||||
|
||||
130
crates/ksp-app-config-desk/src/logging_runtime.rs
Normal file
130
crates/ksp-app-config-desk/src/logging_runtime.rs
Normal file
@@ -0,0 +1,130 @@
|
||||
// file: crates/ksp-app-config-desk/src/logging_runtime.rs
|
||||
// version: 1
|
||||
|
||||
//! 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<String>,
|
||||
/// 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<LoggingRuntimeFileDto>,
|
||||
}
|
||||
|
||||
/// Creates the stable runtime identity for this Config Desk process launch.
|
||||
pub(crate) fn launch_identity() -> ksp_core_lib::Result<ksp_logging_lib::LoggingRuntimeIdentity> {
|
||||
let now = time::OffsetDateTime::now_utc();
|
||||
let milliseconds = now.nanosecond() / 1_000_000;
|
||||
let timestamp = format!(
|
||||
"{:04}{:02}{:02}-{:02}{:02}{:02}.{:03}Z-p{}",
|
||||
now.year(),
|
||||
now.month() as u8,
|
||||
now.day(),
|
||||
now.hour(),
|
||||
now.minute(),
|
||||
now.second(),
|
||||
milliseconds,
|
||||
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<LoggingRuntimeStatusDto> {
|
||||
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<LoggingRuntimeStatusDto> {
|
||||
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;
|
||||
@@ -1,5 +1,5 @@
|
||||
// file: crates/ksp-app-config-desk/src/tauri.rs
|
||||
// version: 13
|
||||
// version: 14
|
||||
|
||||
//! Tauri runtime assembly for the KSP configuration desktop application.
|
||||
|
||||
@@ -49,6 +49,8 @@ fn configure_commands(builder: tauri::Builder<tauri::Wry>) -> tauri::Builder<tau
|
||||
remove_environment_value,
|
||||
reveal_environment_value,
|
||||
get_logging_document,
|
||||
get_logging_runtime_status,
|
||||
apply_logging_profile,
|
||||
save_logging_document,
|
||||
emit_frontend_log,
|
||||
splash_frontend_ready
|
||||
@@ -181,6 +183,27 @@ fn get_logging_document(state: tauri::State<'_, crate::AppState>) -> std::result
|
||||
};
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
fn get_logging_runtime_status(state: tauri::State<'_, crate::AppState>) -> std::result::Result<crate::LoggingRuntimeStatusDto, crate::CommandErrorDto> {
|
||||
let result = crate::logging_runtime::status(&state);
|
||||
return match result {
|
||||
std::result::Result::Ok(value) => std::result::Result::Ok(value),
|
||||
std::result::Result::Err(error) => std::result::Result::Err(crate::CommandErrorDto::from_error(&error)),
|
||||
};
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
fn apply_logging_profile(
|
||||
profile_id: String,
|
||||
state: tauri::State<'_, crate::AppState>,
|
||||
) -> std::result::Result<crate::LoggingRuntimeStatusDto, crate::CommandErrorDto> {
|
||||
let result = crate::logging_runtime::apply_profile(&state, profile_id.as_str());
|
||||
return match result {
|
||||
std::result::Result::Ok(value) => std::result::Result::Ok(value),
|
||||
std::result::Result::Err(error) => std::result::Result::Err(crate::CommandErrorDto::from_error(&error)),
|
||||
};
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
fn save_logging_document(
|
||||
candidate: crate::LoggingDocumentCandidateDto,
|
||||
|
||||
Reference in New Issue
Block a user