diff --git a/Cargo.lock b/Cargo.lock index 64e7a86..b33410e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -62,56 +62,6 @@ dependencies = [ "libc", ] -[[package]] -name = "anstream" -version = "0.6.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b" -dependencies = [ - "anstyle", - "anstyle-parse", - "anstyle-query", - "anstyle-wincon", - "colorchoice", - "is_terminal_polyfill", - "utf8parse", -] - -[[package]] -name = "anstyle" -version = "1.0.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" - -[[package]] -name = "anstyle-parse" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9" -dependencies = [ - "utf8parse", -] - -[[package]] -name = "anstyle-query" -version = "1.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c" -dependencies = [ - "windows-sys 0.59.0", -] - -[[package]] -name = "anstyle-wincon" -version = "3.0.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6680de5231bd6ee4c6191b8a1325daa282b415391ec9d3a37bd34f2060dc73fa" -dependencies = [ - "anstyle", - "once_cell_polyfill", - "windows-sys 0.59.0", -] - [[package]] name = "async-compression" version = "0.4.23" @@ -305,12 +255,6 @@ dependencies = [ "tracing-error", ] -[[package]] -name = "colorchoice" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" - [[package]] name = "compact_str" version = "0.8.1" @@ -497,19 +441,6 @@ dependencies = [ "regex", ] -[[package]] -name = "env_logger" -version = "0.11.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13c863f0904021b108aa8b2f55046443e6b1ebde8fd4a15c399893aae4fa069f" -dependencies = [ - "anstream", - "anstyle", - "env_filter", - "jiff", - "log", -] - [[package]] name = "equivalent" version = "1.0.2" @@ -1099,12 +1030,6 @@ dependencies = [ "serde", ] -[[package]] -name = "is_terminal_polyfill" -version = "1.70.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" - [[package]] name = "itertools" version = "0.13.0" @@ -1120,30 +1045,6 @@ version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" -[[package]] -name = "jiff" -version = "0.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a194df1107f33c79f4f93d02c80798520551949d59dfad22b6157048a88cca93" -dependencies = [ - "jiff-static", - "log", - "portable-atomic", - "portable-atomic-util", - "serde", -] - -[[package]] -name = "jiff-static" -version = "0.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c6e1db7ed32c6c71b759497fae34bf7933636f75a251b9e736555da426f6442" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.101", -] - [[package]] name = "js-sys" version = "0.3.77" @@ -1290,6 +1191,16 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "nu-ansi-term" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" +dependencies = [ + "overload", + "winapi", +] + [[package]] name = "num-traits" version = "0.2.19" @@ -1314,18 +1225,18 @@ version = "1.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" -[[package]] -name = "once_cell_polyfill" -version = "1.70.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4895175b425cb1f87721b59f0f286c2092bd4af812243672510e1ac53e2e0ad" - [[package]] name = "option-ext" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" +[[package]] +name = "overload" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" + [[package]] name = "owo-colors" version = "4.2.1" @@ -1379,21 +1290,6 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" -[[package]] -name = "portable-atomic" -version = "1.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "350e9b48cbc6b0e028b0473b114454c6316e57336ee184ceab6e53f72c178b3e" - -[[package]] -name = "portable-atomic-util" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8a2f0d8d040d7848a709caf78912debcc3f33ee4b3cac47d73d1e1069e83507" -dependencies = [ - "portable-atomic", -] - [[package]] name = "potential_utf" version = "0.1.2" @@ -1429,10 +1325,8 @@ dependencies = [ "crossterm", "derivative", "dirs", - "env_logger", "fancy-regex", "futures", - "log", "maxminddb", "ratatui", "reqwest", @@ -1441,6 +1335,9 @@ dependencies = [ "serde_json", "tokio", "toml", + "tracing", + "tracing-log", + "tracing-subscriber", "tui-logger", "url", ] @@ -2298,15 +2195,29 @@ dependencies = [ "tracing-subscriber", ] +[[package]] +name = "tracing-log" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" +dependencies = [ + "log", + "once_cell", + "tracing-core", +] + [[package]] name = "tracing-subscriber" version = "0.3.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e8189decb5ac0fa7bc8b96b7cb9b2701d60d48805aca84a238004d665fcc4008" dependencies = [ + "nu-ansi-term", "sharded-slab", + "smallvec", "thread_local", "tracing-core", + "tracing-log", ] [[package]] @@ -2328,6 +2239,8 @@ dependencies = [ "log", "parking_lot", "ratatui", + "tracing", + "tracing-subscriber", "unicode-segmentation", ] @@ -2389,12 +2302,6 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" -[[package]] -name = "utf8parse" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" - [[package]] name = "valuable" version = "0.1.1" diff --git a/Cargo.toml b/Cargo.toml index 9b41777..c437027 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,10 +12,8 @@ crossterm = { version = "=0.28.1", features = [ ], optional = true } derivative = "=2.2.0" dirs = "=6.0.0" -env_logger = "=0.11.8" fancy-regex = "=0.14.0" futures = { version = "=0.3.31", optional = true } -log = "=0.4.27" maxminddb = { version = "=0.26.0", features = ["mmap"] } ratatui = { version = "=0.29.0", optional = true } rlimit = "=0.10.2" @@ -23,7 +21,12 @@ serde = "=1.0.219" serde_json = "=1.0.140" tokio = { version = "=1.45.1", features = ["full"] } toml = "=0.8.22" -tui-logger = { version = "=0.17.3", optional = true } +tracing = "=0.1.41" +tracing-log = "=0.2.0" +tracing-subscriber = "=0.3.19" +tui-logger = { version = "=0.17.3", features = [ + "tracing-support", +], optional = true } url = "=2.5.4" [features] diff --git a/config.toml b/config.toml index 36f7a71..c309e96 100644 --- a/config.toml +++ b/config.toml @@ -1,5 +1,5 @@ # Use debug logging level -# Useful for debugging but can produce a lot of output +# Produces a lot of output debug = false @@ -23,10 +23,6 @@ timeout = 5.0 # "" - Disable checking entirely check_url = "https://checkip.amazonaws.com" -# Enable logging of proxy rejection reasons -# Useful for debugging but can produce a lot of output -debug = false - # Maximum concurrent proxy checks # Make sure you have enough RAM first and your network can handle it, gradually increasing the default value max_concurrent_checks = 4096 diff --git a/src/checker.rs b/src/checker.rs index f527eb8..e212c25 100644 --- a/src/checker.rs +++ b/src/checker.rs @@ -48,13 +48,10 @@ pub async fn check_all( )))?; new_storage.lock().await.push(proxy); } - Err(e) if config.checking.debug => { - log::log!( - if log::log_enabled!(log::Level::Debug) { - log::Level::Debug - } else { - log::Level::Info - }, + Err(e) + if tracing::event_enabled!(tracing::Level::DEBUG) => + { + tracing::debug!( "{} | {}", proxy.as_str(true), pretty_error(&e) diff --git a/src/config.rs b/src/config.rs index 6fb3c79..f595d7c 100644 --- a/src/config.rs +++ b/src/config.rs @@ -25,7 +25,6 @@ pub struct ScrapingConfig { pub struct CheckingConfig { pub check_url: String, - pub debug: bool, pub max_concurrent_checks: usize, pub timeout: tokio::time::Duration, } @@ -104,7 +103,7 @@ impl Config { let lim = usize::try_from(lim).unwrap_or(usize::MAX); if raw_config.checking.max_concurrent_checks.get() > lim { - log::warn!( + tracing::warn!( "max_concurrent_checks config value is too high for \ your OS. It will be ignored and {lim} will be used." ); @@ -138,7 +137,6 @@ impl Config { }, checking: CheckingConfig { check_url: raw_config.checking.check_url, - debug: raw_config.checking.debug, max_concurrent_checks, timeout: tokio::time::Duration::from_secs_f64( raw_config.checking.timeout, diff --git a/src/event.rs b/src/event.rs index 42269d0..482e01c 100644 --- a/src/event.rs +++ b/src/event.rs @@ -1,9 +1,5 @@ -#[cfg(feature = "tui")] -use crate::ipdb; -#[cfg(feature = "tui")] -use crate::proxy::ProxyType; +use crate::{ipdb, proxy::ProxyType}; -#[cfg(feature = "tui")] pub enum AppEvent { IpDbTotal(ipdb::DbType, Option), IpDbDownloaded(ipdb::DbType, usize), @@ -18,12 +14,8 @@ pub enum AppEvent { Done, } -#[cfg(feature = "tui")] pub enum Event { Tick, Crossterm(crossterm::event::Event), App(AppEvent), } - -#[cfg(not(feature = "tui"))] -pub enum Event {} diff --git a/src/ipdb.rs b/src/ipdb.rs index a6b0df0..e05a86b 100644 --- a/src/ipdb.rs +++ b/src/ipdb.rs @@ -83,7 +83,7 @@ impl DbType { async fn save_etag( &self, - etag: reqwest::header::HeaderValue, + etag: impl AsRef<[u8]>, ) -> color_eyre::Result<()> { let path = self.etag_path().await?; tokio::fs::write(&path, etag).await.wrap_err_with(move || { @@ -150,7 +150,7 @@ impl DbType { })?; if response.status() == reqwest::StatusCode::NOT_MODIFIED { - log::info!( + tracing::info!( "Latest {} database is already cached at {}", self.name(), db_path.display() @@ -177,13 +177,13 @@ impl DbType { .wrap_err_with(|| format!("failed to save {} database", self.name()))?; if is_docker().await { - log::info!( + tracing::info!( "Downloaded {} database to Docker volume ({} in container)", self.name(), db_path.display() ); } else { - log::info!( + tracing::info!( "Downloaded {} database to {}", self.name(), db_path.display() diff --git a/src/main.rs b/src/main.rs index f5f21c9..73f649b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -36,6 +36,7 @@ mod checker; mod config; +#[cfg(feature = "tui")] mod event; mod fs; mod ipdb; @@ -44,13 +45,17 @@ mod parsers; mod proxy; mod raw_config; mod scraper; -mod ui; +#[cfg(feature = "tui")] +mod tui; mod utils; use std::sync::Arc; use color_eyre::eyre::WrapErr as _; -use ui::UI as _; +#[cfg(not(feature = "tui"))] +use tracing_subscriber::{ + layer::SubscriberExt as _, util::SubscriberInitExt as _, +}; fn create_reqwest_client() -> reqwest::Result { reqwest::Client::builder() @@ -64,16 +69,13 @@ fn create_reqwest_client() -> reqwest::Result { #[tokio::main] async fn main() -> color_eyre::Result<()> { color_eyre::install().wrap_err("failed to install color_eyre hooks")?; - let ui_impl = - ui::UIImpl::new().wrap_err("failed to initialize user interface")?; - - let (tx, rx) = tokio::sync::mpsc::unbounded_channel(); - let ui_task = tokio::task::spawn(ui_impl.run(tx.clone(), rx)); let raw_config_path = raw_config::get_config_path(); - let raw_config = raw_config::read_config(&raw_config_path) - .await - .wrap_err_with(move || format!("failed to read {raw_config_path}"))?; + let raw_config = raw_config::read_config(std::path::Path::new( + &raw_config_path, + )) + .await + .wrap_err_with(move || format!("failed to read {raw_config_path}"))?; let config = Arc::new( config::Config::from_raw_config(raw_config) @@ -81,9 +83,34 @@ async fn main() -> color_eyre::Result<()> { .wrap_err("failed to create Config from RawConfig")?, ); - if config.debug { - ui::UIImpl::set_log_level(log::LevelFilter::Debug); - } + let targets_filter = tracing_subscriber::filter::Targets::new() + .with_default(tracing::level_filters::LevelFilter::INFO) + // TODO: remove for hickory_proto >= 0.25.0 + .with_target( + "hickory_proto::xfer::dns_exchange", + tracing::level_filters::LevelFilter::ERROR, + ) + .with_target( + "proxy_scraper_checker", + if config.debug { + tracing::level_filters::LevelFilter::DEBUG + } else { + tracing::level_filters::LevelFilter::INFO + }, + ); + + #[cfg(feature = "tui")] + let (tx, rx) = tokio::sync::mpsc::unbounded_channel(); + + #[cfg(feature = "tui")] + let tui_task = + tokio::task::spawn(tui::Tui::new(targets_filter)?.run(tx.clone(), rx)); + + #[cfg(not(feature = "tui"))] + tracing_subscriber::registry() + .with(targets_filter) + .with(tracing_subscriber::fmt::layer()) + .init(); let http_client = create_reqwest_client() .wrap_err("failed to create reqwest HTTP client")?; @@ -134,10 +161,14 @@ async fn main() -> color_eyre::Result<()> { while let Some(task) = output_dependencies_tasks.join_next().await { task.wrap_err("failed to join output dependencies task")??; } + drop(output_dependencies_tasks); let proxies = if config.checking.check_url.is_empty() { proxies.into_iter().collect() } else { + #[cfg(not(feature = "tui"))] + tracing::info!("Started checking {} proxies", proxies.len()); + checker::check_all( Arc::clone(&config), proxies, @@ -152,9 +183,16 @@ async fn main() -> color_eyre::Result<()> { .await .wrap_err("failed to save proxies")?; - log::info!("Thank you for using proxy-scraper-checker!"); + tracing::info!("Thank you for using proxy-scraper-checker!"); + #[cfg(feature = "tui")] tx.send(event::Event::App(event::AppEvent::Done))?; + + #[cfg(feature = "tui")] drop(tx); - ui_task.await? + + #[cfg(feature = "tui")] + tui_task.await??; + + Ok(()) } diff --git a/src/output.rs b/src/output.rs index 19b3e08..6d9b314 100644 --- a/src/output.rs +++ b/src/output.rs @@ -45,7 +45,7 @@ struct ProxyJson<'a> { fn group_proxies<'a>( config: &Config, - proxies: &'a Vec, + proxies: &'a [Proxy], ) -> HashMap> { let mut groups: HashMap<_, _> = config.enabled_protocols().map(|p| (p.clone(), Vec::new())).collect(); @@ -189,7 +189,7 @@ pub async fn save_proxies( )?; let text = create_proxy_list_str( - &proxies.iter().collect(), + &proxies.iter().collect::>(), anonymous_only, true, ); @@ -226,19 +226,19 @@ pub async fn save_proxies( .canonicalize() .unwrap_or_else(move |_| config.output.path.clone()); if is_docker().await { - log::info!( + tracing::info!( "Proxies have been saved to ./out ({} in container)", path.display() ); } else { - log::info!("Proxies have been saved to {}", path.display()); + tracing::info!("Proxies have been saved to {}", path.display()); } Ok(()) } fn create_proxy_list_str( - proxies: &Vec<&Proxy>, + proxies: &[&Proxy], anonymous_only: bool, include_protocol: bool, ) -> String { diff --git a/src/raw_config.rs b/src/raw_config.rs index c693911..930b394 100644 --- a/src/raw_config.rs +++ b/src/raw_config.rs @@ -1,4 +1,9 @@ -use std::{collections::HashSet, env, num::NonZero, path::PathBuf}; +use std::{ + collections::HashSet, + env, + num::NonZero, + path::{Path, PathBuf}, +}; use color_eyre::eyre::WrapErr as _; use serde::{Deserialize, Deserializer}; @@ -50,7 +55,6 @@ pub struct ScrapingConfig { pub struct CheckingConfig { #[serde(deserialize_with = "validate_http_url")] pub check_url: String, - pub debug: bool, pub max_concurrent_checks: NonZero, #[serde(deserialize_with = "validate_positive_f64")] pub timeout: f64, @@ -119,11 +123,12 @@ pub fn get_config_path() -> String { env::var(CONFIG_ENV).unwrap_or_else(|_| "config.toml".to_owned()) } -pub async fn read_config(path: &str) -> color_eyre::Result { - let raw_config = tokio::fs::read_to_string(path) - .await - .wrap_err_with(move || format!("failed to read {path} to string"))?; +pub async fn read_config(path: &Path) -> color_eyre::Result { + let raw_config = + tokio::fs::read_to_string(path).await.wrap_err_with(move || { + format!("failed to read {} to string", path.display()) + })?; toml::from_str(&raw_config).wrap_err_with(move || { - format!("failed to parse {path} as TOML config file") + format!("failed to parse {} as TOML config file", path.display()) }) } diff --git a/src/scraper.rs b/src/scraper.rs index ad69e6a..c028899 100644 --- a/src/scraper.rs +++ b/src/scraper.rs @@ -49,7 +49,7 @@ async fn scrape_one( let text = match text_result { Ok(text) => text, Err(e) => { - log::warn!("{} | {}", source, pretty_error(&e)); + tracing::warn!("{} | {}", source, pretty_error(&e)); return Ok(()); } }; @@ -58,14 +58,14 @@ async fn scrape_one( PROXY_REGEX.captures_iter(&text).collect::, _>>()?; if matches.is_empty() { - log::warn!("{source} | No proxies found"); + tracing::warn!("{source} | No proxies found"); return Ok(()); } if config.scraping.max_proxies_per_source != 0 && matches.len() > config.scraping.max_proxies_per_source { - log::warn!( + tracing::warn!( "{} | Too many proxies ({}) - skipped", source, matches.len(), diff --git a/src/ui/tui.rs b/src/tui.rs similarity index 96% rename from src/ui/tui.rs rename to src/tui.rs index 0759e01..e2adbcc 100644 --- a/src/ui/tui.rs +++ b/src/tui.rs @@ -18,6 +18,9 @@ use ratatui::{ text::{Line, Text}, widgets::{Block, Gauge}, }; +use tracing_subscriber::{ + layer::SubscriberExt as _, util::SubscriberInitExt as _, +}; use tui_logger::{TuiLoggerWidget, TuiWidgetEvent, TuiWidgetState}; use crate::{ @@ -33,22 +36,25 @@ pub struct Tui { terminal: DefaultTerminal, } -impl super::UI for Tui { - fn new() -> color_eyre::Result { - tui_logger::init_logger(log::LevelFilter::Info) +impl Tui { + pub fn new( + filter: tracing_subscriber::filter::Targets, + ) -> color_eyre::Result { + tui_logger::init_logger(tui_logger::LevelFilter::Trace) .wrap_err("failed to initialize tui_logger")?; - tui_logger::set_default_level(log::LevelFilter::Trace); + + tracing_subscriber::registry() + .with(filter) + .with(tui_logger::TuiTracingSubscriberLayer) + .init(); + Ok(Self { terminal: ratatui::try_init() .wrap_err("failed to initialize ratatui")?, }) } - fn set_log_level(log_level: log::LevelFilter) { - log::set_max_level(log_level); - } - - async fn run( + pub async fn run( mut self, tx: tokio::sync::mpsc::UnboundedSender, mut rx: tokio::sync::mpsc::UnboundedReceiver, diff --git a/src/ui/logger.rs b/src/ui/logger.rs deleted file mode 100644 index 5e899bd..0000000 --- a/src/ui/logger.rs +++ /dev/null @@ -1,27 +0,0 @@ -use color_eyre::eyre::WrapErr as _; - -use crate::event::Event; - -pub struct LoggerUI; - -impl super::UI for LoggerUI { - fn new() -> color_eyre::Result { - env_logger::Builder::new() - .filter_level(log::LevelFilter::Info) - .try_init() - .wrap_err("failed to initialize env_logger")?; - Ok(Self {}) - } - - fn set_log_level(log_level: log::LevelFilter) { - log::set_max_level(log_level); - } - - async fn run( - self, - _tx: tokio::sync::mpsc::UnboundedSender, - _rx: tokio::sync::mpsc::UnboundedReceiver, - ) -> color_eyre::Result<()> { - Ok(()) - } -} diff --git a/src/ui/mod.rs b/src/ui/mod.rs deleted file mode 100644 index c137b27..0000000 --- a/src/ui/mod.rs +++ /dev/null @@ -1,29 +0,0 @@ -#![expect(clippy::pub_use)] - -use std::marker::Sized; - -use crate::event::Event; - -pub trait UI { - fn new() -> color_eyre::Result - where - Self: Sized; - - fn set_log_level(log_level: log::LevelFilter); - - async fn run( - self, - tx: tokio::sync::mpsc::UnboundedSender, - rx: tokio::sync::mpsc::UnboundedReceiver, - ) -> color_eyre::Result<()>; -} - -#[cfg(feature = "tui")] -mod tui; -#[cfg(feature = "tui")] -pub use tui::Tui as UIImpl; - -#[cfg(not(feature = "tui"))] -mod logger; -#[cfg(not(feature = "tui"))] -pub use logger::LoggerUI as UIImpl;