Skip to content

Commit d806231

Browse files
authored
tail: add --debug flag to show follow implementation mode (#10105)
* tail: add --debug flag to show follow implementation mode * tail: add tests for --debug flag output * fix formatting
1 parent 0b0ba60 commit d806231

4 files changed

Lines changed: 61 additions & 0 deletions

File tree

src/uu/tail/locales/en-US.ftl

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ tail-usage = tail [FLAG]... [FILE]...
66
77
# Help messages
88
tail-help-bytes = Number of bytes to print
9+
tail-help-debug = indicate which --follow implementation is used
910
tail-help-follow = Print the file as it grows
1011
tail-help-lines = Number of lines to print
1112
tail-help-pid = With -f, terminate after process ID, PID dies
@@ -70,3 +71,7 @@ tail-giving-up-on-this-name = ; giving up on this name
7071
tail-stdin-header = standard input
7172
tail-no-files-remaining = no files remaining
7273
tail-become-inaccessible = has become inaccessible
74+
75+
# Debug messages
76+
tail-debug-using-notification-mode = using notification mode
77+
tail-debug-using-polling-mode = using polling mode

src/uu/tail/src/args.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ pub mod options {
3838
pub const MAX_UNCHANGED_STATS: &str = "max-unchanged-stats";
3939
pub const ARG_FILES: &str = "files";
4040
pub const PRESUME_INPUT_PIPE: &str = "-presume-input-pipe"; // NOTE: three hyphens is correct
41+
pub const DEBUG: &str = "debug";
4142
}
4243

4344
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
@@ -139,6 +140,7 @@ pub struct Settings {
139140
pub use_polling: bool,
140141
pub verbose: bool,
141142
pub presume_input_pipe: bool,
143+
pub debug: bool,
142144
/// `FILE(s)` positional arguments
143145
pub inputs: Vec<Input>,
144146
}
@@ -155,6 +157,7 @@ impl Default for Settings {
155157
use_polling: Default::default(),
156158
verbose: Default::default(),
157159
presume_input_pipe: Default::default(),
160+
debug: Default::default(),
158161
inputs: Vec::default(),
159162
}
160163
}
@@ -223,6 +226,7 @@ impl Settings {
223226
mode: FilterMode::from(matches)?,
224227
verbose: matches.get_flag(options::verbosity::VERBOSE),
225228
presume_input_pipe: matches.get_flag(options::PRESUME_INPUT_PIPE),
229+
debug: matches.get_flag(options::DEBUG),
226230
..Default::default()
227231
};
228232

@@ -543,6 +547,12 @@ pub fn uu_app() -> Command {
543547
.overrides_with(options::FOLLOW_RETRY)
544548
.action(ArgAction::SetTrue),
545549
)
550+
.arg(
551+
Arg::new(options::DEBUG)
552+
.long(options::DEBUG)
553+
.help(translate!("tail-help-debug"))
554+
.action(ArgAction::SetTrue),
555+
)
546556
.arg(
547557
Arg::new(options::PRESUME_INPUT_PIPE)
548558
.long("presume-input-pipe")

src/uu/tail/src/tail.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,16 @@ fn uu_tail(settings: &Settings) -> UResult<()> {
7272
let mut observer = Observer::from(settings);
7373

7474
observer.start(settings)?;
75+
76+
// Print debug info about the follow implementation being used
77+
if settings.debug && settings.follow.is_some() {
78+
if observer.use_polling {
79+
show_error!("{}", translate!("tail-debug-using-polling-mode"));
80+
} else {
81+
show_error!("{}", translate!("tail-debug-using-notification-mode"));
82+
}
83+
}
84+
7585
// Do an initial tail print of each path's content.
7686
// Add `path` and `reader` to `files` map if `--follow` is selected.
7787
for input in &settings.inputs.clone() {

tests/by-util/test_tail.rs

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5065,3 +5065,39 @@ fn test_follow_stdout_pipe_close() {
50655065
child.close_stdout();
50665066
child.delay(2000).make_assertion().is_not_alive();
50675067
}
5068+
5069+
#[test]
5070+
fn test_debug_flag_with_polling() {
5071+
let ts = TestScenario::new(util_name!());
5072+
let at = &ts.fixtures;
5073+
at.touch("f");
5074+
5075+
let mut child = ts
5076+
.ucmd()
5077+
.args(&["--debug", "-f", "--use-polling", "f"])
5078+
.run_no_wait();
5079+
5080+
child.make_assertion_with_delay(500).is_alive();
5081+
child
5082+
.kill()
5083+
.make_assertion()
5084+
.with_all_output()
5085+
.stderr_contains("tail: using polling mode");
5086+
}
5087+
5088+
#[test]
5089+
#[cfg(target_os = "linux")]
5090+
fn test_debug_flag_with_inotify() {
5091+
let ts = TestScenario::new(util_name!());
5092+
let at = &ts.fixtures;
5093+
at.touch("f");
5094+
5095+
let mut child = ts.ucmd().args(&["--debug", "-f", "f"]).run_no_wait();
5096+
5097+
child.make_assertion_with_delay(500).is_alive();
5098+
child
5099+
.kill()
5100+
.make_assertion()
5101+
.with_all_output()
5102+
.stderr_contains("tail: using notification mode");
5103+
}

0 commit comments

Comments
 (0)