v0.1.2-pre.002
This commit is contained in:
233
crates/ksp-logging-lib/src/settings.rs
Normal file
233
crates/ksp-logging-lib/src/settings.rs
Normal file
@@ -0,0 +1,233 @@
|
||||
// file: crates/ksp-logging-lib/src/settings.rs
|
||||
// version: 1
|
||||
|
||||
/// Runtime filter level used by KSP logging settings.
|
||||
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
|
||||
pub enum LogFilterLevel {
|
||||
/// Disables matching logging events and spans.
|
||||
Off,
|
||||
/// Enables only error-level events and spans.
|
||||
Error,
|
||||
/// Enables warning and error events and spans.
|
||||
Warn,
|
||||
/// Enables informational, warning and error events and spans.
|
||||
Info,
|
||||
/// Enables debug and less verbose events and spans.
|
||||
Debug,
|
||||
/// Enables all KSP logging events and spans.
|
||||
Trace,
|
||||
}
|
||||
|
||||
/// Per-target filter override owned by Logging.
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
pub struct TargetFilter {
|
||||
target_prefix: std::string::String,
|
||||
level: crate::LogFilterLevel,
|
||||
}
|
||||
|
||||
impl TargetFilter {
|
||||
/// Creates a filter override for a KSP target prefix.
|
||||
#[must_use]
|
||||
pub fn new(target_prefix: impl std::convert::Into<std::string::String>, level: crate::LogFilterLevel) -> Self {
|
||||
return Self { target_prefix: target_prefix.into(), level };
|
||||
}
|
||||
|
||||
/// Returns the configured target prefix.
|
||||
#[must_use]
|
||||
pub fn target_prefix(&self) -> &str {
|
||||
return self.target_prefix.as_str();
|
||||
}
|
||||
|
||||
/// Returns the configured filter level.
|
||||
#[must_use]
|
||||
pub const fn level(&self) -> crate::LogFilterLevel {
|
||||
return self.level;
|
||||
}
|
||||
}
|
||||
|
||||
/// Lifecycle events emitted for spans by the formatted subscriber.
|
||||
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
|
||||
pub enum SpanEvents {
|
||||
/// Does not synthesize span lifecycle events.
|
||||
Off,
|
||||
/// Emits span creation and closure events for timing-oriented diagnostics.
|
||||
NewAndClose,
|
||||
/// Emits all supported span lifecycle events.
|
||||
Full,
|
||||
}
|
||||
|
||||
/// Console stream selected for human-readable logs.
|
||||
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
|
||||
pub enum ConsoleOutput {
|
||||
/// Writes console logs to standard output.
|
||||
Stdout,
|
||||
/// Writes console logs to standard error.
|
||||
Stderr,
|
||||
}
|
||||
|
||||
/// Runtime settings for the optional console output.
|
||||
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
|
||||
pub struct ConsoleSettings {
|
||||
output: crate::ConsoleOutput,
|
||||
}
|
||||
|
||||
impl ConsoleSettings {
|
||||
/// Creates console settings targeting standard output.
|
||||
#[must_use]
|
||||
pub const fn stdout() -> Self {
|
||||
return Self { output: crate::ConsoleOutput::Stdout };
|
||||
}
|
||||
|
||||
/// Creates console settings targeting standard error.
|
||||
#[must_use]
|
||||
pub const fn stderr() -> Self {
|
||||
return Self { output: crate::ConsoleOutput::Stderr };
|
||||
}
|
||||
|
||||
/// Returns the selected console stream.
|
||||
#[must_use]
|
||||
pub const fn output(&self) -> crate::ConsoleOutput {
|
||||
return self.output;
|
||||
}
|
||||
}
|
||||
|
||||
/// Rotation cadence for the optional file output.
|
||||
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
|
||||
pub enum FileRotation {
|
||||
/// Keeps a single non-rotating file.
|
||||
Never,
|
||||
/// Rotates the file every hour.
|
||||
Hourly,
|
||||
/// Rotates the file every day.
|
||||
Daily,
|
||||
}
|
||||
|
||||
/// Runtime settings for the optional file output.
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
pub struct FileSettings {
|
||||
directory: std::path::PathBuf,
|
||||
file_name_prefix: std::string::String,
|
||||
rotation: crate::FileRotation,
|
||||
}
|
||||
|
||||
impl FileSettings {
|
||||
/// Creates file output settings.
|
||||
#[must_use]
|
||||
pub fn new(
|
||||
directory: impl std::convert::Into<std::path::PathBuf>,
|
||||
file_name_prefix: impl std::convert::Into<std::string::String>,
|
||||
rotation: crate::FileRotation,
|
||||
) -> Self {
|
||||
return Self { directory: directory.into(), file_name_prefix: file_name_prefix.into(), rotation };
|
||||
}
|
||||
|
||||
/// Returns the directory containing log files.
|
||||
#[must_use]
|
||||
pub fn directory(&self) -> &std::path::Path {
|
||||
return self.directory.as_path();
|
||||
}
|
||||
|
||||
/// Returns the file-name prefix passed to the file appender.
|
||||
#[must_use]
|
||||
pub fn file_name_prefix(&self) -> &str {
|
||||
return self.file_name_prefix.as_str();
|
||||
}
|
||||
|
||||
/// Returns the selected file rotation cadence.
|
||||
#[must_use]
|
||||
pub const fn rotation(&self) -> crate::FileRotation {
|
||||
return self.rotation;
|
||||
}
|
||||
}
|
||||
|
||||
/// Complete runtime settings consumed by `ksp-logging-lib` initialization and reload.
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
pub struct LoggingSettings {
|
||||
default_filter: crate::LogFilterLevel,
|
||||
target_filters: std::vec::Vec<crate::TargetFilter>,
|
||||
span_events: crate::SpanEvents,
|
||||
console: std::option::Option<crate::ConsoleSettings>,
|
||||
file: std::option::Option<crate::FileSettings>,
|
||||
}
|
||||
|
||||
impl LoggingSettings {
|
||||
/// Creates explicit Logging settings without any target override.
|
||||
#[must_use]
|
||||
pub fn new(
|
||||
default_filter: crate::LogFilterLevel,
|
||||
span_events: crate::SpanEvents,
|
||||
console: std::option::Option<crate::ConsoleSettings>,
|
||||
file: std::option::Option<crate::FileSettings>,
|
||||
) -> Self {
|
||||
return Self { default_filter, target_filters: std::vec::Vec::new(), span_events, console, file };
|
||||
}
|
||||
|
||||
/// Adds one target-prefix override and returns the updated settings.
|
||||
#[must_use]
|
||||
pub fn with_target_filter(mut self, target_filter: crate::TargetFilter) -> Self {
|
||||
self.target_filters.push(target_filter);
|
||||
return self;
|
||||
}
|
||||
|
||||
/// Returns the default level applied to KSP-owned targets.
|
||||
#[must_use]
|
||||
pub const fn default_filter(&self) -> crate::LogFilterLevel {
|
||||
return self.default_filter;
|
||||
}
|
||||
|
||||
/// Returns target-prefix overrides in insertion order.
|
||||
#[must_use]
|
||||
pub fn target_filters(&self) -> &[crate::TargetFilter] {
|
||||
return self.target_filters.as_slice();
|
||||
}
|
||||
|
||||
/// Returns the selected span lifecycle event policy.
|
||||
#[must_use]
|
||||
pub const fn span_events(&self) -> crate::SpanEvents {
|
||||
return self.span_events;
|
||||
}
|
||||
|
||||
/// Returns console settings when console output is enabled.
|
||||
#[must_use]
|
||||
pub fn console(&self) -> std::option::Option<&crate::ConsoleSettings> {
|
||||
return self.console.as_ref();
|
||||
}
|
||||
|
||||
/// Returns file settings when file output is enabled.
|
||||
#[must_use]
|
||||
pub fn file(&self) -> std::option::Option<&crate::FileSettings> {
|
||||
return self.file.as_ref();
|
||||
}
|
||||
|
||||
/// Validates backend-independent invariants of the runtime settings.
|
||||
pub fn validate(&self) -> ksp_core_lib::Result<()> {
|
||||
for target_filter in &self.target_filters {
|
||||
if target_filter.target_prefix().is_empty() {
|
||||
return std::result::Result::Err(
|
||||
ksp_core_lib::Error::new(crate::ERROR_CODE_INVALID_SETTINGS, "target filter prefix must not be empty")
|
||||
.with_context("field", "target_filters.target_prefix"),
|
||||
);
|
||||
}
|
||||
if !target_filter.target_prefix().starts_with("ksp-") {
|
||||
return std::result::Result::Err(
|
||||
ksp_core_lib::Error::new(crate::ERROR_CODE_INVALID_SETTINGS, "target filter prefix must identify a KSP-owned target")
|
||||
.with_context("field", "target_filters.target_prefix")
|
||||
.with_context("target_prefix", target_filter.target_prefix()),
|
||||
);
|
||||
}
|
||||
}
|
||||
if let std::option::Option::Some(file) = self.file.as_ref() {
|
||||
if file.file_name_prefix().is_empty() {
|
||||
return std::result::Result::Err(
|
||||
ksp_core_lib::Error::new(crate::ERROR_CODE_INVALID_SETTINGS, "file name prefix must not be empty")
|
||||
.with_context("field", "file.file_name_prefix"),
|
||||
);
|
||||
}
|
||||
}
|
||||
return std::result::Result::Ok(());
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[path = "../unit_tests/settings.rs"]
|
||||
mod tests;
|
||||
Reference in New Issue
Block a user