docker_image_pusher/logging/
mod.rs

1//! Enhanced logging and output control
2//!
3//! This module provides the [`Logger`] for controlling output verbosity, formatting logs,
4//! and tracking operation timing. It supports quiet, verbose, and structured output.
5
6use std::io::{self, Write};
7use std::time::{Duration, Instant};
8
9/// Logger responsible for all user-visible output
10#[derive(Debug, Clone)]
11pub struct Logger {
12    pub verbose: bool,
13    pub quiet: bool,
14    pub start_time: Option<Instant>,
15}
16
17impl Logger {
18    pub fn new(verbose: bool) -> Self {
19        Self {
20            verbose,
21            quiet: false,
22            start_time: Some(Instant::now()),
23        }
24    }
25
26    pub fn new_quiet() -> Self {
27        Self {
28            verbose: false,
29            quiet: true,
30            start_time: Some(Instant::now()),
31        }
32    }
33
34    /// Main section heading
35    pub fn section(&self, title: &str) {
36        if !self.quiet {
37            println!("\n=== {} ===", title);
38        }
39    }
40
41    /// Sub-section heading
42    pub fn subsection(&self, title: &str) {
43        if !self.quiet {
44            println!("\n--- {} ---", title);
45        }
46    }
47
48    // Structured logging levels
49    pub fn trace(&self, message: &str) {
50        if self.verbose && !self.quiet {
51            println!("šŸ” TRACE: {}", message);
52        }
53    }
54
55    pub fn debug(&self, message: &str) {
56        if self.verbose && !self.quiet {
57            println!("šŸ› DEBUG: {}", message);
58        }
59    }
60
61    pub fn verbose(&self, message: &str) {
62        if self.verbose && !self.quiet {
63            println!("šŸ“ {}", message);
64        }
65    }
66
67    /// Information message
68    pub fn info(&self, message: &str) {
69        if !self.quiet {
70            println!("ā„¹ļø  {}", message);
71        }
72    }
73
74    /// Success message
75    pub fn success(&self, message: &str) {
76        if !self.quiet {
77            println!("āœ… {}", message);
78        }
79    }
80
81    /// Warning message
82    pub fn warning(&self, message: &str) {
83        if !self.quiet {
84            println!("āš ļø  WARNING: {}", message);
85        }
86    }
87
88    /// Error message
89    pub fn error(&self, message: &str) {
90        eprintln!("āŒ ERROR: {}", message);
91    }
92
93    /// Step information
94    pub fn step(&self, message: &str) {
95        if !self.quiet {
96            println!("ā–¶ļø  {}", message);
97        }
98    }
99
100    /// Progress information
101    pub fn progress(&self, message: &str) {
102        if !self.quiet {
103            print!("ā³ {}...", message);
104            let _ = io::stdout().flush();
105        }
106    }
107
108    /// Progress completion
109    pub fn progress_done(&self) {
110        if !self.quiet {
111            println!(" Done");
112        }
113    }
114
115    /// Detailed information (only shown in verbose mode)
116    pub fn detail(&self, message: &str) {
117        if self.verbose && !self.quiet {
118            println!("   {}", message);
119        }
120    }
121
122    // Summary method for displaying structured information
123    pub fn summary(&self, title: &str, items: &[String]) {
124        if !self.quiet {
125            println!("\nšŸ“‹ {}", title);
126            println!("{}", "─".repeat(title.len() + 3));
127
128            for item in items {
129                println!("  • {}", item);
130            }
131
132            if items.is_empty() {
133                println!("  (No items to display)");
134            }
135        }
136    }
137
138    /// Key-value pair summary display
139    pub fn summary_kv(&self, title: &str, items: &[(&str, String)]) {
140        if !self.quiet {
141            self.subsection(title);
142            for (key, value) in items {
143                println!("  {}: {}", key, value);
144            }
145        }
146    }
147
148    // Structured list output
149    pub fn list(&self, title: &str, items: &[String]) {
150        if !self.quiet {
151            self.subsection(title);
152            for (i, item) in items.iter().enumerate() {
153                println!("  {}. {}", i + 1, item);
154            }
155
156            if items.is_empty() {
157                println!("  (No items to display)");
158            }
159        }
160    }
161
162    /// Format file size in human-readable units
163    pub fn format_size(&self, bytes: u64) -> String {
164        if bytes < 1024 {
165            format!("{} B", bytes)
166        } else if bytes < 1024 * 1024 {
167            format!("{:.1} KB", bytes as f64 / 1024.0)
168        } else if bytes < 1024 * 1024 * 1024 {
169            format!("{:.1} MB", bytes as f64 / (1024.0 * 1024.0))
170        } else {
171            format!("{:.1} GB", bytes as f64 / (1024.0 * 1024.0 * 1024.0))
172        }
173    }
174
175    /// Format duration in human-readable format
176    pub fn format_duration(&self, duration: Duration) -> String {
177        let secs = duration.as_secs();
178        if secs < 60 {
179            format!("{}s", secs)
180        } else if secs < 3600 {
181            format!("{}m{}s", secs / 60, secs % 60)
182        } else {
183            format!("{}h{}m{}s", secs / 3600, (secs % 3600) / 60, secs % 60)
184        }
185    }
186
187    /// Format transfer speed in human-readable format
188    pub fn format_speed(&self, bytes_per_sec: u64) -> String {
189        format!("{}/s", self.format_size(bytes_per_sec))
190    }
191}