refactor: remove log dependency, replace with custom macros
- Added custom logging macros (log_error!, log_warn!, log_info!, log_debug!) - Implemented LogLevel enum and LOG_LEVEL static for runtime level control - Exported macros with #[macro_export] for use across all modules - Replaced all log:: calls in websocket_client.rs, health.rs, and version.rs - Removed obsolete test code referencing old log crate - Removed log dependency from Cargo.toml - Fixed useless comparison warning in test - Binary size: still 1.5M (no change - log was lightweight) - Tests: 65 passing, 0 warnings This completes the removal of 9 dependencies (thiserror, hostname, chrono, base64, rand, ureq, tiny_http, anyhow, log). Dependency count: 19 → 10. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
0daaf9ed68
commit
71267870b0
6 changed files with 45 additions and 84 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
|
@ -1085,7 +1085,6 @@ version = "0.1.0"
|
|||
dependencies = [
|
||||
"clap",
|
||||
"futures",
|
||||
"log",
|
||||
"prost",
|
||||
"prost-build",
|
||||
"prost-types",
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@ tokio-tungstenite = { version = "0.21", features = ["rustls-tls-webpki-roots"] }
|
|||
futures = "0.3"
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde_json = "1.0"
|
||||
log = { version = "0.4", features = ["std"] }
|
||||
clap = { version = "4.0", features = ["derive", "env"] }
|
||||
prost = "0.13"
|
||||
prost-types = "0.13"
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
use log::info;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::sync::Arc;
|
||||
use std::time::Instant;
|
||||
|
|
@ -19,7 +18,7 @@ pub async fn start_health_server(port: u16) -> Result<()> {
|
|||
let start_time = Arc::new(Instant::now());
|
||||
let addr = format!("0.0.0.0:{}", port);
|
||||
|
||||
info!("Starting health endpoint on {}", addr);
|
||||
crate::log_info!("Starting health endpoint on {}", addr);
|
||||
let listener = TcpListener::bind(&addr).await?;
|
||||
|
||||
loop {
|
||||
|
|
@ -68,7 +67,7 @@ pub async fn start_health_server(port: u16) -> Result<()> {
|
|||
});
|
||||
}
|
||||
Err(e) => {
|
||||
log::warn!("Failed to accept health check connection: {}", e);
|
||||
crate::log_warn!("Failed to accept health check connection: {}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
62
src/main.rs
62
src/main.rs
|
|
@ -12,10 +12,10 @@ use tokio::time::sleep;
|
|||
use websocket_client::AgentClient;
|
||||
|
||||
// Log levels
|
||||
static LOG_LEVEL: std::sync::OnceLock<LogLevel> = std::sync::OnceLock::new();
|
||||
pub(crate) static LOG_LEVEL: std::sync::OnceLock<LogLevel> = std::sync::OnceLock::new();
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
|
||||
enum LogLevel {
|
||||
pub(crate) enum LogLevel {
|
||||
Error = 1,
|
||||
Warn = 2,
|
||||
Info = 3,
|
||||
|
|
@ -34,40 +34,44 @@ impl LogLevel {
|
|||
}
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! log_error {
|
||||
($($arg:tt)*) => {{
|
||||
let level = LOG_LEVEL.get().copied().unwrap_or(LogLevel::Info);
|
||||
if level >= LogLevel::Error {
|
||||
let level = $crate::LOG_LEVEL.get().copied().unwrap_or($crate::LogLevel::Info);
|
||||
if level >= $crate::LogLevel::Error {
|
||||
let ts = $crate::format_timestamp();
|
||||
eprintln!("[{}] [ERROR] {}", ts, format!($($arg)*));
|
||||
}
|
||||
}};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! log_warn {
|
||||
($($arg:tt)*) => {{
|
||||
let level = LOG_LEVEL.get().copied().unwrap_or(LogLevel::Info);
|
||||
if level >= LogLevel::Warn {
|
||||
let level = $crate::LOG_LEVEL.get().copied().unwrap_or($crate::LogLevel::Info);
|
||||
if level >= $crate::LogLevel::Warn {
|
||||
let ts = $crate::format_timestamp();
|
||||
eprintln!("[{}] [WARN] {}", ts, format!($($arg)*));
|
||||
}
|
||||
}};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! log_info {
|
||||
($($arg:tt)*) => {{
|
||||
let level = LOG_LEVEL.get().copied().unwrap_or(LogLevel::Info);
|
||||
if level >= LogLevel::Info {
|
||||
let level = $crate::LOG_LEVEL.get().copied().unwrap_or($crate::LogLevel::Info);
|
||||
if level >= $crate::LogLevel::Info {
|
||||
let ts = $crate::format_timestamp();
|
||||
eprintln!("[{}] [INFO] {}", ts, format!($($arg)*));
|
||||
}
|
||||
}};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! log_debug {
|
||||
($($arg:tt)*) => {{
|
||||
let level = LOG_LEVEL.get().copied().unwrap_or(LogLevel::Info);
|
||||
if level >= LogLevel::Debug {
|
||||
let level = $crate::LOG_LEVEL.get().copied().unwrap_or($crate::LogLevel::Info);
|
||||
if level >= $crate::LogLevel::Debug {
|
||||
let ts = $crate::format_timestamp();
|
||||
eprintln!("[{}] [DEBUG] {}", ts, format!($($arg)*));
|
||||
}
|
||||
|
|
@ -243,44 +247,6 @@ async fn main() {
|
|||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use log::Log;
|
||||
|
||||
#[test]
|
||||
fn test_simple_logger_enabled() {
|
||||
let logger = SimpleLogger {
|
||||
level: LevelFilter::Info,
|
||||
};
|
||||
|
||||
// Info level should be enabled
|
||||
let info_metadata = log::MetadataBuilder::new()
|
||||
.level(log::Level::Info)
|
||||
.target("test")
|
||||
.build();
|
||||
assert!(logger.enabled(&info_metadata));
|
||||
|
||||
// Debug level should not be enabled
|
||||
let debug_metadata = log::MetadataBuilder::new()
|
||||
.level(log::Level::Debug)
|
||||
.target("test")
|
||||
.build();
|
||||
assert!(!logger.enabled(&debug_metadata));
|
||||
|
||||
// Error level should be enabled
|
||||
let error_metadata = log::MetadataBuilder::new()
|
||||
.level(log::Level::Error)
|
||||
.target("test")
|
||||
.build();
|
||||
assert!(logger.enabled(&error_metadata));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_simple_logger_flush() {
|
||||
let logger = SimpleLogger {
|
||||
level: LevelFilter::Info,
|
||||
};
|
||||
// flush() does nothing, just verify it's callable
|
||||
logger.flush();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_convert_http_to_websocket() {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,3 @@
|
|||
use log::info;
|
||||
|
||||
// Get version at runtime - prefers BUILD_VERSION from build.rs, falls back to Cargo.toml
|
||||
fn current_version() -> &'static str {
|
||||
option_env!("BUILD_VERSION").unwrap_or(env!("CARGO_PKG_VERSION"))
|
||||
|
|
@ -8,8 +6,8 @@ fn current_version() -> &'static str {
|
|||
/// Startup check - logs current version
|
||||
pub fn check_for_updates() {
|
||||
let current_ver = current_version();
|
||||
info!("Current version: {}", current_ver);
|
||||
info!("Watchtower will automatically update to new versions");
|
||||
crate::log_info!("Current version: {}", current_ver);
|
||||
crate::log_info!("Watchtower will automatically update to new versions");
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
|
|
|||
|
|
@ -59,17 +59,17 @@ impl AgentClient {
|
|||
// Strip trailing slash from base URL to avoid double slashes
|
||||
let base_url = url.trim_end_matches('/');
|
||||
let ws_url = format!("{}/socket/agent/websocket", base_url);
|
||||
log::info!("Connecting to WebSocket: {}", ws_url);
|
||||
crate::log_info!("Connecting to WebSocket: {}", ws_url);
|
||||
|
||||
let (mut ws_stream, _) = connect_async(&ws_url)
|
||||
.await
|
||||
.map_err(|e| {
|
||||
log::error!("WebSocket connection failed: {}", e);
|
||||
crate::log_error!("WebSocket connection failed: {}", e);
|
||||
e
|
||||
})
|
||||
.map_err(|e| format!("Failed to connect to WebSocket: {}", e))?;
|
||||
|
||||
log::info!("Connected to Towerops server at {}", url);
|
||||
crate::log_info!("Connected to Towerops server at {}", url);
|
||||
|
||||
let agent_id = generate_agent_id();
|
||||
let (result_tx, result_rx) = mpsc::unbounded_channel();
|
||||
|
|
@ -85,7 +85,7 @@ impl AgentClient {
|
|||
|
||||
let join_text = serde_json::to_string(&join_msg)?;
|
||||
ws_stream.send(WsMessage::Text(join_text)).await?;
|
||||
log::info!(
|
||||
crate::log_info!(
|
||||
"Sent channel join request with token for agent:{}",
|
||||
agent_id
|
||||
);
|
||||
|
|
@ -122,15 +122,15 @@ impl AgentClient {
|
|||
self.handle_text_message(&text).await?;
|
||||
}
|
||||
Some(Ok(WsMessage::Close(_))) => {
|
||||
log::info!("Server closed connection");
|
||||
crate::log_info!("Server closed connection");
|
||||
break;
|
||||
}
|
||||
Some(Err(e)) => {
|
||||
log::error!("WebSocket error: {}", e);
|
||||
crate::log_error!("WebSocket error: {}", e);
|
||||
return Err(e.into());
|
||||
}
|
||||
None => {
|
||||
log::info!("Connection closed");
|
||||
crate::log_info!("Connection closed");
|
||||
break;
|
||||
}
|
||||
_ => {}
|
||||
|
|
@ -163,7 +163,7 @@ impl AgentClient {
|
|||
|
||||
match phoenix_msg.event.as_str() {
|
||||
"phx_reply" => {
|
||||
log::info!("Channel join reply: {:?}", phoenix_msg.payload);
|
||||
crate::log_info!("Channel join reply: {:?}", phoenix_msg.payload);
|
||||
}
|
||||
"jobs" => {
|
||||
// Extract binary protobuf from payload
|
||||
|
|
@ -176,7 +176,7 @@ impl AgentClient {
|
|||
}
|
||||
}
|
||||
_ => {
|
||||
log::debug!("Ignoring unknown event: {}", phoenix_msg.event);
|
||||
crate::log_debug!("Ignoring unknown event: {}", phoenix_msg.event);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -195,11 +195,11 @@ impl AgentClient {
|
|||
|
||||
/// Process job list from server.
|
||||
async fn handle_jobs(&self, job_list: AgentJobList) -> Result<()> {
|
||||
log::info!("Received {} jobs from server", job_list.jobs.len());
|
||||
crate::log_info!("Received {} jobs from server", job_list.jobs.len());
|
||||
|
||||
for job in job_list.jobs {
|
||||
let job_type = JobType::try_from(job.job_type).unwrap_or(JobType::Poll);
|
||||
log::info!("Executing job: {} (type: {:?})", job.job_id, job_type);
|
||||
crate::log_info!("Executing job: {} (type: {:?})", job.job_id, job_type);
|
||||
|
||||
// Extract monitoring configuration before moving job
|
||||
let monitoring_info = job.snmp_device.as_ref().and_then(|snmp_device| {
|
||||
|
|
@ -224,13 +224,13 @@ impl AgentClient {
|
|||
|
||||
tokio::spawn(async move {
|
||||
if let Err(e) = execute_job(job, result_tx).await {
|
||||
log::error!("Job execution failed: {}", e);
|
||||
crate::log_error!("Job execution failed: {}", e);
|
||||
}
|
||||
});
|
||||
|
||||
// Start monitoring task if enabled
|
||||
if let Some((ip, interval_seconds)) = monitoring_info {
|
||||
log::info!(
|
||||
crate::log_info!(
|
||||
"Starting ICMP monitoring for device {} every {} seconds",
|
||||
device_id,
|
||||
interval_seconds
|
||||
|
|
@ -246,7 +246,7 @@ impl AgentClient {
|
|||
)
|
||||
.await
|
||||
{
|
||||
log::error!("Monitoring task failed: {}", e);
|
||||
crate::log_error!("Monitoring task failed: {}", e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
@ -277,7 +277,7 @@ impl AgentClient {
|
|||
let text = serde_json::to_string(&msg)?;
|
||||
self.ws_stream.send(WsMessage::Text(text)).await?;
|
||||
|
||||
log::debug!("Sent heartbeat");
|
||||
crate::log_debug!("Sent heartbeat");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
@ -295,7 +295,7 @@ impl AgentClient {
|
|||
let text = serde_json::to_string(&msg)?;
|
||||
self.ws_stream.send(WsMessage::Text(text)).await?;
|
||||
|
||||
log::debug!("Sent SNMP result for device {}", result.device_id);
|
||||
crate::log_debug!("Sent SNMP result for device {}", result.device_id);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
@ -313,7 +313,7 @@ impl AgentClient {
|
|||
let text = serde_json::to_string(&msg)?;
|
||||
self.ws_stream.send(WsMessage::Text(text)).await?;
|
||||
|
||||
log::debug!(
|
||||
crate::log_debug!(
|
||||
"Sent monitoring check for device {}: {}",
|
||||
check.device_id,
|
||||
check.status
|
||||
|
|
@ -351,7 +351,7 @@ async fn execute_job(job: AgentJob, result_tx: mpsc::UnboundedSender<SnmpResult>
|
|||
oid_values.insert(oid.clone(), value_to_string(value));
|
||||
}
|
||||
Err(e) => {
|
||||
log::warn!("SNMP GET failed for OID {}: {}", oid, e);
|
||||
crate::log_warn!("SNMP GET failed for OID {}: {}", oid, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -375,7 +375,7 @@ async fn execute_job(job: AgentJob, result_tx: mpsc::UnboundedSender<SnmpResult>
|
|||
}
|
||||
}
|
||||
Err(e) => {
|
||||
log::warn!("SNMP WALK failed for OID {}: {}", base_oid, e);
|
||||
crate::log_warn!("SNMP WALK failed for OID {}: {}", base_oid, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -393,7 +393,7 @@ async fn execute_job(job: AgentJob, result_tx: mpsc::UnboundedSender<SnmpResult>
|
|||
.as_secs() as i64,
|
||||
};
|
||||
|
||||
log::info!(
|
||||
crate::log_info!(
|
||||
"Collected {} OID values for job {}",
|
||||
result.oid_values.len(),
|
||||
job.job_id
|
||||
|
|
@ -549,7 +549,7 @@ async fn run_monitoring_task(
|
|||
let ip_addr: std::net::IpAddr = match ip.parse() {
|
||||
Ok(addr) => addr,
|
||||
Err(e) => {
|
||||
log::error!("Invalid IP address for device {}: {}", device_id, e);
|
||||
crate::log_error!("Invalid IP address for device {}: {}", device_id, e);
|
||||
continue;
|
||||
}
|
||||
};
|
||||
|
|
@ -568,11 +568,11 @@ async fn run_monitoring_task(
|
|||
};
|
||||
|
||||
if let Err(e) = check_tx.send(check) {
|
||||
log::error!("Failed to send monitoring check: {}", e);
|
||||
crate::log_error!("Failed to send monitoring check: {}", e);
|
||||
break;
|
||||
}
|
||||
|
||||
log::debug!(
|
||||
crate::log_debug!(
|
||||
"ICMP ping successful for {}: {:.2}ms",
|
||||
ip,
|
||||
rtt.as_secs_f64() * 1000.0
|
||||
|
|
@ -589,11 +589,11 @@ async fn run_monitoring_task(
|
|||
};
|
||||
|
||||
if let Err(send_err) = check_tx.send(check) {
|
||||
log::error!("Failed to send monitoring check: {}", send_err);
|
||||
crate::log_error!("Failed to send monitoring check: {}", send_err);
|
||||
break;
|
||||
}
|
||||
|
||||
log::warn!("ICMP ping failed for {}: {}", ip, e);
|
||||
crate::log_warn!("ICMP ping failed for {}: {}", ip, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -663,8 +663,8 @@ mod tests {
|
|||
let uptime = get_uptime_seconds();
|
||||
// On Linux with /proc/uptime, should return non-zero
|
||||
// On other platforms or if file doesn't exist, returns 0
|
||||
// Just verify it's callable and returns a number
|
||||
assert!(uptime >= 0);
|
||||
// uptime is u64, so always >= 0 - just verify it's callable
|
||||
let _ = uptime;
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue