Files
khadhroony-solana-project/crates/ksp-logging-lib/tests/runtime.rs

396 lines
19 KiB
Rust

// file: crates/ksp-logging-lib/tests/runtime.rs
// version: 10
//! Integration tests for global initialization, takeover filtering, non-blocking outputs and hot reload.
const EXTERNAL_TARGET: &str = "sqlx";
const JSON_KSP_TARGET: &str = "ksp-logging-json-test";
const LOGGING_TARGET: &str = "ksp-logging-lib";
const OTHER_KSP_TARGET: &str = "ksp-store-lib";
fn logging_trace_enabled() -> bool {
return tracing::enabled!(target: LOGGING_TARGET, tracing::Level::TRACE);
}
fn other_ksp_info_enabled() -> bool {
return tracing::enabled!(target: OTHER_KSP_TARGET, tracing::Level::INFO);
}
fn other_ksp_debug_enabled() -> bool {
return tracing::enabled!(target: OTHER_KSP_TARGET, tracing::Level::DEBUG);
}
fn external_error_enabled() -> bool {
return tracing::enabled!(target: EXTERNAL_TARGET, tracing::Level::ERROR);
}
fn test_root_directory() -> std::path::PathBuf {
return std::env::temp_dir().join(format!("ksp-logging-lib-runtime-{}", std::process::id()));
}
fn reset_directory(path: &std::path::Path) {
if path.exists() {
let remove_result = std::fs::remove_dir_all(path);
assert!(remove_result.is_ok());
}
}
fn read_directory_text(path: &std::path::Path) -> std::string::String {
let read_result = std::fs::read_dir(path);
let entries = match read_result {
std::result::Result::Ok(entries) => entries,
std::result::Result::Err(_) => return std::string::String::new(),
};
let mut output = std::string::String::new();
for entry_result in entries {
let entry = match entry_result {
std::result::Result::Ok(entry) => entry,
std::result::Result::Err(_) => continue,
};
let file_type = match entry.file_type() {
std::result::Result::Ok(file_type) => file_type,
std::result::Result::Err(_) => continue,
};
if !file_type.is_file() {
continue;
}
let content = match std::fs::read_to_string(entry.path()) {
std::result::Result::Ok(content) => content,
std::result::Result::Err(_) => continue,
};
output.push_str(content.as_str());
}
return output;
}
fn exercise_concurrent_reload(guard: &mut ksp_logging_lib::LoggingGuard, disabled: &ksp_logging_lib::LoggingSettings) {
let quiet_console = ksp_logging_lib::LoggingSettings::new(
ksp_logging_lib::LogFilterLevel::Off,
ksp_logging_lib::SpanEvents::Off,
std::option::Option::Some(ksp_logging_lib::ConsoleSettings::stderr()),
std::vec::Vec::new(),
);
let quiet_reload = ksp_logging_lib::reinitialize(guard, &quiet_console);
assert!(quiet_reload.is_ok());
let stop = std::sync::Arc::new(std::sync::atomic::AtomicBool::new(false));
let barrier = std::sync::Arc::new(std::sync::Barrier::new(5));
let mut threads = std::vec::Vec::new();
for worker_index in 0..4_u32 {
let worker_stop = std::sync::Arc::clone(&stop);
let worker_barrier = std::sync::Arc::clone(&barrier);
threads.push(std::thread::spawn(move || {
worker_barrier.wait();
let mut sequence = 0_u64;
while !worker_stop.load(std::sync::atomic::Ordering::Relaxed) {
ksp_logging_lib::trace!(target: LOGGING_TARGET, worker_index, sequence, "concurrent reload probe");
sequence = sequence.wrapping_add(1);
}
return;
}));
}
barrier.wait();
let mut reloads_succeeded = true;
for reload_index in 0..32_u32 {
let settings = if reload_index % 2 == 0 { &quiet_console } else { disabled };
let reload_result = ksp_logging_lib::reinitialize(guard, settings);
if reload_result.is_err() {
reloads_succeeded = false;
break;
}
}
stop.store(true, std::sync::atomic::Ordering::Relaxed);
let mut joins_succeeded = true;
for thread in threads {
if thread.join().is_err() {
joins_succeeded = false;
}
}
assert!(reloads_succeeded);
assert!(joins_succeeded);
}
#[test]
fn global_runtime_supports_takeover_non_blocking_outputs_hot_reload_and_single_initialization() {
let root = test_root_directory();
reset_directory(root.as_path());
let disabled = ksp_logging_lib::LoggingSettings::new(
ksp_logging_lib::LogFilterLevel::Info,
ksp_logging_lib::SpanEvents::Off,
std::option::Option::None,
std::vec::Vec::new(),
);
let identity = ksp_logging_lib::LoggingRuntimeIdentity::new("ksp-logging-runtime-test", "20260816-182519.123Z-p4242");
assert!(identity.is_ok());
let identity = match identity {
std::result::Result::Ok(value) => value,
std::result::Result::Err(_) => return,
};
let initialize_result = ksp_logging_lib::initialize_with_identity(&disabled, &identity);
assert!(initialize_result.is_ok());
let mut guard = match initialize_result {
std::result::Result::Ok(guard) => guard,
std::result::Result::Err(_) => return,
};
assert_eq!(guard.dropped_lines(), ksp_logging_lib::DroppedLines::zero());
assert!(!logging_trace_enabled());
assert!(!other_ksp_info_enabled());
assert!(!external_error_enabled());
let console_enabled = ksp_logging_lib::LoggingSettings::new(
ksp_logging_lib::LogFilterLevel::Info,
ksp_logging_lib::SpanEvents::NewAndClose,
std::option::Option::Some(ksp_logging_lib::ConsoleSettings::stderr()),
std::vec::Vec::new(),
)
.with_target_filter(ksp_logging_lib::TargetFilter::new(LOGGING_TARGET, ksp_logging_lib::LogFilterLevel::Trace));
let reload_result = ksp_logging_lib::reinitialize(&mut guard, &console_enabled);
assert!(reload_result.is_ok());
assert_eq!(guard.settings(), &console_enabled);
assert!(logging_trace_enabled());
assert!(other_ksp_info_enabled());
assert!(!other_ksp_debug_enabled());
assert!(!external_error_enabled());
let blocked_directory = root.join("not-a-directory");
let create_root = std::fs::create_dir_all(root.as_path());
assert!(create_root.is_ok());
let create_blocker = std::fs::write(blocked_directory.as_path(), b"file blocks directory creation");
assert!(create_blocker.is_ok());
let invalid_file = ksp_logging_lib::LoggingSettings::new(
ksp_logging_lib::LogFilterLevel::Error,
ksp_logging_lib::SpanEvents::Full,
std::option::Option::None,
std::vec![ksp_logging_lib::FileSettings::new(
"file.invalid",
true,
blocked_directory.as_path(),
"invalid",
ksp_logging_lib::FileRotation::Daily,
ksp_logging_lib::LogFormat::Human,
ksp_logging_lib::OutputFilter::unrestricted(),
)],
);
let failed_reload = ksp_logging_lib::reinitialize(&mut guard, &invalid_file);
assert!(failed_reload.is_err());
let file_error = match failed_reload {
std::result::Result::Ok(()) => return,
std::result::Result::Err(error) => error,
};
assert_eq!(file_error.code(), ksp_logging_lib::ERROR_CODE_FILE_OUTPUT_INITIALIZATION_FAILED);
assert_eq!(guard.settings(), &console_enabled);
assert!(logging_trace_enabled());
assert!(!external_error_enabled());
exercise_concurrent_reload(&mut guard, &disabled);
let human_directory = root.join("human");
let compact_directory = root.join("compact");
let pretty_directory = root.join("pretty");
let json_directory = root.join("json");
let files_enabled = ksp_logging_lib::LoggingSettings::new(
ksp_logging_lib::LogFilterLevel::Trace,
ksp_logging_lib::SpanEvents::Off,
std::option::Option::None,
std::vec![
ksp_logging_lib::FileSettings::new(
"file.human.logging",
true,
human_directory.as_path(),
"human.log",
ksp_logging_lib::FileRotation::Never,
ksp_logging_lib::LogFormat::Human,
ksp_logging_lib::OutputFilter::new(ksp_logging_lib::LogFilterLevel::Info, std::vec![LOGGING_TARGET.to_string()], std::vec!["*".to_string()],),
),
ksp_logging_lib::FileSettings::new(
"file.compact.store",
true,
compact_directory.as_path(),
"compact.log",
ksp_logging_lib::FileRotation::Never,
ksp_logging_lib::LogFormat::Compact,
ksp_logging_lib::OutputFilter::new(ksp_logging_lib::LogFilterLevel::Warn, std::vec![OTHER_KSP_TARGET.to_string()], std::vec!["*".to_string()],),
),
ksp_logging_lib::FileSettings::new(
"file.pretty.error",
true,
pretty_directory.as_path(),
"pretty.log",
ksp_logging_lib::FileRotation::Never,
ksp_logging_lib::LogFormat::Pretty,
ksp_logging_lib::OutputFilter::new(ksp_logging_lib::LogFilterLevel::Error, std::vec![LOGGING_TARGET.to_string()], std::vec!["*".to_string()],),
),
ksp_logging_lib::FileSettings::new(
"file.json.logging",
true,
json_directory.as_path(),
"runtime.jsonl",
ksp_logging_lib::FileRotation::Never,
ksp_logging_lib::LogFormat::Json,
ksp_logging_lib::OutputFilter::new(ksp_logging_lib::LogFilterLevel::Trace, std::vec![JSON_KSP_TARGET.to_string()], std::vec!["*".to_string()],),
),
],
);
let file_reload = ksp_logging_lib::reinitialize(&mut guard, &files_enabled);
assert!(file_reload.is_ok());
assert_eq!(guard.runtime_identity(), std::option::Option::Some(&identity));
let active_files = guard.active_file_outputs();
assert_eq!(active_files.len(), 4);
for file in &active_files {
assert!(file.file_name_prefix().starts_with("ksp-logging-runtime-test.20260816-182519.123Z-p4242."));
}
ksp_logging_lib::info!(target: LOGGING_TARGET, "logging info \x1b[31mmarker\x1b[0m");
ksp_logging_lib::error!(target: LOGGING_TARGET, "logging error marker");
ksp_logging_lib::info!(target: JSON_KSP_TARGET, "json info marker");
ksp_logging_lib::error!(target: JSON_KSP_TARGET, "json error marker");
ksp_logging_lib::warn!(target: OTHER_KSP_TARGET, "store warning marker");
ksp_logging_lib::info!(target: OTHER_KSP_TARGET, "store info must be filtered");
tracing::error!(target: EXTERNAL_TARGET, "external marker must remain silent");
let disable_after_file = ksp_logging_lib::reinitialize(&mut guard, &disabled);
assert!(disable_after_file.is_ok());
let human_text = read_directory_text(human_directory.as_path());
let compact_text = read_directory_text(compact_directory.as_path());
let pretty_text = read_directory_text(pretty_directory.as_path());
let json_text = read_directory_text(json_directory.as_path());
assert!(human_text.contains("logging info marker"));
assert!(human_text.contains("logging error marker"));
assert!(!human_text.contains("store warning marker"));
assert!(!human_text.contains("\x1b["));
assert!(compact_text.contains("store warning marker"));
assert!(!compact_text.contains("store info must be filtered"));
assert!(!compact_text.contains("logging info marker"));
assert!(pretty_text.contains("logging error marker"));
assert!(!pretty_text.contains("logging info marker"));
assert!(json_text.contains("json info marker"));
assert!(json_text.contains("json error marker"));
assert!(json_text.contains(JSON_KSP_TARGET));
assert!(!json_text.contains("store warning marker"));
assert!(!human_text.contains("external marker must remain silent"));
assert!(!compact_text.contains("external marker must remain silent"));
assert!(!pretty_text.contains("external marker must remain silent"));
assert!(!json_text.contains("external marker must remain silent"));
assert_eq!(guard.dropped_file_lines("file.human.logging"), std::option::Option::Some(0));
assert_eq!(guard.dropped_file_lines("file.compact.store"), std::option::Option::Some(0));
assert_eq!(guard.dropped_file_lines("file.pretty.error"), std::option::Option::Some(0));
assert_eq!(guard.dropped_file_lines("file.json.logging"), std::option::Option::Some(0));
assert_eq!(guard.dropped_file_lines("file.unknown"), std::option::Option::None);
let domain_logging_directory = root.join("domain-logging");
let domain_store_directory = root.join("domain-store");
let domain_any_directory = root.join("domain-any");
let domain_settings = ksp_logging_lib::LoggingSettings::new(
ksp_logging_lib::LogFilterLevel::Trace,
ksp_logging_lib::SpanEvents::Full,
std::option::Option::None,
std::vec![
ksp_logging_lib::FileSettings::new(
"file.domain.logging",
true,
domain_logging_directory.as_path(),
"logging.log",
ksp_logging_lib::FileRotation::Never,
ksp_logging_lib::LogFormat::Human,
ksp_logging_lib::OutputFilter::new(
ksp_logging_lib::LogFilterLevel::Trace,
std::vec![LOGGING_TARGET.to_string()],
std::vec!["logging".to_string()],
),
),
ksp_logging_lib::FileSettings::new(
"file.domain.store",
true,
domain_store_directory.as_path(),
"store.log",
ksp_logging_lib::FileRotation::Never,
ksp_logging_lib::LogFormat::Human,
ksp_logging_lib::OutputFilter::new(
ksp_logging_lib::LogFilterLevel::Trace,
std::vec![LOGGING_TARGET.to_string()],
std::vec!["store".to_string()],
),
),
ksp_logging_lib::FileSettings::new(
"file.domain.any",
true,
domain_any_directory.as_path(),
"any.log",
ksp_logging_lib::FileRotation::Never,
ksp_logging_lib::LogFormat::Human,
ksp_logging_lib::OutputFilter::new(ksp_logging_lib::LogFilterLevel::Trace, std::vec![LOGGING_TARGET.to_string()], std::vec!["*".to_string()],),
),
],
);
let domain_reload = ksp_logging_lib::reinitialize(&mut guard, &domain_settings);
assert!(domain_reload.is_ok());
ksp_logging_lib::info!(target: LOGGING_TARGET, domain = "logging.runtime", "direct logging domain marker");
ksp_logging_lib::info!(target: LOGGING_TARGET, domain = "store", "direct store domain marker");
ksp_logging_lib::info!(target: LOGGING_TARGET, "undomained marker");
let logging_lifecycle = ksp_logging_lib::info_span!(target: LOGGING_TARGET, "logging_lifecycle_span", domain = "logging");
logging_lifecycle.in_scope(|| {
return;
});
let store_lifecycle = ksp_logging_lib::info_span!(target: LOGGING_TARGET, "store_lifecycle_span", domain = "store");
store_lifecycle.in_scope(|| {
return;
});
let logging_parent = ksp_logging_lib::info_span!(target: LOGGING_TARGET, "logging_parent_span", domain = "logging");
logging_parent.in_scope(|| {
ksp_logging_lib::info!(target: LOGGING_TARGET, "inherited logging marker");
ksp_logging_lib::info!(target: LOGGING_TARGET, domain = "store", "event override store marker");
let inherited_child = ksp_logging_lib::info_span!(target: LOGGING_TARGET, "inherited_child_span");
inherited_child.in_scope(|| {
ksp_logging_lib::info!(target: LOGGING_TARGET, "child inherited logging marker");
});
let store_child = ksp_logging_lib::info_span!(target: LOGGING_TARGET, "store_child_span", domain = "store");
store_child.in_scope(|| {
ksp_logging_lib::info!(target: LOGGING_TARGET, "child explicit store marker");
});
});
let store_parent = ksp_logging_lib::info_span!(target: LOGGING_TARGET, "store_parent_span", domain = "store");
store_parent.in_scope(|| {
ksp_logging_lib::info!(target: LOGGING_TARGET, "inherited store marker");
});
let disable_after_domain = ksp_logging_lib::reinitialize(&mut guard, &disabled);
assert!(disable_after_domain.is_ok());
let domain_logging_text = read_directory_text(domain_logging_directory.as_path());
let domain_store_text = read_directory_text(domain_store_directory.as_path());
let domain_any_text = read_directory_text(domain_any_directory.as_path());
assert!(domain_logging_text.contains("direct logging domain marker"));
assert!(domain_logging_text.contains("inherited logging marker"));
assert!(domain_logging_text.contains("child inherited logging marker"));
assert!(domain_logging_text.contains("logging_lifecycle_span"));
assert!(!domain_logging_text.contains("direct store domain marker"));
assert!(!domain_logging_text.contains("event override store marker"));
assert!(!domain_logging_text.contains("child explicit store marker"));
assert!(!domain_logging_text.contains("inherited store marker"));
assert!(!domain_logging_text.contains("store_lifecycle_span"));
assert!(!domain_logging_text.contains("undomained marker"));
assert!(domain_store_text.contains("direct store domain marker"));
assert!(domain_store_text.contains("event override store marker"));
assert!(domain_store_text.contains("child explicit store marker"));
assert!(domain_store_text.contains("inherited store marker"));
assert!(domain_store_text.contains("store_lifecycle_span"));
assert!(!domain_store_text.contains("direct logging domain marker"));
assert!(!domain_store_text.contains("inherited logging marker"));
assert!(!domain_store_text.contains("child inherited logging marker"));
assert!(!domain_store_text.contains("logging_lifecycle_span"));
assert!(!domain_store_text.contains("undomained marker"));
assert!(domain_any_text.contains("direct logging domain marker"));
assert!(domain_any_text.contains("direct store domain marker"));
assert!(domain_any_text.contains("undomained marker"));
assert!(domain_any_text.contains("inherited logging marker"));
assert!(domain_any_text.contains("event override store marker"));
assert!(domain_any_text.contains("child inherited logging marker"));
assert!(domain_any_text.contains("child explicit store marker"));
assert!(domain_any_text.contains("inherited store marker"));
assert!(domain_any_text.contains("logging_lifecycle_span"));
assert!(domain_any_text.contains("store_lifecycle_span"));
assert_eq!(guard.dropped_file_lines("file.domain.logging"), std::option::Option::Some(0));
assert_eq!(guard.dropped_file_lines("file.domain.store"), std::option::Option::Some(0));
assert_eq!(guard.dropped_file_lines("file.domain.any"), std::option::Option::Some(0));
let dropped = guard.dropped_lines();
assert_eq!(dropped.total(), dropped.console().saturating_add(dropped.file()));
let second_initialize = ksp_logging_lib::initialize(&disabled);
assert!(second_initialize.is_err());
let error = match second_initialize {
std::result::Result::Ok(_) => return,
std::result::Result::Err(error) => error,
};
assert_eq!(error.code(), ksp_logging_lib::ERROR_CODE_ALREADY_INITIALIZED);
reset_directory(root.as_path());
}