Skip to content

Commit 3096b3f

Browse files
authored
Test suite for directory logging functionality (#536)
1 parent 54aef80 commit 3096b3f

File tree

7 files changed

+464
-5
lines changed

7 files changed

+464
-5
lines changed

.vscode/settings.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
{
22
"[rust]": {
33
"editor.defaultFormatter": "rust-lang.rust-analyzer"
4-
}
5-
}
4+
},
5+
"rust-analyzer.rustc.source": null
6+
}

Cargo.lock

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

xet_logging/Cargo.toml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,3 +26,12 @@ console-subscriber = { version = "0.4.1", optional = true }
2626
[features]
2727
default = []
2828
tokio-console = ["dep:console-subscriber"]
29+
30+
[[bin]]
31+
name = "log_test_executable"
32+
path = "tests/bin/log_test_executable.rs"
33+
34+
[dev-dependencies]
35+
tempfile = "3.0"
36+
tokio = { version = "1.0", features = ["rt", "time"] }
37+
rand = { workspace = true }

xet_logging/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,4 @@ mod constants;
33
mod logging;
44

55
pub use config::{LogDirConfig, LoggingConfig, LoggingMode};
6-
pub use logging::init;
6+
pub use logging::{init, wait_for_log_directory_cleanup};

xet_logging/src/logging.rs

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
use std::ffi::OsStr;
22
use std::io;
33
use std::path::{Path, PathBuf};
4-
use std::sync::OnceLock;
4+
use std::sync::{Mutex, OnceLock};
5+
use std::thread::JoinHandle;
56
use std::time::Duration;
67

78
use chrono::{DateTime, FixedOffset, Local, Utc};
@@ -17,6 +18,19 @@ use utils::ByteSize;
1718
use crate::config::*;
1819
use crate::constants::{DEFAULT_LOG_LEVEL_CONSOLE, DEFAULT_LOG_LEVEL_FILE};
1920

21+
/// Global variable to hold the JoinHandle for the log cleanup thread
22+
static LOG_CLEANUP_HANDLE: Mutex<Option<JoinHandle<()>>> = Mutex::new(None);
23+
24+
/// Wait for the log directory cleanup to complete.
25+
/// This function blocks until the background cleanup thread finishes.
26+
pub fn wait_for_log_directory_cleanup() {
27+
if let Ok(mut handle_opt) = LOG_CLEANUP_HANDLE.lock()
28+
&& let Some(handle) = handle_opt.take()
29+
{
30+
let _ = handle.join();
31+
}
32+
}
33+
2034
/// The main entry point to set up logging. Should only be called once.
2135
pub fn init(cfg: LoggingConfig) {
2236
let mut dir_cleanup_task = None;
@@ -112,6 +126,7 @@ fn init_logging_to_file(path: &Path, use_json: bool) -> Result<(), std::io::Erro
112126
let _ = FILE_GUARD.set(guard); // ignore error if already initialised
113127

114128
let registry = tracing_subscriber::registry();
129+
115130
#[cfg(feature = "tokio-console")]
116131
let registry = {
117132
// Console subscriber layer for tokio-console, custom filter for tokio trace level events
@@ -189,11 +204,17 @@ struct CandidateLogFile {
189204
fn run_log_directory_cleanup_background(cfg: LogDirConfig, log_dir: &Path) {
190205
// Spawn run_log_directory_cleanup as background thread, logging any errors as a warn!
191206
let log_dir = log_dir.to_path_buf();
192-
std::thread::spawn(move || {
207+
let handle = std::thread::spawn(move || {
193208
if let Err(e) = run_log_directory_cleanup(cfg, &log_dir) {
194209
warn!("Error during log directory cleanup in {:?}: {}", log_dir, e);
195210
}
196211
});
212+
213+
// Store the JoinHandle in the global variable
214+
if let Ok(mut handle_opt) = LOG_CLEANUP_HANDLE.lock() {
215+
debug_assert!(handle_opt.is_none(), "Log directory cleanup called multiple times.");
216+
*handle_opt = Some(handle);
217+
}
197218
}
198219

199220
fn run_log_directory_cleanup(cfg: LogDirConfig, log_dir: &Path) -> io::Result<()> {
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
use std::env;
2+
use std::time::Duration;
3+
4+
use tracing::info;
5+
use xet_logging::{LoggingConfig, LoggingMode};
6+
7+
fn main() {
8+
let args: Vec<String> = env::args().collect();
9+
if args.len() != 3 {
10+
eprintln!("Usage: {} <log_directory> <num_lines>", args[0]);
11+
std::process::exit(1);
12+
}
13+
14+
let log_directory = &args[1];
15+
let num_lines: usize = args[2].parse().expect("num_lines must be a number");
16+
17+
// Initialize logging to the specified directory
18+
let config = LoggingConfig {
19+
logging_mode: LoggingMode::Directory(log_directory.into()),
20+
use_json: true,
21+
enable_log_dir_cleanup: true,
22+
version: "test".to_string(),
23+
log_dir_config: xet_logging::LogDirConfig::default(),
24+
};
25+
26+
xet_logging::init(config);
27+
28+
// Generate log messages with 5ms delay between each
29+
for i in 0..num_lines {
30+
info!("Test log message number {} - this is a dummy log message for testing purposes", i + 1);
31+
32+
// Wait for 50 microseconds between each log message just to spread it out a little...
33+
std::thread::sleep(Duration::from_micros(50));
34+
}
35+
36+
// Wait for background cleanup to complete before exiting
37+
xet_logging::wait_for_log_directory_cleanup();
38+
}

0 commit comments

Comments
 (0)