v0.1.4-pre.016
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
// file: crates/ksp-logging-lib/src/runtime.rs
|
||||
// version: 11
|
||||
// version: 12
|
||||
|
||||
use tracing_subscriber::Layer; // rust-rules: trait-import
|
||||
use tracing_subscriber::layer::SubscriberExt; // rust-rules: trait-import
|
||||
@@ -41,10 +41,46 @@ impl DroppedLines {
|
||||
}
|
||||
}
|
||||
|
||||
/// Metadata for one active persistent Logging file output.
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
pub struct RuntimeFileMetadata {
|
||||
output_id: std::string::String,
|
||||
directory: std::path::PathBuf,
|
||||
file_name_prefix: std::string::String,
|
||||
rotation: crate::FileRotation,
|
||||
}
|
||||
|
||||
impl RuntimeFileMetadata {
|
||||
/// Returns the stable output identifier.
|
||||
#[must_use]
|
||||
pub fn output_id(&self) -> &str {
|
||||
return self.output_id.as_str();
|
||||
}
|
||||
|
||||
/// Returns the resolved directory containing this launch's files.
|
||||
#[must_use]
|
||||
pub fn directory(&self) -> &std::path::Path {
|
||||
return self.directory.as_path();
|
||||
}
|
||||
|
||||
/// Returns the effective launch-specific filename prefix passed to the rolling appender.
|
||||
#[must_use]
|
||||
pub fn file_name_prefix(&self) -> &str {
|
||||
return self.file_name_prefix.as_str();
|
||||
}
|
||||
|
||||
/// Returns the configured rotation cadence.
|
||||
#[must_use]
|
||||
pub const fn rotation(&self) -> crate::FileRotation {
|
||||
return self.rotation;
|
||||
}
|
||||
}
|
||||
|
||||
/// Guard owning the mutable runtime state and non-blocking writers of the installed KSP logging subscriber.
|
||||
pub struct LoggingGuard {
|
||||
reload_handle: RuntimeReloadHandle,
|
||||
settings: crate::LoggingSettings,
|
||||
runtime_identity: std::option::Option<crate::LoggingRuntimeIdentity>,
|
||||
outputs: RuntimeOutputs,
|
||||
retired_dropped_lines: crate::DroppedLines,
|
||||
retired_file_dropped_lines: std::collections::HashMap<std::string::String, usize>,
|
||||
@@ -57,6 +93,25 @@ impl LoggingGuard {
|
||||
return &self.settings;
|
||||
}
|
||||
|
||||
/// Returns the stable application/launch identity attached to this runtime, when one was supplied at initialization.
|
||||
#[must_use]
|
||||
pub const fn runtime_identity(&self) -> std::option::Option<&crate::LoggingRuntimeIdentity> {
|
||||
return self.runtime_identity.as_ref();
|
||||
}
|
||||
|
||||
/// Returns metadata for the currently active persistent file outputs.
|
||||
#[must_use]
|
||||
pub fn active_file_outputs(&self) -> std::vec::Vec<crate::RuntimeFileMetadata> {
|
||||
return self
|
||||
.outputs
|
||||
.files
|
||||
.iter()
|
||||
.map(|output| -> crate::RuntimeFileMetadata {
|
||||
return output.metadata.clone();
|
||||
})
|
||||
.collect();
|
||||
}
|
||||
|
||||
/// Returns cumulative dropped-line counters across active and previously reloaded outputs.
|
||||
#[must_use]
|
||||
pub fn dropped_lines(&self) -> crate::DroppedLines {
|
||||
@@ -110,7 +165,7 @@ impl RuntimeOutputs {
|
||||
.files
|
||||
.iter()
|
||||
.find(|output| -> bool {
|
||||
return output.output_id == output_id;
|
||||
return output.metadata.output_id == output_id;
|
||||
})
|
||||
.map(|output| -> usize {
|
||||
return output.output.dropped_lines();
|
||||
@@ -120,7 +175,7 @@ impl RuntimeOutputs {
|
||||
fn accumulate_file_dropped_lines(&self, destination: &mut std::collections::HashMap<std::string::String, usize>) {
|
||||
for output in &self.files {
|
||||
let dropped = output.output.dropped_lines();
|
||||
match destination.entry(output.output_id.clone()) {
|
||||
match destination.entry(output.metadata.output_id.clone()) {
|
||||
std::collections::hash_map::Entry::Occupied(mut entry) => {
|
||||
let cumulative = entry.get().saturating_add(dropped);
|
||||
*entry.get_mut() = cumulative;
|
||||
@@ -134,7 +189,7 @@ impl RuntimeOutputs {
|
||||
}
|
||||
|
||||
struct RuntimeFileOutput {
|
||||
output_id: std::string::String,
|
||||
metadata: crate::RuntimeFileMetadata,
|
||||
output: RuntimeOutput,
|
||||
}
|
||||
|
||||
@@ -155,7 +210,7 @@ struct PreparedOutput {
|
||||
}
|
||||
|
||||
struct PreparedFileOutput {
|
||||
output_id: std::string::String,
|
||||
metadata: crate::RuntimeFileMetadata,
|
||||
layer: BoxedRuntimeLayer,
|
||||
output: RuntimeOutput,
|
||||
}
|
||||
@@ -165,7 +220,19 @@ struct PreparedFileOutput {
|
||||
/// This function may succeed only once for the lifetime of the process. The returned guard owns all non-blocking writer guards and is then used by
|
||||
/// [`crate::reinitialize`] to replace the active KSP logging configuration without installing a second global subscriber.
|
||||
pub fn initialize(settings: &crate::LoggingSettings) -> ksp_core_lib::Result<crate::LoggingGuard> {
|
||||
return prepare_runtime(settings).and_then(|prepared| -> ksp_core_lib::Result<crate::LoggingGuard> {
|
||||
return initialize_runtime(settings, std::option::Option::None);
|
||||
}
|
||||
|
||||
/// Installs the global KSP tracing subscriber and isolates persistent file outputs with one stable application launch identity.
|
||||
pub fn initialize_with_identity(settings: &crate::LoggingSettings, identity: &crate::LoggingRuntimeIdentity) -> ksp_core_lib::Result<crate::LoggingGuard> {
|
||||
return initialize_runtime(settings, std::option::Option::Some(identity.clone()));
|
||||
}
|
||||
|
||||
fn initialize_runtime(
|
||||
settings: &crate::LoggingSettings,
|
||||
runtime_identity: std::option::Option<crate::LoggingRuntimeIdentity>,
|
||||
) -> ksp_core_lib::Result<crate::LoggingGuard> {
|
||||
return prepare_runtime_with_identity(settings, runtime_identity.as_ref()).and_then(|prepared| -> ksp_core_lib::Result<crate::LoggingGuard> {
|
||||
let PreparedRuntime { layers, outputs } = prepared;
|
||||
let (reload_layer, reload_handle) = tracing_subscriber::reload::Layer::new(layers);
|
||||
let subscriber = tracing_subscriber::registry().with(reload_layer);
|
||||
@@ -174,6 +241,7 @@ pub fn initialize(settings: &crate::LoggingSettings) -> ksp_core_lib::Result<cra
|
||||
std::result::Result::Ok(()) => std::result::Result::Ok(crate::LoggingGuard {
|
||||
reload_handle,
|
||||
settings: settings.clone(),
|
||||
runtime_identity,
|
||||
outputs,
|
||||
retired_dropped_lines: crate::DroppedLines::zero(),
|
||||
retired_file_dropped_lines: std::collections::HashMap::new(),
|
||||
@@ -191,7 +259,7 @@ pub fn initialize(settings: &crate::LoggingSettings) -> ksp_core_lib::Result<cra
|
||||
/// configuration remains unchanged. After a successful layer swap, dropped-line counters from the retired outputs are retained cumulatively. Retired
|
||||
/// layers are then dropped before their worker guards so all retired `NonBlocking` senders are released before shutdown asks the workers to drain/flush.
|
||||
pub fn reinitialize(guard: &mut crate::LoggingGuard, settings: &crate::LoggingSettings) -> ksp_core_lib::Result<()> {
|
||||
return prepare_runtime(settings).and_then(|prepared| -> ksp_core_lib::Result<()> {
|
||||
return prepare_runtime_with_identity(settings, guard.runtime_identity.as_ref()).and_then(|prepared| -> ksp_core_lib::Result<()> {
|
||||
let PreparedRuntime { layers, outputs } = prepared;
|
||||
let mut retired_layers = RuntimeLayers::new();
|
||||
let reload_result = guard.reload_handle.modify(|active_layers| {
|
||||
@@ -215,6 +283,13 @@ pub fn reinitialize(guard: &mut crate::LoggingGuard, settings: &crate::LoggingSe
|
||||
}
|
||||
|
||||
fn prepare_runtime(settings: &crate::LoggingSettings) -> ksp_core_lib::Result<PreparedRuntime> {
|
||||
return prepare_runtime_with_identity(settings, std::option::Option::None);
|
||||
}
|
||||
|
||||
fn prepare_runtime_with_identity(
|
||||
settings: &crate::LoggingSettings,
|
||||
runtime_identity: std::option::Option<&crate::LoggingRuntimeIdentity>,
|
||||
) -> ksp_core_lib::Result<PreparedRuntime> {
|
||||
let validation_error = settings.validate().err();
|
||||
if let std::option::Option::Some(error) = validation_error {
|
||||
return std::result::Result::Err(error);
|
||||
@@ -233,13 +308,13 @@ fn prepare_runtime(settings: &crate::LoggingSettings) -> ksp_core_lib::Result<Pr
|
||||
outputs.console = std::option::Option::Some(prepared_console.output);
|
||||
}
|
||||
for file in enabled_files {
|
||||
let prepared_file_result = build_file_output(file, settings);
|
||||
let prepared_file_result = build_file_output(file, settings, runtime_identity);
|
||||
let prepared_file = match prepared_file_result {
|
||||
std::result::Result::Ok(output) => output,
|
||||
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
||||
};
|
||||
output_layers.push(prepared_file.layer);
|
||||
outputs.files.push(RuntimeFileOutput { output_id: prepared_file.output_id, output: prepared_file.output });
|
||||
outputs.files.push(RuntimeFileOutput { metadata: prepared_file.metadata, output: prepared_file.output });
|
||||
}
|
||||
if output_layers.is_empty() {
|
||||
return std::result::Result::Ok(PreparedRuntime { layers: RuntimeLayers::new(), outputs });
|
||||
@@ -272,10 +347,18 @@ fn build_console_output(console: &crate::ConsoleSettings, settings: &crate::Logg
|
||||
};
|
||||
}
|
||||
|
||||
fn build_file_output(file: &crate::FileSettings, settings: &crate::LoggingSettings) -> ksp_core_lib::Result<PreparedFileOutput> {
|
||||
fn build_file_output(
|
||||
file: &crate::FileSettings,
|
||||
settings: &crate::LoggingSettings,
|
||||
runtime_identity: std::option::Option<&crate::LoggingRuntimeIdentity>,
|
||||
) -> ksp_core_lib::Result<PreparedFileOutput> {
|
||||
let file_name_prefix = match runtime_identity {
|
||||
std::option::Option::Some(identity) => identity.file_name_prefix(file.file_name_prefix()),
|
||||
std::option::Option::None => file.file_name_prefix().to_owned(),
|
||||
};
|
||||
let appender_result = tracing_appender::rolling::RollingFileAppender::builder()
|
||||
.rotation(map_file_rotation(file.rotation()))
|
||||
.filename_prefix(file.file_name_prefix())
|
||||
.filename_prefix(file_name_prefix.as_str())
|
||||
.build(file.directory());
|
||||
let appender = match appender_result {
|
||||
std::result::Result::Ok(appender) => appender,
|
||||
@@ -284,7 +367,7 @@ fn build_file_output(file: &crate::FileSettings, settings: &crate::LoggingSettin
|
||||
ksp_core_lib::Error::new(crate::ERROR_CODE_FILE_OUTPUT_INITIALIZATION_FAILED, "unable to initialize the KSP rolling file appender")
|
||||
.with_context("output_id", file.output_id())
|
||||
.with_context("directory", file.directory().display().to_string())
|
||||
.with_context("file_name_prefix", file.file_name_prefix())
|
||||
.with_context("file_name_prefix", file_name_prefix.as_str())
|
||||
.with_source(error),
|
||||
);
|
||||
},
|
||||
@@ -292,7 +375,13 @@ fn build_file_output(file: &crate::FileSettings, settings: &crate::LoggingSettin
|
||||
let stripped_writer = crate::writer::StripAnsiWriter::new(appender);
|
||||
let thread_name = format!("ksp-logging-{}", file.output_id());
|
||||
let prepared = build_non_blocking_output(stripped_writer, thread_name.as_str(), settings.span_events(), false, false, file.format(), file.filter());
|
||||
return std::result::Result::Ok(PreparedFileOutput { output_id: file.output_id().to_string(), layer: prepared.layer, output: prepared.output });
|
||||
let metadata = crate::RuntimeFileMetadata {
|
||||
output_id: file.output_id().to_owned(),
|
||||
directory: file.directory().to_path_buf(),
|
||||
file_name_prefix,
|
||||
rotation: file.rotation(),
|
||||
};
|
||||
return std::result::Result::Ok(PreparedFileOutput { metadata, layer: prepared.layer, output: prepared.output });
|
||||
}
|
||||
|
||||
fn build_non_blocking_output<W>(
|
||||
|
||||
Reference in New Issue
Block a user