Refactor startup logging

Move all startup output (DC pings, proxy links) from println!() to
      info!() for consistent tracing format. Add reload::Layer so startup
      messages stay visible even in silent mode.
This commit is contained in:
Жора Змейкин
2026-02-12 05:14:23 +03:00
parent 364bc6e278
commit 9304d5256a
3 changed files with 2777 additions and 25 deletions

2742
Cargo.lock generated Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -43,7 +43,8 @@ pub enum LogLevel {
#[default] #[default]
Normal, Normal,
/// Minimal output: only warnings and errors (warn + error). /// Minimal output: only warnings and errors (warn + error).
/// Proxy links are still printed to stdout via println!. /// Startup messages (config, DC connectivity, proxy links) are always shown
/// via info! before the filter is applied.
Silent, Silent,
} }

View File

@@ -6,7 +6,7 @@ use std::time::Duration;
use tokio::net::TcpListener; use tokio::net::TcpListener;
use tokio::signal; use tokio::signal;
use tracing::{info, error, warn, debug}; use tracing::{info, error, warn, debug};
use tracing_subscriber::{fmt, EnvFilter}; use tracing_subscriber::{fmt, EnvFilter, reload, prelude::*};
mod cli; mod cli;
mod config; mod config;
@@ -105,6 +105,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
std::process::exit(1); std::process::exit(1);
} }
let has_rust_log = std::env::var("RUST_LOG").is_ok();
let effective_log_level = if cli_silent { let effective_log_level = if cli_silent {
LogLevel::Silent LogLevel::Silent
} else if let Some(ref s) = cli_log_level { } else if let Some(ref s) = cli_log_level {
@@ -113,13 +114,13 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
config.general.log_level.clone() config.general.log_level.clone()
}; };
let filter = if std::env::var("RUST_LOG").is_ok() { // Start with INFO so startup messages are always visible,
EnvFilter::from_default_env() // then switch to user-configured level after startup
} else { let (filter_layer, filter_handle) = reload::Layer::new(EnvFilter::new("info"));
EnvFilter::new(effective_log_level.to_filter_str()) tracing_subscriber::registry()
}; .with(filter_layer)
.with(fmt::Layer::default())
fmt().with_env_filter(filter).init(); .init();
info!("Telemt MTProxy v{}", env!("CARGO_PKG_VERSION")); info!("Telemt MTProxy v{}", env!("CARGO_PKG_VERSION"));
info!("Log level: {}", effective_log_level); info!("Log level: {}", effective_log_level);
@@ -151,25 +152,25 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
let buffer_pool = Arc::new(BufferPool::with_config(16 * 1024, 4096)); let buffer_pool = Arc::new(BufferPool::with_config(16 * 1024, 4096));
// Startup DC ping // Startup DC ping
println!("=== Telegram DC Connectivity ==="); info!("=== Telegram DC Connectivity ===");
let ping_results = upstream_manager.ping_all_dcs(prefer_ipv6).await; let ping_results = upstream_manager.ping_all_dcs(prefer_ipv6).await;
for upstream_result in &ping_results { for upstream_result in &ping_results {
println!(" via {}", upstream_result.upstream_name); info!(" via {}", upstream_result.upstream_name);
for dc in &upstream_result.results { for dc in &upstream_result.results {
match (&dc.rtt_ms, &dc.error) { match (&dc.rtt_ms, &dc.error) {
(Some(rtt), _) => { (Some(rtt), _) => {
println!(" DC{} ({:>21}): {:.0}ms", dc.dc_idx, dc.dc_addr, rtt); info!(" DC{} ({:>21}): {:.0}ms", dc.dc_idx, dc.dc_addr, rtt);
} }
(None, Some(err)) => { (None, Some(err)) => {
println!(" DC{} ({:>21}): FAIL ({})", dc.dc_idx, dc.dc_addr, err); info!(" DC{} ({:>21}): FAIL ({})", dc.dc_idx, dc.dc_addr, err);
} }
_ => { _ => {
println!(" DC{} ({:>21}): FAIL", dc.dc_idx, dc.dc_addr); info!(" DC{} ({:>21}): FAIL", dc.dc_idx, dc.dc_addr);
} }
} }
} }
} }
println!("================================"); info!("================================");
// Background tasks // Background tasks
let um_clone = upstream_manager.clone(); let um_clone = upstream_manager.clone();
@@ -208,28 +209,28 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
}; };
if !config.show_link.is_empty() { if !config.show_link.is_empty() {
println!("--- Proxy Links ({}) ---", public_ip); info!("--- Proxy Links ({}) ---", public_ip);
for user_name in &config.show_link { for user_name in &config.show_link {
if let Some(secret) = config.access.users.get(user_name) { if let Some(secret) = config.access.users.get(user_name) {
println!("[{}]", user_name); info!("User: {}", user_name);
if config.general.modes.classic { if config.general.modes.classic {
println!(" Classic: tg://proxy?server={}&port={}&secret={}", info!(" Classic: tg://proxy?server={}&port={}&secret={}",
public_ip, config.server.port, secret); public_ip, config.server.port, secret);
} }
if config.general.modes.secure { if config.general.modes.secure {
println!(" DD: tg://proxy?server={}&port={}&secret=dd{}", info!(" DD: tg://proxy?server={}&port={}&secret=dd{}",
public_ip, config.server.port, secret); public_ip, config.server.port, secret);
} }
if config.general.modes.tls { if config.general.modes.tls {
let domain_hex = hex::encode(&config.censorship.tls_domain); let domain_hex = hex::encode(&config.censorship.tls_domain);
println!(" EE-TLS: tg://proxy?server={}&port={}&secret=ee{}{}", info!(" EE-TLS: tg://proxy?server={}&port={}&secret=ee{}{}",
public_ip, config.server.port, secret, domain_hex); public_ip, config.server.port, secret, domain_hex);
} }
} else { } else {
warn!("User '{}' in show_link not found", user_name); warn!("User '{}' in show_link not found", user_name);
} }
} }
println!("------------------------"); info!("------------------------");
} }
listeners.push(listener); listeners.push(listener);
@@ -245,6 +246,14 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
std::process::exit(1); std::process::exit(1);
} }
// Switch to user-configured log level after startup
let runtime_filter = if has_rust_log {
EnvFilter::from_default_env()
} else {
EnvFilter::new(effective_log_level.to_filter_str())
};
filter_handle.reload(runtime_filter).expect("Failed to switch log filter");
for listener in listeners { for listener in listeners {
let config = config.clone(); let config = config.clone();
let stats = stats.clone(); let stats = stats.clone();