diff --git a/src/lib.rs b/src/lib.rs index da9d553..426e0d1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -327,7 +327,6 @@ fn handle_routine_load_loop(config: &Config, tools: &[Box]) -> Result< } } -/// 执行 Routine Load 工具的辅助函数 fn execute_routine_load_tool( config: &Config, tools: &[Box], diff --git a/src/tools/common/fs_utils.rs b/src/tools/common/fs_utils.rs index 5af975f..85f3c0d 100644 --- a/src/tools/common/fs_utils.rs +++ b/src/tools/common/fs_utils.rs @@ -1,6 +1,6 @@ use crate::error::Result; use std::fs; -use std::path::Path; +use std::path::{Path, PathBuf}; /// A generic utility to serialize a struct to a TOML file. pub fn save_toml_to_file(obj: &T, file_path: &Path) -> Result<()> { @@ -42,3 +42,56 @@ pub fn read_file_content(path: &Path) -> Result { fs::read_to_string(path) .map_err(|e| crate::error::CliError::ConfigError(format!("Failed to read file: {e}"))) } + +pub fn collect_log_files(dir: &Path, log_prefix: &str) -> Result> { + if !dir.exists() { + return Err(crate::error::CliError::ConfigError(format!( + "Log directory does not exist: {}", + dir.display() + ))); + } + + if !dir.is_dir() { + return Err(crate::error::CliError::ConfigError(format!( + "Path is not a directory: {}", + dir.display() + ))); + } + + let mut files: Vec = fs::read_dir(dir) + .map_err(crate::error::CliError::IoError)? + .filter_map(|e| e.ok()) + .map(|e| e.path()) + .filter(|p| { + let name = p.file_name().and_then(|n| n.to_str()).unwrap_or(""); + // Only accept log files with the specified prefix and exclude compressed archives + name.starts_with(log_prefix) + && !name.ends_with(".gz") + && !name.ends_with(".zip") + && !name.ends_with(".tar") + && !name.ends_with(".tar.gz") + }) + .collect(); + + if files.is_empty() { + return Err(crate::error::CliError::ConfigError(format!( + "No {} files found in directory: {}", + log_prefix, + dir.display() + ))); + } + + // Sort by modification time (newest first) + files.sort_by_key(|p| fs::metadata(p).and_then(|m| m.modified()).ok()); + files.reverse(); + + Ok(files) +} + +pub fn collect_fe_logs(dir: &Path) -> Result> { + collect_log_files(dir, "fe.log") +} + +pub fn collect_be_logs(dir: &Path) -> Result> { + collect_log_files(dir, "be.INFO") +} diff --git a/src/tools/fe/routine_load/log_parser.rs b/src/tools/fe/routine_load/log_parser.rs index 6bf30d3..60cee38 100644 --- a/src/tools/fe/routine_load/log_parser.rs +++ b/src/tools/fe/routine_load/log_parser.rs @@ -3,7 +3,7 @@ use chrono::NaiveDateTime; use regex::Regex; use std::fs; use std::io::{BufRead, BufReader}; -use std::path::{Path, PathBuf}; +use std::path::Path; #[derive(Debug, Clone, Default)] pub struct LogCommitEntry { @@ -66,47 +66,6 @@ impl FeLogParser { } } -pub fn collect_fe_logs(dir: &Path) -> Result> { - if !dir.exists() { - return Err(CliError::ConfigError(format!( - "Log directory does not exist: {}", - dir.display() - ))); - } - - if !dir.is_dir() { - return Err(CliError::ConfigError(format!( - "Path is not a directory: {}", - dir.display() - ))); - } - - let mut files: Vec = fs::read_dir(dir) - .map_err(CliError::IoError)? - .filter_map(|e| e.ok()) - .map(|e| e.path()) - .filter(|p| { - p.file_name() - .and_then(|n| n.to_str()) - .map(|s| s.starts_with("fe.log")) - .unwrap_or(false) - }) - .collect(); - - if files.is_empty() { - return Err(CliError::ConfigError(format!( - "No fe.log files found in directory: {}", - dir.display() - ))); - } - - // Sort by modification time (newest first) - files.sort_by_key(|p| fs::metadata(p).and_then(|m| m.modified()).ok()); - files.reverse(); - - Ok(files) -} - pub fn scan_file( parser: &FeLogParser, path: &Path, diff --git a/src/tools/fe/routine_load/performance_analyzer.rs b/src/tools/fe/routine_load/performance_analyzer.rs index a0c95be..615b3f0 100644 --- a/src/tools/fe/routine_load/performance_analyzer.rs +++ b/src/tools/fe/routine_load/performance_analyzer.rs @@ -1,13 +1,15 @@ +use chrono::Duration; +use std::collections::HashMap; + use super::job_manager::RoutineLoadJobManager; -use super::log_parser::{FeLogParser, LogCommitEntry, collect_fe_logs, scan_file}; +use super::log_parser::{FeLogParser, LogCommitEntry, scan_file}; use crate::config::Config; use crate::error::{CliError, Result}; +use crate::tools::common::fs_utils; use crate::tools::fe::routine_load::messages as ErrMsg; use crate::tools::{ExecutionResult, Tool}; use crate::ui; use crate::ui::{FormatHelper, InputHelper}; -use chrono::Duration; -use std::collections::HashMap; pub struct RoutineLoadPerformanceAnalyzer; @@ -65,7 +67,7 @@ impl RoutineLoadPerformanceAnalyzer { log_dir: &std::path::Path, job_id: &str, ) -> Result> { - let files = collect_fe_logs(log_dir)?; + let files = fs_utils::collect_fe_logs(log_dir)?; let parser = FeLogParser::new(); let mut entries: Vec = Vec::new(); diff --git a/src/tools/fe/routine_load/traffic_monitor.rs b/src/tools/fe/routine_load/traffic_monitor.rs index bfd7bf8..f57efaa 100644 --- a/src/tools/fe/routine_load/traffic_monitor.rs +++ b/src/tools/fe/routine_load/traffic_monitor.rs @@ -1,13 +1,15 @@ +use chrono::Duration; +use std::collections::BTreeMap; + use super::job_manager::RoutineLoadJobManager; -use super::log_parser::{FeLogParser, LogCommitEntry, collect_fe_logs, scan_file}; +use super::log_parser::{FeLogParser, LogCommitEntry, scan_file}; use crate::config::Config; use crate::error::{CliError, Result}; +use crate::tools::common::fs_utils; use crate::tools::fe::routine_load::messages as ErrMsg; use crate::tools::{ExecutionResult, Tool}; use crate::ui; use crate::ui::InputHelper; -use chrono::Duration; -use std::collections::BTreeMap; pub struct RoutineLoadTrafficMonitor; @@ -72,7 +74,7 @@ impl RoutineLoadTrafficMonitor { log_dir: &std::path::Path, job_id: &str, ) -> Result> { - let files = collect_fe_logs(log_dir)?; + let files = fs_utils::collect_fe_logs(log_dir)?; let parser = FeLogParser::new(); let mut entries: Vec = Vec::new(); diff --git a/src/ui/menu.rs b/src/ui/menu.rs index fb649e7..56f5aca 100644 --- a/src/ui/menu.rs +++ b/src/ui/menu.rs @@ -194,7 +194,7 @@ pub fn show_fe_tools_menu() -> Result { MenuOption { action: FeToolAction::RoutineLoad, key: "[5]".to_string(), - name: "Routine Load".to_string(), + name: "routine-load".to_string(), description: "Routine Load management tools".to_string(), }, MenuOption {