v0.1.4-pre.014
This commit is contained in:
200
crates/ksp-app-config-desk/src/logging_editor.rs
Normal file
200
crates/ksp-app-config-desk/src/logging_editor.rs
Normal file
@@ -0,0 +1,200 @@
|
||||
// file: crates/ksp-app-config-desk/src/logging_editor.rs
|
||||
// version: 1
|
||||
|
||||
//! Read-only typed Logging document projection for the Config Desk Logging editor.
|
||||
|
||||
use ts_rs::TS; // rust-rules: derive-import
|
||||
|
||||
/// One Logging sink selector/filter exposed to the read-only editor.
|
||||
#[derive(Clone, Debug, serde::Serialize, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export, export_to = "../frontend/ts/bindings/ksp_app_config_desk/logging/LoggingOutputFilterDto.ts")]
|
||||
pub(crate) struct LoggingOutputFilterDto {
|
||||
/// Filter level source text.
|
||||
pub(crate) level: String,
|
||||
/// Target selectors in source order.
|
||||
pub(crate) targets: std::vec::Vec<String>,
|
||||
/// Structured domain selectors in source order.
|
||||
pub(crate) domains: std::vec::Vec<String>,
|
||||
}
|
||||
|
||||
/// Console sink configuration exposed to the read-only editor.
|
||||
#[derive(Clone, Debug, serde::Serialize, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export, export_to = "../frontend/ts/bindings/ksp_app_config_desk/logging/LoggingConsoleDto.ts")]
|
||||
pub(crate) struct LoggingConsoleDto {
|
||||
/// Whether the console sink is enabled.
|
||||
pub(crate) enabled: bool,
|
||||
/// `stdout` or `stderr` source text.
|
||||
pub(crate) output: String,
|
||||
/// Whether ANSI output is requested.
|
||||
pub(crate) ansi: bool,
|
||||
/// Console format source text.
|
||||
pub(crate) format: String,
|
||||
/// Sink-local selectors.
|
||||
pub(crate) filter: LoggingOutputFilterDto,
|
||||
}
|
||||
|
||||
/// One persistent file sink exposed to the read-only editor.
|
||||
#[derive(Clone, Debug, serde::Serialize, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export, export_to = "../frontend/ts/bindings/ksp_app_config_desk/logging/LoggingFileDto.ts")]
|
||||
pub(crate) struct LoggingFileDto {
|
||||
/// Stable sink identifier.
|
||||
pub(crate) output_id: String,
|
||||
/// Whether the file sink is enabled.
|
||||
pub(crate) enabled: bool,
|
||||
/// Source path relative to the Logging root.
|
||||
pub(crate) path: String,
|
||||
/// Rotation source text.
|
||||
pub(crate) rotation: String,
|
||||
/// File format source text.
|
||||
pub(crate) format: String,
|
||||
/// Whether ANSI output is requested.
|
||||
pub(crate) ansi: bool,
|
||||
/// Sink-local selectors.
|
||||
pub(crate) filter: LoggingOutputFilterDto,
|
||||
}
|
||||
|
||||
/// One global Logging target override exposed to the read-only editor.
|
||||
#[derive(Clone, Debug, serde::Serialize, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export, export_to = "../frontend/ts/bindings/ksp_app_config_desk/logging/LoggingTargetFilterDto.ts")]
|
||||
pub(crate) struct LoggingTargetFilterDto {
|
||||
/// KSP target prefix.
|
||||
pub(crate) target_prefix: String,
|
||||
/// Override level source text.
|
||||
pub(crate) level: String,
|
||||
}
|
||||
|
||||
/// One typed Logging profile exposed to the read-only editor.
|
||||
#[derive(Clone, Debug, serde::Serialize, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export, export_to = "../frontend/ts/bindings/ksp_app_config_desk/logging/LoggingProfileDto.ts")]
|
||||
pub(crate) struct LoggingProfileDto {
|
||||
/// Stable profile identifier.
|
||||
pub(crate) profile_id: String,
|
||||
/// Profile-level default filter source text.
|
||||
pub(crate) default_filter: String,
|
||||
/// Span lifecycle source text.
|
||||
pub(crate) span_events: String,
|
||||
/// Console sink configuration.
|
||||
pub(crate) console: LoggingConsoleDto,
|
||||
/// Persistent file sinks in source order.
|
||||
pub(crate) files: std::vec::Vec<LoggingFileDto>,
|
||||
/// Global target overrides in source order.
|
||||
pub(crate) target_filters: std::vec::Vec<LoggingTargetFilterDto>,
|
||||
}
|
||||
|
||||
/// Complete typed Logging document exposed to the read-only editor.
|
||||
#[derive(Clone, Debug, serde::Serialize, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export, export_to = "../frontend/ts/bindings/ksp_app_config_desk/logging/LoggingDocumentDto.ts")]
|
||||
pub(crate) struct LoggingDocumentDto {
|
||||
/// Stable Config file identifier.
|
||||
pub(crate) file_id: String,
|
||||
/// Physical path resolved by Config.
|
||||
pub(crate) path: String,
|
||||
/// Source format version.
|
||||
pub(crate) format_version: u32,
|
||||
/// Source Logging root expression/path.
|
||||
pub(crate) logs_directory: String,
|
||||
/// Autonomous default profile identifier.
|
||||
pub(crate) default_profile: String,
|
||||
/// Typed profiles in source order.
|
||||
pub(crate) profiles: std::vec::Vec<LoggingProfileDto>,
|
||||
}
|
||||
|
||||
/// Loads the typed Logging source through ConfigManagement and projects it for the frontend.
|
||||
pub(crate) fn document(state: &crate::AppState) -> ksp_core_lib::Result<LoggingDocumentDto> {
|
||||
return document_from_management(state.config_management());
|
||||
}
|
||||
|
||||
fn document_from_management(management: &ksp_config_lib::ConfigManagement) -> ksp_core_lib::Result<LoggingDocumentDto> {
|
||||
let source = management.load_logging_document();
|
||||
let source = match source {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
||||
};
|
||||
let file_id = ksp_config_lib::ConfigFileId::new(ksp_config_lib::FILE_ID_STD_LOGGING);
|
||||
let file_id = match file_id {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
||||
};
|
||||
let path = management.engine().registry().resolve_path(management.engine().bootstrap(), &file_id);
|
||||
let path = match path {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
||||
};
|
||||
let mut profiles = std::vec::Vec::<LoggingProfileDto>::with_capacity(source.profiles().len());
|
||||
let mut file_count = 0usize;
|
||||
let mut target_filter_count = 0usize;
|
||||
for profile in source.profiles() {
|
||||
file_count += profile.files().len();
|
||||
target_filter_count += profile.target_filters().len();
|
||||
profiles.push(project_profile(profile));
|
||||
}
|
||||
let result = LoggingDocumentDto {
|
||||
file_id: file_id.as_str().to_owned(),
|
||||
path: path.display().to_string(),
|
||||
format_version: source.format_version(),
|
||||
logs_directory: source.logs_directory().to_owned(),
|
||||
default_profile: source.default_profile().to_owned(),
|
||||
profiles,
|
||||
};
|
||||
ksp_logging_lib::debug!(
|
||||
target: crate::TRACING_TARGET,
|
||||
domain = crate::TRACING_DOMAIN_LOGGING_EDITOR,
|
||||
file_id = result.file_id.as_str(),
|
||||
profile_count = result.profiles.len(),
|
||||
file_count,
|
||||
target_filter_count,
|
||||
"typed Logging document projected for read-only editor"
|
||||
);
|
||||
return std::result::Result::Ok(result);
|
||||
}
|
||||
|
||||
fn project_profile(profile: &ksp_config_lib::LoggingProfileConfig) -> LoggingProfileDto {
|
||||
let mut files = std::vec::Vec::<LoggingFileDto>::with_capacity(profile.files().len());
|
||||
for file in profile.files() {
|
||||
files.push(LoggingFileDto {
|
||||
output_id: file.output_id().to_owned(),
|
||||
enabled: file.enabled(),
|
||||
path: file.path().to_owned(),
|
||||
rotation: file.rotation().to_owned(),
|
||||
format: file.format().to_owned(),
|
||||
ansi: file.ansi(),
|
||||
filter: project_output_filter(file.filter()),
|
||||
});
|
||||
}
|
||||
let mut target_filters = std::vec::Vec::<LoggingTargetFilterDto>::with_capacity(profile.target_filters().len());
|
||||
for target_filter in profile.target_filters() {
|
||||
target_filters.push(LoggingTargetFilterDto { target_prefix: target_filter.target_prefix().to_owned(), level: target_filter.level().to_owned() });
|
||||
}
|
||||
return LoggingProfileDto {
|
||||
profile_id: profile.profile_id().to_owned(),
|
||||
default_filter: profile.default_filter().to_owned(),
|
||||
span_events: profile.span_events().to_owned(),
|
||||
console: LoggingConsoleDto {
|
||||
enabled: profile.console().enabled(),
|
||||
output: profile.console().output().to_owned(),
|
||||
ansi: profile.console().ansi(),
|
||||
format: profile.console().format().to_owned(),
|
||||
filter: project_output_filter(profile.console().filter()),
|
||||
},
|
||||
files,
|
||||
target_filters,
|
||||
};
|
||||
}
|
||||
|
||||
fn project_output_filter(filter: &ksp_config_lib::LoggingOutputFilterConfig) -> LoggingOutputFilterDto {
|
||||
return LoggingOutputFilterDto {
|
||||
level: filter.level().to_owned(),
|
||||
targets: filter.targets().to_vec(),
|
||||
domains: filter.domains().to_vec(),
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[path = "../unit_tests/logging_editor.rs"]
|
||||
mod tests;
|
||||
Reference in New Issue
Block a user