From a88082aa40c99a1d59082b396210e3f2e39f68df Mon Sep 17 00:00:00 2001 From: Jose Celano Date: Fri, 14 Jun 2024 16:22:43 +0100 Subject: [PATCH 1/3] fix: [#893] enable color in logs --- src/bootstrap/logging.rs | 2 +- src/console/ci/e2e/logs_parser.rs | 57 +++++++++++++++++++++++++----- src/console/ci/e2e/runner.rs | 2 +- src/console/clients/checker/app.rs | 2 +- src/console/clients/udp/app.rs | 2 +- 5 files changed, 52 insertions(+), 13 deletions(-) diff --git a/src/bootstrap/logging.rs b/src/bootstrap/logging.rs index 5194f06ea..14756565f 100644 --- a/src/bootstrap/logging.rs +++ b/src/bootstrap/logging.rs @@ -46,7 +46,7 @@ fn config_level_or_default(log_level: &Option) -> LevelFilter { } fn tracing_stdout_init(filter: LevelFilter, style: &TraceStyle) { - let builder = tracing_subscriber::fmt().with_max_level(filter).with_ansi(false); + let builder = tracing_subscriber::fmt().with_max_level(filter).with_ansi(true); let () = match style { TraceStyle::Default => builder.init(), diff --git a/src/console/ci/e2e/logs_parser.rs b/src/console/ci/e2e/logs_parser.rs index 2a1876a11..ff4028f80 100644 --- a/src/console/ci/e2e/logs_parser.rs +++ b/src/console/ci/e2e/logs_parser.rs @@ -1,9 +1,16 @@ //! Utilities to parse Torrust Tracker logs. use serde::{Deserialize, Serialize}; -const UDP_TRACKER_PATTERN: &str = "UDP TRACKER: Started on: udp://"; -const HTTP_TRACKER_PATTERN: &str = "HTTP TRACKER: Started on: "; -const HEALTH_CHECK_PATTERN: &str = "HEALTH CHECK API: Started on: "; +const INFO_LOG_LEVEL: &str = "INFO"; + +const UDP_TRACKER_TARGET: &str = "UDP TRACKER"; +const UDP_TRACKER_SOCKET_ADDR_START_PATTERN: &str = "Started on: udp://"; + +const HTTP_TRACKER_TARGET: &str = "HTTP TRACKER"; +const HTTP_TRACKER_URL_START_PATTERN: &str = "Started on: "; + +const HEALTH_CHECK_TARGET: &str = "HEALTH CHECK API"; +const HEALTH_CHECK_URL_START_PATTERN: &str = "Started on: "; #[derive(Serialize, Deserialize, Debug, Default)] pub struct RunningServices { @@ -59,11 +66,11 @@ impl RunningServices { let mut health_checks: Vec = Vec::new(); for line in logs.lines() { - if let Some(address) = Self::extract_address_if_matches(line, UDP_TRACKER_PATTERN) { + if let Some(address) = Self::extract_udp_tracker_url(line) { udp_trackers.push(address); - } else if let Some(address) = Self::extract_address_if_matches(line, HTTP_TRACKER_PATTERN) { + } else if let Some(address) = Self::extract_http_tracker_url(line) { http_trackers.push(address); - } else if let Some(address) = Self::extract_address_if_matches(line, HEALTH_CHECK_PATTERN) { + } else if let Some(address) = Self::extract_health_check_api_url(line) { health_checks.push(format!("{address}/health_check")); } } @@ -75,9 +82,32 @@ impl RunningServices { } } - fn extract_address_if_matches(line: &str, pattern: &str) -> Option { - line.find(pattern) - .map(|start| Self::replace_wildcard_ip_with_localhost(line[start + pattern.len()..].trim())) + fn extract_udp_tracker_url(line: &str) -> Option { + if !line.contains(INFO_LOG_LEVEL) || !line.contains(UDP_TRACKER_TARGET) { + return None; + }; + + line.find(UDP_TRACKER_SOCKET_ADDR_START_PATTERN).map(|start| { + Self::replace_wildcard_ip_with_localhost(line[start + UDP_TRACKER_SOCKET_ADDR_START_PATTERN.len()..].trim()) + }) + } + + fn extract_http_tracker_url(line: &str) -> Option { + if !line.contains(INFO_LOG_LEVEL) || !line.contains(HTTP_TRACKER_TARGET) { + return None; + }; + + line.find(HTTP_TRACKER_URL_START_PATTERN) + .map(|start| Self::replace_wildcard_ip_with_localhost(line[start + HTTP_TRACKER_URL_START_PATTERN.len()..].trim())) + } + + fn extract_health_check_api_url(line: &str) -> Option { + if !line.contains(INFO_LOG_LEVEL) || !line.contains(HEALTH_CHECK_TARGET) { + return None; + }; + + line.find(HEALTH_CHECK_URL_START_PATTERN) + .map(|start| Self::replace_wildcard_ip_with_localhost(line[start + HEALTH_CHECK_URL_START_PATTERN.len()..].trim())) } fn replace_wildcard_ip_with_localhost(address: &str) -> String { @@ -127,6 +157,15 @@ mod tests { assert_eq!(running_services.health_checks, vec!["http://127.0.0.1:1313/health_check"]); } + #[test] + fn it_should_support_colored_output() { + let logs = "\x1b[2m2024-06-14T14:40:13.028824Z\x1b[0m \x1b[33mINFO\x1b[0m \x1b[2mUDP TRACKER\x1b[0m: \x1b[37mStarted on: udp://0.0.0.0:6969\x1b[0m"; + + let running_services = RunningServices::parse_from_logs(logs); + + assert_eq!(running_services.udp_trackers, vec!["127.0.0.1:6969"]); + } + #[test] fn it_should_ignore_logs_with_no_matching_lines() { let logs = "[Other Service][INFO] Started on: 0.0.0.0:7070"; diff --git a/src/console/ci/e2e/runner.rs b/src/console/ci/e2e/runner.rs index a80b65ce2..a3d61894e 100644 --- a/src/console/ci/e2e/runner.rs +++ b/src/console/ci/e2e/runner.rs @@ -116,7 +116,7 @@ pub fn run() -> anyhow::Result<()> { } fn tracing_stdout_init(filter: LevelFilter) { - tracing_subscriber::fmt().with_max_level(filter).with_ansi(false).init(); + tracing_subscriber::fmt().with_max_level(filter).init(); info!("Logging initialized."); } diff --git a/src/console/clients/checker/app.rs b/src/console/clients/checker/app.rs index ade1d4820..84802688d 100644 --- a/src/console/clients/checker/app.rs +++ b/src/console/clients/checker/app.rs @@ -58,7 +58,7 @@ pub async fn run() -> Result> { } fn tracing_stdout_init(filter: LevelFilter) { - tracing_subscriber::fmt().with_max_level(filter).with_ansi(false).init(); + tracing_subscriber::fmt().with_max_level(filter).init(); info!("logging initialized."); } diff --git a/src/console/clients/udp/app.rs b/src/console/clients/udp/app.rs index 323fca1b6..c780157f4 100644 --- a/src/console/clients/udp/app.rs +++ b/src/console/clients/udp/app.rs @@ -127,7 +127,7 @@ pub async fn run() -> anyhow::Result<()> { } fn tracing_stdout_init(filter: LevelFilter) { - tracing_subscriber::fmt().with_max_level(filter).with_ansi(false).init(); + tracing_subscriber::fmt().with_max_level(filter).init(); info!("logging initialized."); } From a293373bb271d543bf0f03ef0ebb3807148b55d7 Mon Sep 17 00:00:00 2001 From: Jose Celano Date: Fri, 14 Jun 2024 16:36:14 +0100 Subject: [PATCH 2/3] chore(deps): add cargo dependency regex To parse cargo logs. --- Cargo.lock | 1 + Cargo.toml | 1 + 2 files changed, 2 insertions(+) diff --git a/Cargo.lock b/Cargo.lock index 1c10516b2..7a54063bf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4067,6 +4067,7 @@ dependencies = [ "r2d2_mysql", "r2d2_sqlite", "rand", + "regex", "reqwest", "ringbuf", "serde", diff --git a/Cargo.toml b/Cargo.toml index 418bcb3ed..8b58154ec 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -59,6 +59,7 @@ r2d2 = "0" r2d2_mysql = "24" r2d2_sqlite = { version = "0", features = ["bundled"] } rand = "0" +regex = "1.10.5" reqwest = { version = "0", features = ["json"] } ringbuf = "0" serde = { version = "1", features = ["derive"] } From eb928bcd041ba9942b777d150bf86b95b07829c8 Mon Sep 17 00:00:00 2001 From: Jose Celano Date: Fri, 14 Jun 2024 16:44:32 +0100 Subject: [PATCH 3/3] fix: [#893] enable color for logs It was disabled becuase parsing lgos to extract the services URLs was not working due to hidden color chars. This changes the parser to ignore color chars. --- src/console/ci/e2e/logs_parser.rs | 77 ++++++++++++++----------------- 1 file changed, 34 insertions(+), 43 deletions(-) diff --git a/src/console/ci/e2e/logs_parser.rs b/src/console/ci/e2e/logs_parser.rs index ff4028f80..a4024f29d 100644 --- a/src/console/ci/e2e/logs_parser.rs +++ b/src/console/ci/e2e/logs_parser.rs @@ -1,16 +1,11 @@ //! Utilities to parse Torrust Tracker logs. +use regex::Regex; use serde::{Deserialize, Serialize}; const INFO_LOG_LEVEL: &str = "INFO"; - -const UDP_TRACKER_TARGET: &str = "UDP TRACKER"; -const UDP_TRACKER_SOCKET_ADDR_START_PATTERN: &str = "Started on: udp://"; - -const HTTP_TRACKER_TARGET: &str = "HTTP TRACKER"; -const HTTP_TRACKER_URL_START_PATTERN: &str = "Started on: "; - -const HEALTH_CHECK_TARGET: &str = "HEALTH CHECK API"; -const HEALTH_CHECK_URL_START_PATTERN: &str = "Started on: "; +const UDP_TRACKER_LOG_TARGET: &str = "UDP TRACKER"; +const HTTP_TRACKER_LOG_TARGET: &str = "HTTP TRACKER"; +const HEALTH_CHECK_API_LOG_TARGET: &str = "HEALTH CHECK API"; #[derive(Serialize, Deserialize, Debug, Default)] pub struct RunningServices { @@ -59,19 +54,43 @@ impl RunningServices { /// /// NOTICE: Using colors in the console output could affect this method /// due to the hidden control chars. + /// + /// # Panics + /// + /// Will panic is the regular expression to parse the services can't be compiled. #[must_use] pub fn parse_from_logs(logs: &str) -> Self { let mut udp_trackers: Vec = Vec::new(); let mut http_trackers: Vec = Vec::new(); let mut health_checks: Vec = Vec::new(); + let udp_re = Regex::new(r"Started on: udp://([0-9.]+:[0-9]+)").unwrap(); + let http_re = Regex::new(r"Started on: (https?://[0-9.]+:[0-9]+)").unwrap(); // DevSkim: ignore DS137138 + let health_re = Regex::new(r"Started on: (https?://[0-9.]+:[0-9]+)").unwrap(); // DevSkim: ignore DS137138 + let ansi_escape_re = Regex::new(r"\x1b\[[0-9;]*m").unwrap(); + for line in logs.lines() { - if let Some(address) = Self::extract_udp_tracker_url(line) { - udp_trackers.push(address); - } else if let Some(address) = Self::extract_http_tracker_url(line) { - http_trackers.push(address); - } else if let Some(address) = Self::extract_health_check_api_url(line) { - health_checks.push(format!("{address}/health_check")); + let clean_line = ansi_escape_re.replace_all(line, ""); + + if !line.contains(INFO_LOG_LEVEL) { + continue; + }; + + if line.contains(UDP_TRACKER_LOG_TARGET) { + if let Some(captures) = udp_re.captures(&clean_line) { + let address = Self::replace_wildcard_ip_with_localhost(&captures[1]); + udp_trackers.push(address); + } + } else if line.contains(HTTP_TRACKER_LOG_TARGET) { + if let Some(captures) = http_re.captures(&clean_line) { + let address = Self::replace_wildcard_ip_with_localhost(&captures[1]); + http_trackers.push(address); + } + } else if line.contains(HEALTH_CHECK_API_LOG_TARGET) { + if let Some(captures) = health_re.captures(&clean_line) { + let address = format!("{}/health_check", Self::replace_wildcard_ip_with_localhost(&captures[1])); + health_checks.push(address); + } } } @@ -82,34 +101,6 @@ impl RunningServices { } } - fn extract_udp_tracker_url(line: &str) -> Option { - if !line.contains(INFO_LOG_LEVEL) || !line.contains(UDP_TRACKER_TARGET) { - return None; - }; - - line.find(UDP_TRACKER_SOCKET_ADDR_START_PATTERN).map(|start| { - Self::replace_wildcard_ip_with_localhost(line[start + UDP_TRACKER_SOCKET_ADDR_START_PATTERN.len()..].trim()) - }) - } - - fn extract_http_tracker_url(line: &str) -> Option { - if !line.contains(INFO_LOG_LEVEL) || !line.contains(HTTP_TRACKER_TARGET) { - return None; - }; - - line.find(HTTP_TRACKER_URL_START_PATTERN) - .map(|start| Self::replace_wildcard_ip_with_localhost(line[start + HTTP_TRACKER_URL_START_PATTERN.len()..].trim())) - } - - fn extract_health_check_api_url(line: &str) -> Option { - if !line.contains(INFO_LOG_LEVEL) || !line.contains(HEALTH_CHECK_TARGET) { - return None; - }; - - line.find(HEALTH_CHECK_URL_START_PATTERN) - .map(|start| Self::replace_wildcard_ip_with_localhost(line[start + HEALTH_CHECK_URL_START_PATTERN.len()..].trim())) - } - fn replace_wildcard_ip_with_localhost(address: &str) -> String { address.replace("0.0.0.0", "127.0.0.1") }