Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DynamicProgress does not work well when printing other logs at the same time #138

Closed
yczhang-nv opened this issue Oct 1, 2024 · 1 comment

Comments

@yczhang-nv
Copy link

yczhang-nv commented Oct 1, 2024

Currently I'm trying to use DynamicProgress along with my own logger, which outputs logs to the same terminal as the progress bars. I would like to let the DynamicProgress to always display as the last line of the output, so that it does not cover the log output.

I've looked into the method mentioned in #107 and #108, and it works well with one ProgressBar. But when I integrated the method with DynamicProgress, only a small portion of DynamicProgress show in the terminal.

Below is a code snippet that reproduces the issue:

#include <indicators/cursor_control.hpp>
#include <indicators/progress_bar.hpp>
#include <indicators/progress_spinner.hpp>
#include <indicators/dynamic_progress.hpp>
#include <boost/iostreams/filter/line.hpp>
#include <boost/iostreams/filtering_streambuf.hpp>
#include <vector>

int main() {
   using namespace indicators;
   struct LineInsertingFilter : boost::iostreams::line_filter
{
   std::string do_filter(const std::string& line)
   {
       return "\n\033[A\033[1L" + line;
   }
};
  auto* stdout_buf = std::cout.rdbuf();  // get stdout streambuf

  // create a filtering_ostreambuf with our filter and the stdout streambuf as a sink
  boost::iostreams::filtering_ostreambuf filtering_buf{};
  filtering_buf.push(LineInsertingFilter());
  filtering_buf.push(*stdout_buf);

  std::cout.rdbuf(&filtering_buf);  // configure std::cout to use our streambuf

  std::ostream os(stdout_buf);  // create local ostream acting as std::cout normally would

  auto bar1 = std::make_unique<ProgressBar>(
      option::BarWidth{50},
      option::ForegroundColor{Color::red},
      option::ShowElapsedTime{true},
      option::ShowRemainingTime{true},
      option::PrefixText{"5c90d4a2d1a8: Downloading "},
      indicators::option::FontStyles{std::vector<indicators::FontStyle>{indicators::FontStyle::bold}},
      option::Stream{os});

  auto bar2 = std::make_unique<ProgressBar>(
      option::BarWidth{50},
      option::ForegroundColor{Color::yellow},
      option::ShowElapsedTime{true},
      option::ShowRemainingTime{true},
      option::PrefixText{"22337bfd13a9: Downloading "},
      indicators::option::FontStyles{std::vector<indicators::FontStyle>{indicators::FontStyle::bold}},
      option::Stream{os});

  auto bar3 = std::make_unique<ProgressBar>(
      option::BarWidth{50},
      option::ForegroundColor{Color::green},
      option::ShowElapsedTime{true},
      option::ShowRemainingTime{true},
      option::PrefixText{"10f26c680a34: Downloading "},
      indicators::option::FontStyles{std::vector<indicators::FontStyle>{indicators::FontStyle::bold}},
      option::Stream{os});

  auto bar4 = std::make_unique<ProgressBar>(
      option::BarWidth{50},
      option::ForegroundColor{Color::white},
      option::ShowElapsedTime{true},
      option::ShowRemainingTime{true},
      option::PrefixText{"6364e0d7a283: Downloading "},
      indicators::option::FontStyles{std::vector<indicators::FontStyle>{indicators::FontStyle::bold}},
      option::Stream{os});

  auto bar5 = std::make_unique<ProgressBar>(
      option::BarWidth{50},
      option::ForegroundColor{Color::blue},
      option::ShowElapsedTime{true},
      option::ShowRemainingTime{true},
      option::PrefixText{"ff1356ba118b: Downloading "},
      indicators::option::FontStyles{std::vector<indicators::FontStyle>{indicators::FontStyle::bold}},
      option::Stream{os});

  auto bar6 = std::make_unique<ProgressBar>(
      option::BarWidth{50},
      option::ForegroundColor{Color::cyan},
      option::ShowElapsedTime{true},
      option::ShowRemainingTime{true},
      option::PrefixText{"5a17453338b4: Downloading "},
      indicators::option::FontStyles{std::vector<indicators::FontStyle>{indicators::FontStyle::bold}},
      option::Stream{os});

  std::cout << termcolor::bold << termcolor::white << "Pulling image foo:bar/baz\n";

  // Construct with 3 progress bars. We'll add 3 more at a later point
  DynamicProgress<ProgressBar> bars(bar1, bar2, bar3);

  // Do not hide bars when completed
  bars.set_option(option::HideBarWhenComplete{false});

  std::thread fourth_job, fifth_job, sixth_job;

  auto job4 = [&bars](size_t i) {
      while (true)
      {
          bars[i].tick();
          if (bars[i].is_completed())
          {
              bars[i].set_option(option::PrefixText{"6364e0d7a283: Pull complete "});
              bars[i].mark_as_completed();
              break;
          }
          std::this_thread::sleep_for(std::chrono::milliseconds(50));
      }
  };

  auto job5 = [&bars](size_t i) {
      while (true)
      {
          bars[i].tick();
          if (bars[i].is_completed())
          {
              bars[i].set_option(option::PrefixText{"ff1356ba118b: Pull complete "});
              bars[i].mark_as_completed();
              break;
          }
          std::this_thread::sleep_for(std::chrono::milliseconds(100));
      }
  };

  auto job6 = [&bars](size_t i) {
      while (true)
      {
          bars[i].tick();
          if (bars[i].is_completed())
          {
              bars[i].set_option(option::PrefixText{"5a17453338b4: Pull complete "});
              bars[i].mark_as_completed();
              break;
          }
          std::this_thread::sleep_for(std::chrono::milliseconds(40));
      }
  };

  auto job1 = [&bars, &bar6, &sixth_job, &job6]() {
      while (true)
      {
          bars[0].tick();
          if (bars[0].is_completed())
          {
              bars[0].set_option(option::PrefixText{"5c90d4a2d1a8: Pull complete "});
              // bar1 is completed, adding bar6
              auto i    = bars.push_back(std::move(bar6));
              sixth_job = std::thread(job6, i);
              sixth_job.join();
              break;
          }
          std::this_thread::sleep_for(std::chrono::milliseconds(140));
      }
  };

  auto job2 = [&bars, &bar5, &fifth_job, &job5]() {
      while (true)
      {
          bars[1].tick();
          if (bars[1].is_completed())
          {
              bars[1].set_option(option::PrefixText{"22337bfd13a9: Pull complete "});
              // bar2 is completed, adding bar5
              auto i    = bars.push_back(std::move(bar5));
              fifth_job = std::thread(job5, i);
              fifth_job.join();
              break;
          }
          std::this_thread::sleep_for(std::chrono::milliseconds(25));
      }
  };

  auto job3 = [&bars, &bar4, &fourth_job, &job4]() {
      while (true)
      {
          bars[2].tick();
          if (bars[2].is_completed())
          {
              bars[2].set_option(option::PrefixText{"10f26c680a34: Pull complete "});
              // bar3 is completed, adding bar4
              auto i     = bars.push_back(std::move(bar4));
              fourth_job = std::thread(job4, i);
              fourth_job.join();
              break;
          }
          std::this_thread::sleep_for(std::chrono::milliseconds(50));
      }
  };

  std::thread first_job(job1);
  std::thread second_job(job2);
  std::thread third_job(job3);

  third_job.join();
  second_job.join();
  first_job.join();

 return 0;
}

And the progress bar looks like this (there should be 6 bars in total, but only one of them are displaying):

Screenshot from 2024-10-01 09-31-35

I'll appreciate any helps to get this to work.

@yczhang-nv
Copy link
Author

yczhang-nv commented Oct 9, 2024

The blocker for this is the DynamicProgress is hard coded to output to std::cout, which is mentioned in #123 . The workaround in #107 can work with multiple progress bars by re-implementing the print_progress() function of DynamicProgress by redirecting the output to the customized ostream.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant