History

implement progress trait for logs with throttling

Sebastian Thiel committed 6 years ago

Commit 287eca91 parent e82e63f5 files · +121 −6Browse files

Showing the changes to git-features/src (1 of 5 files). Show all

Unified · Split

git-features/src/progress.rs+103−5
@@ -1,8 +1,21 @@
1+/// The severity of a message
2+#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
3+pub enum MessageLevel {
4+ /// Rarely sent information related to the progress, not to be confused with the progress itself
5+ Info,
6+ /// Used to indicate that a task has failed, along with the reason
7+ Failure,
8+ /// Indicates a task was completed successfully
9+ Success,
10+}
11+
112 pub trait Progress {
13+ type SubProgress: Progress;
14+
215 /// Adds a new child, whose parent is this instance, with the given name.
316 ///
417 /// This will make the child progress to appear contained in the parent progress.
5− fn add_child(&self, name: impl Into<String>) -> Self;
18+ fn add_child(&mut self, name: impl Into<String>) -> Self::SubProgress;
619
720 /// Initialize the Item for receiving progress information.
821 ///
@@ -19,15 +32,100 @@ pub trait Progress { · 10 unmodified lines
1932 /// **Note** that this method can be called multiple times, changing the bounded-ness and unit at will.
2033 fn init(&mut self, max: Option<u32>, unit: Option<&'static str>);
2134
22− /// Set the current progress to the given `step`.
35+ /// Set the current progress to the given `step`. The cost of this call is negligible,
36+ /// making manual throttling *not* necessary.
2337 ///
2438 /// **Note**: that this call has no effect unless `init(…)` was called before.
2539 fn set(&mut self, step: u32);
2640
41+ /// Create a `message` of the given `level` and store it with the progress tree.
42+ ///
43+ /// Use this to provide additional,human-readable information about the progress
44+ /// made, including indicating success or failure.
45+ fn message(&self, level: MessageLevel, message: impl Into<String>);
46+
2747 /// Create a message providing additional information about the progress thus far.
28− fn info(&self, name: impl Into<String>) -> Self;
48+ fn info(&self, message: impl Into<String>) {
49+ self.message(MessageLevel::Info, message)
50+ }
2951 /// Create a message indicating the task is done successfully
30− fn done(&self, name: impl Into<String>) -> Self;
52+ fn done(&self, message: impl Into<String>) {
53+ self.message(MessageLevel::Success, message)
54+ }
3155 /// Create a message indicating the task failed
32− fn fail(&self, name: impl Into<String>) -> Self;
56+ fn fail(&self, message: impl Into<String>) {
57+ self.message(MessageLevel::Failure, message)
58+ }
59+}
60+
61+#[cfg(feature = "progress-log")]
62+mod log {
63+ use crate::progress::{MessageLevel, Progress};
64+ use std::time::Duration;
65+
66+ pub struct LogProgress {
67+ name: String,
68+ max: Option<u32>,
69+ unit: Option<&'static str>,
70+ last_set: Option<std::time::SystemTime>,
71+ }
72+
73+ const EMIT_LOG_EVERY_S: f32 = 0.5;
74+
75+ impl LogProgress {
76+ pub fn new(name: impl Into<String>) -> Self {
77+ LogProgress {
78+ name: name.into(),
79+ max: None,
80+ unit: None,
81+ last_set: None,
82+ }
83+ }
84+ }
85+
86+ impl Progress for LogProgress {
87+ type SubProgress = LogProgress;
88+
89+ fn add_child(&mut self, name: impl Into<String>) -> Self::SubProgress {
90+ LogProgress::new(format!("{}::{}", self.name, Into::<String>::into(name)))
91+ }
92+
93+ fn init(&mut self, max: Option<u32>, unit: Option<&'static str>) {
94+ self.max = max;
95+ self.unit = unit;
96+ }
97+
98+ fn set(&mut self, step: u32) {
99+ let now = std::time::SystemTime::now();
100+ let last = self.last_set.unwrap_or(now);
101+ if now
102+ .duration_since(last)
103+ .unwrap_or_else(|_| Duration::default())
104+ .as_secs_f32()
105+ > EMIT_LOG_EVERY_S
106+ {
107+ match (self.max, self.unit) {
108+ (Some(max), Some(unit)) => {
109+ log::info!("{} → {} / {} {}", self.name, step, max, unit)
110+ }
111+ (None, Some(unit)) => log::info!("{} → {} {}", self.name, step, unit),
112+ (Some(max), None) => log::info!("{} → {} / {}", self.name, step, max),
113+ (None, None) => log::info!("{} → {}", self.name, step),
114+ }
115+ }
116+ self.last_set = Some(now);
117+ }
118+
119+ fn message(&self, level: MessageLevel, message: impl Into<String>) {
120+ let message: String = message.into();
121+ match level {
122+ MessageLevel::Info => log::info!("ℹ{} → {}", self.name, message),
123+ MessageLevel::Failure => log::error!("𐄂{} → {}", self.name, message),
124+ MessageLevel::Success => log::info!("✓{} → {}", self.name, message),
125+ }
126+ }
127+ }
33128 }
129+
130+#[cfg(feature = "progress-log")]
131+pub use self::log::LogProgress;