Skip to content

multi.println produces "dummy/ghost" progress bars #729

@crowbait

Description

@crowbait

I'm trying to run a few operations on files while "logging" the files using MultiProgress::println. This leads to unexpected results:

  8.01 MiB: SomeFile1.ext
Bytes copied: #####-----------------------   2.37 GiB /  69.64 GiB   ETA: 14m
  8.60 MiB: SomeFile2.ext
 17.33 MiB: SomeFile3.ext
Bytes copied: #####-----------------------   2.37 GiB /  69.64 GiB   ETA: 14m       
▹▹▹ SomeFile4.ext
Copying: ===> 

The last three lines (and the two log entries before that) are completely fine, but, as you can see, there are "copies" of the progress bar interleaved with the logged output. I'm calling them dummies or ghosts, for lack of a better word.
Because of excessive flickering, I've already done the following:

  • buffer log entries to some extend
  • throttle log prints

However, this still happens. I've noticed that it seems to be happening mostly when there are lots of files being processed quickly (eg. they are very small); for larger files, this seems to be working fine almost all the time.

// ...

  // Prepare buffer for file name logging, if enabled
  // `Task` is an externally defined type
  let mut filename_buffer: VecDeque<Task> = VecDeque::with_capacity(20);
  // Tracks the last time the buffer was flushed
  let mut last_filename_log = Instant::now();
  // Target buffer flushing interval
  let filename_log_interval = Duration::from_millis(500);

  // Little helper allows easy call to "flush buffer" from multiple locations
  let log_files = |buffer: &mut VecDeque<Task>| {
    for file in buffer.drain(..) {
      // For every buffered task, print it's size and relative path; both part of `Task`
      // `progress` is MultiProgress
      let _ = progress.println(format!(
        "{:>10}: {}",
        match &file {
          Task::Copy(task) => bytes_to_str(task.bytes).dimmed().bold(),
          Task::Delete(_) => "DEL".dimmed().bold()
        },
        file.relative().dimmed()
      ));
    }
    Instant::now()
  };

// ...

  for task in tasks {
    // If logging enabled at all AND interval is reached OR buffer is at capacity
    //   (don't want it to grow too large, this would hinder realtime readability
    //   and use needless memory), print all lines from buffer
    if args.log_files && (
      filename_buffer.len() >= 20 || 
      last_filename_log.elapsed() >= filename_log_interval
    ) { last_filename_log = log_files(&mut filename_buffer); }

// ...

Any help would be greatly appreciated; for me, multi::println would be a significant asset in my little project.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions