ReUseX  0.0.1
3D Point Cloud Processing for Building Reuse
Loading...
Searching...
No Matches
spdmon.hpp
Go to the documentation of this file.
1// SPDX-FileCopyrightText: 2025 Povl Filip Sonne-Frederiksen
2//
3// SPDX-License-Identifier: MIT
4
5#pragma once
6#include <array>
7#include <atomic>
8#include <fmt/core.h>
9#include <iostream>
10#include <iterator>
11#include <list>
12#include <memory>
13#include <mutex>
14#include <string>
15
16#include <spdlog/common.h>
17#include <spdlog/details/console_globals.h>
18#include <spdlog/details/null_mutex.h>
19#include <spdlog/details/os.h>
20#include <spdlog/fmt/chrono.h>
21#include <spdlog/pattern_formatter.h>
22#include <spdlog/sinks/ansicolor_sink.h>
23#include <spdlog/sinks/basic_file_sink.h>
24#include <spdlog/sinks/sink.h>
25#include <spdlog/sinks/stdout_sinks.h>
26#include <spdlog/spdlog.h>
27
28/*
29 * Check if system is Windows
30 */
31#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__)
32#error Progress sink only work on Linux platform
33#else
34#include <signal.h>
35#include <sys/ioctl.h>
36#include <unistd.h>
37#endif
38
39namespace spdmon {
40/*
41 * This is a short macro for deleting a class's copy constructor and
42 * copy assignment operator.
43 */
44#define SPDMON_DECLARE_NON_COPYABLE(classInst) \
45 classInst(const classInst &other) = delete; \
46 classInst &operator=(const classInst &other) = delete;
47
48/*
49 * This is a short macro for deleting a class's move constructor and
50 * move assignment operator.
51 */
52#define SPDMON_DECLARE_NON_MOVEABLE(classInst) \
53 classInst(classInst &&other) noexcept = delete; \
54 classInst &operator=(classInst &&other) noexcept = delete;
55
56/*
57 * This is a short macro for declaring class's default copy constructor and
58 * move assignment operator.
59 */
60#define SPDMON_DECLARE_DEFAULT_COPYABLE(classInst) \
61 classInst(const classInst &other) = default; \
62 classInst &operator=(const classInst &other) = default;
63
64/*
65 * This is a short macro for declaring class's default move constructor and
66 * move assignment operator.
67 */
68#define SPDMON_DECLARE_DEFAULT_MOVEABLE(classInst) \
69 classInst(classInst &&other) noexcept = default; \
70 classInst &operator=(classInst &&other) noexcept = default;
71
72/*
73 * Bar symbols coded in unicode used for displaying spdmon
74 */
75static const char *kBarSymsUnicode[] = {" ",
76 "\xE2\x96\x8F",
77 "\xE2\x96\x8E",
78 "\xE2\x96\x8D",
79 "\xE2\x96\x8C",
80 "\xE2\x96\x8B",
81 "\xE2\x96\x8A",
82 "\xE2\x96\x89",
83 "\xE2\x96\x88"};
84
85/*
86 * Bar symbols coded in ascii used for displaying spdmon
87 */
88static const char *kBarSymsAscii[] = {" ", "0", "1", "2", "3", "4",
89 "5", "6", "7", "8", "9", "#"};
90
91/*
92 * Abstract base rendering spdmon bar
93 * needs ShowProgress() filled in
94 */
96 public:
97 using clock_t = std::chrono::steady_clock;
98 using timepoint_t = clock_t::time_point;
99 using duration_t = clock_t::duration;
100
101 explicit BaseProgress(std::string desc = "", unsigned int total = 0,
102 bool ascii = false)
103 : total_(total), desc_(desc),
104 bar_syms_(ascii ? kBarSymsAscii : kBarSymsUnicode),
105 nsyms_(ascii ? std::extent<decltype(kBarSymsAscii)>::value
106 : std::extent<decltype(kBarSymsUnicode)>::value) {}
107
108 virtual ~BaseProgress() = default;
109
110 void Restart(std::string desc = "", unsigned int total = 0) {
111 n_ = 0;
112 total_ = total;
113 desc_ = desc;
114 ShowProgress();
115 }
116
117 unsigned int Count() { return n_; }
118
120 Update();
121 return *this;
122 }
123
124 void operator+=(unsigned int n) { Update(n); }
125
126 void SetTotal(unsigned int n) { total_ = n; }
127
128 unsigned int Size() { return total_; }
129
130 void FormatBarTo(fmt::memory_buffer &buf, unsigned int width, float frac) {
131 if (width == 0) {
132 return;
133 }
134
135 buf.reserve(buf.size() + width * 3);
136 auto it = fmt::appender(buf);
137
138 const auto complete =
139 static_cast<unsigned int>(frac * static_cast<float>(width * nsyms_));
140 const size_t full_blocks = complete / nsyms_;
141 const size_t frac_block = complete % nsyms_;
142 size_t fill_length = width - full_blocks;
143
144 // fmt::format_to(it, "{:^9}", fmt::format("{:.2f}%", frac * 100));
145
146 auto append_n = [&](size_t n, size_t idx) {
147 size_t len_sym = strlen(bar_syms_[idx]);
148 if (len_sym == 1) {
149 std::fill_n(it, n, bar_syms_[idx][0]);
150 // fmt::detail::fill_n(it, n, bar_syms_[idx][0]);
151 } else {
152 for (size_t i = 0; i < n; i++)
153 std::copy_n(bar_syms_[idx], len_sym, it);
154 }
155 };
156
157 append_n(full_blocks, nsyms_ - 1);
158 if (frac_block > 0) {
159 append_n(1, frac_block);
160 --fill_length;
161 }
162 append_n(fill_length, 0);
163 }
164
165 void Update(unsigned int n = 1) {
166 n_ += n;
167 if (n_ == total_) {
168 std::lock_guard<std::mutex> lock(mutex_);
169 ShowProgress();
170 return;
171 }
172 if (n_ >= last_print_n_ + miniterations_) {
173 timepoint_t now = clock_t::now();
174 duration_t delta_time = now - last_update_;
175 if (delta_time > mininterval_) {
176 std::lock_guard<std::mutex> lock(mutex_);
177 last_update_ = now;
178 miniterations_ = (n_.load() - last_print_n_) *
179 static_cast<unsigned int>(mininterval_ / delta_time);
180 ShowProgress(now);
181 }
182 }
183 }
184
185 void RenderProgress(timepoint_t now, unsigned int width,
186 fmt::memory_buffer &buf) {
187
188 // std::cout << "Width Inside: " << width << std::endl;
189 // std::cout << std::endl;
190 last_print_n_ = n_;
191 const auto elapsed = now - started_at_;
192
193 if (total_ == 0) {
194 fmt::format_to(fmt::appender(buf), kNoTotalFmt, fmt::arg("desc", desc_),
195 fmt::arg("n", n_.load()), fmt::arg("elapsed", elapsed),
196 fmt::arg("eol", kTermEol));
197 return;
198 }
199
200 const float frac =
201 static_cast<float>(n_.load()) / static_cast<float>(total_);
202 // auto eta = elapsed * (1 / frac - 1);
203 const auto remaining =
204 (frac > 0) ? elapsed * (1 / frac - 1) : duration_t(0);
205
206 const float speed =
207 static_cast<float>(n_.load()) /
208 std::chrono::duration_cast<std::chrono::seconds>(elapsed).count();
209
210 fmt::memory_buffer right;
211
212 const float percent = frac * 100;
213 fmt::format_to(fmt::appender(buf), kLbarFmt, fmt::arg("desc", desc_),
214 fmt::arg("frac", percent));
215 fmt::format_to(fmt::appender(right), kRbarFmt, fmt::arg("n", n_.load()),
216 fmt::arg("total", total_), fmt::arg("elapsed", elapsed),
217 fmt::arg("remaining", remaining), fmt::arg("eol", kTermEol),
218 fmt::arg("speed", speed));
219
220 const auto space_for_bar =
221 static_cast<int>(width - buf.size() - right.size() + kTermEol.size());
222 if (space_for_bar > 0) { // Check for underflow (negative width)
223 FormatBarTo(buf, space_for_bar, frac);
224 }
225 buf.reserve(buf.size() + right.size());
226 std::copy(right.begin(), right.end(), std::back_inserter(buf));
227 }
228
229 virtual void ShowProgress(timepoint_t now = clock_t::now()) = 0;
230
231 private:
232 std::atomic<unsigned int> n_{0};
233 unsigned int last_print_n_{0};
234 unsigned int total_{0};
235 std::string desc_{""};
236 const char **bar_syms_{nullptr};
237 unsigned int nsyms_{0};
238 timepoint_t started_at_{clock_t::now()};
239 timepoint_t last_update_{std::chrono::seconds(0)};
240 duration_t mininterval_{std::chrono::milliseconds(10)};
241 unsigned int miniterations_{1};
242 std::string bar_tpl_{""};
243 std::mutex mutex_;
244
245 static constexpr std::string_view kTermEraseLine = "\x1B[0K";
246 static constexpr std::string_view kTermEol = "\n";
247 static constexpr std::string_view kLbarFmt = "{desc}: {frac:3.0f}%|";
248 // static constexpr std::string_view kRbarFmt =
249 // "| {n}/{total} [{elapsed:%T} / {remaining:%T}]{eol}";
250 static constexpr std::string_view kRbarFmt =
251 "| {n}/{total} [{elapsed:.3%T}<{remaining:.3%T}, {speed:.2f}it/s]{eol}";
252 static constexpr std::string_view kNoTotalFmt =
253 "{desc}: {n} [{elapsed:%T}]{eol}";
254};
255
256/* Progress monitor writing directly to a file */
257class Progress final : public BaseProgress {
258 public:
259 explicit Progress(std::string desc = "", unsigned int total = 0,
260 bool ascii = false, FILE *file = stderr,
261 unsigned int width = 0)
262 : BaseProgress(desc, total, ascii), width_(width), file_(file)
263
264 {
265 if (width_ == 0) {
267 }
268 }
269
270 ~Progress() override = default;
271
274
276 int fd = fileno(file_);
277 struct winsize size;
278 if (ioctl(fd, TIOCGWINSZ, &size) == 0) {
279 width_ = size.ws_col;
280 }
281 }
282
283 void ShowProgress(timepoint_t now = clock_t::now()) final {
284 // called from BaseProgress when it decided the spdmon bar needs
285 // to be printed again
286 fmt::memory_buffer buf;
287 RenderProgress(now, width_, buf);
288 std::copy(kTermMoveUp.begin(), kTermMoveUp.end(), std::back_inserter(buf));
289 fwrite(buf.data(), 1, buf.size(), file_);
290 fflush(file_);
291 }
292
293 const std::string kTermMoveUp = "\x1B[A";
294
295 private:
296 unsigned int width_;
297 FILE *file_;
298};
299
300class StatusLine;
301
303 public:
304 StatusLineRegistry() { status_lines_.reserve(20); }
305
306 virtual ~StatusLineRegistry() = default;
307
310
311 void AddStatusLine(StatusLine *msg) { status_lines_.push_back(msg); }
313 status_lines_.erase(
314 std::remove(status_lines_.begin(), status_lines_.end(), msg),
315 status_lines_.end());
316 }
317 const std::vector<StatusLine *> &GetStatusLines() { return status_lines_; }
318
319 virtual void PrintStatusLineRegistry() = 0;
320
321 private:
322 std::vector<StatusLine *> status_lines_ = {};
323 int change_since_last_print_{0};
324};
325
327 public:
328 explicit StatusLine(spdlog::level::level_enum level) : level_(level) {}
329
330 virtual ~StatusLine() {
331 if (logger_.get() == nullptr)
332 return;
333
334 /* on deletion, deregister from all sinks */
335 for (auto &sink : logger_->sinks()) {
336 auto ptr = dynamic_cast<StatusLineRegistry *>(sink.get());
337 if (ptr) {
338 ptr->RemoveStatusLine(this);
339 }
340 }
341 }
342
345
346 void RegisterSinks(std::shared_ptr<spdlog::logger> logger) {
347 logger_ = logger;
348 /* on creation, register it with all sinks that understand about us */
349 for (auto &sink : logger_->sinks()) {
350 auto ptr = dynamic_cast<StatusLineRegistry *>(sink.get());
351 if (ptr) {
352 ptr->AddStatusLine(this);
353 }
354 }
355 }
356
357 /* trigger (re)print of this status line */
359 for (const auto &sink : logger_->sinks()) {
360 if (sink->should_log(GetLevel())) {
361 auto ptr = dynamic_cast<StatusLineRegistry *>(sink.get());
362 if (ptr) {
363 ptr->PrintStatusLineRegistry();
364 }
365 }
366 }
367 }
368
369 virtual void RenderStatusLine(fmt::memory_buffer &buf,
370 unsigned int width) = 0;
371
372 static const char *MagicFilename() {
373 static const char *file = "PROGRESS MONITOR";
374 return file;
375 }
376
377 bool ShouldLog() { return logger_->should_log(level_); }
378
379 spdlog::level::level_enum GetLevel() { return level_; }
380
381 void SendLogMsg(fmt::memory_buffer &buf) {
382 spdlog::source_loc loc;
383 loc.filename = MagicFilename();
384 spdlog::details::log_msg msg{loc, logger_->name(), level_,
385 spdlog::string_view_t{buf.data(), buf.size()}};
386 for (const auto &sink : logger_->sinks()) {
387 if (sink->should_log(GetLevel())) {
388 sink->log(msg);
389 }
390 }
391 }
392
393 private:
394 std::shared_ptr<spdlog::logger> logger_{nullptr};
395 spdlog::level::level_enum level_{spdlog::level::off};
396};
397
399 public:
402
403 protected:
404 explicit SigwinchMixin(bool install) {
405 if (install) {
406 InstallHandler();
407 }
408 Instances().push_back(this);
409 }
410
411 virtual ~SigwinchMixin() { Instances().remove(this); }
412
413 inline bool CheckGotSigwinch() {
414 if (GotSigwinch() != 0) {
415 GotSigwinch() = 0;
416 NotifyInstances();
417 }
418 if (needs_update_ > 0) {
419 needs_update_ = 0;
420 return true;
421 }
422 return false;
423 }
424
425 private:
426 static sig_atomic_t &GotSigwinch() {
427 static sig_atomic_t flag;
428 return flag;
429 }
430
431 static std::list<SigwinchMixin *> &Instances() {
432 static std::list<SigwinchMixin *> list;
433 return list;
434 }
435
436 static void HandleSigwinch(int) { GotSigwinch() = 1; }
437
438 static void InstallHandler() {
439 struct sigaction sa;
440 memset(&sa, 0, sizeof(sa));
441 if (sigaction(SIGWINCH, nullptr, &sa)) {
442 return; // failed
443 }
444 if (sa.sa_handler == HandleSigwinch) {
445 return; // already installed
446 }
447 memset(&sa, 0, sizeof(sa));
448 sa.sa_handler = HandleSigwinch;
449 sigfillset(&sa.sa_mask); // block other signals during handler
450 if (sigaction(SIGWINCH, &sa, nullptr)) {
451 return; // failed
452 }
453 }
454
455 static void NotifyInstances() {
456 // std::lock_guard<mutex_t> lock(log_sink::mutex_);
457 for (auto &instance : Instances()) {
458 instance->needs_update_ = true;
459 }
460 }
461
462 std::atomic_bool needs_update_{false};
463};
464
465template <class ConsoleMutex>
466class TerminalSink final : public spdlog::sinks::ansicolor_sink<ConsoleMutex>,
467 public StatusLineRegistry,
468 public SigwinchMixin {
469 public:
470 using log_sink = spdlog::sinks::ansicolor_sink<ConsoleMutex>;
471 using mutex_t = typename ConsoleMutex::mutex_t;
472
474 : log_sink(stdout, spdlog::color_mode::automatic),
475 SigwinchMixin(log_sink::should_color()) {
476 if (log_sink::should_color()) {
478 }
479 }
480
481 ~TerminalSink() final = default;
482
485
486 // normal log message coming in
487 void log(const spdlog::details::log_msg &msg) final { Print(&msg); }
488
489 // Update to status coming in
490 void PrintStatusLineRegistry() final { Print(nullptr); }
491
492 void Print(const spdlog::details::log_msg *msg) {
493 if (not log_sink::should_color()) { // not a tty
494 if (msg != nullptr) { // got a msg
495 log_sink::log(*msg); // pass it upstream
496 }
497 return;
498 }
499
500 if (CheckGotSigwinch()) {
502 }
503
504 // render status lines
505 fmt::memory_buffer status_text;
506 unsigned int nlines = 0;
507 for (const auto line : GetStatusLines()) {
508 if (log_sink::should_log(line->GetLevel())) {
509 line->RenderStatusLine(status_text, ncols_);
510 ++nlines;
511 }
512 }
513
514 // move back up to last log line
515 std::lock_guard<mutex_t> lock(this->mutex_);
516 for (unsigned int i = 0; i < last_status_lines_; ++i) {
517 fwrite(kTermMoveUp.data(), 1, kTermMoveUp.size(), stdout);
518 }
519 last_status_lines_ = nlines;
520
521 // print message if we have one and it's not an update for other sinks
522 if (msg != nullptr && msg->source.filename != StatusLine::MagicFilename()) {
523 fwrite(term_clear_line.data(), 1, term_clear_line.size(), stdout);
524 log_sink::log(*msg);
525 }
526
527 fwrite(status_text.data(), 1, status_text.size(), stdout);
528 fflush(stdout);
529 }
530
532 int fd = fileno(stdout);
533 struct winsize size;
534 if (ioctl(fd, TIOCGWINSZ, &size) == 0) {
535 // std::lock_guard<mutex_t> lock(log_sink::mutex_);
536 std::lock_guard<mutex_t> lock(this->mutex_);
537 ncols_ = size.ws_col;
538 }
539 }
540
541 const std::string kTermMoveUp = "\x1B[A";
542 const std::string term_clear_line = "\x1B[K";
543
544 private:
545 unsigned int ncols_{60};
546 unsigned int last_status_lines_{0};
547 mutex_t mutex_;
548};
549
556
557template <typename Factory = spdlog::default_factory>
558inline std::shared_ptr<spdlog::logger>
559stdout_terminal_mt(const std::string &logger_name) {
560 return Factory::template create<terminal_stdout_sink_mt>(logger_name);
561}
562
563template <typename Factory = spdlog::default_factory>
564inline std::shared_ptr<spdlog::logger>
565stderr_terminal_mt(const std::string &logger_name) {
566 return Factory::template create<terminal_stderr_sink_mt>(logger_name);
567}
568
569template <typename Factory = spdlog::default_factory>
570inline std::shared_ptr<spdlog::logger>
571stdout_terminal_st(const std::string &logger_name) {
572 return Factory::template create<terminal_stdout_sink_st>(logger_name);
573}
574template <typename Factory = spdlog::default_factory>
575inline std::shared_ptr<spdlog::logger>
576stderr_terminal_st(const std::string &logger_name) {
577 return Factory::template create<terminal_stderr_sink_st>(logger_name);
578}
579
580#define IS_ONE_OF_TYPE(sink) \
581 (typeid(*(sink)) == typeid(spdlog::sinks::stdout_sink_st)) || \
582 (typeid(*(sink)) == typeid(spdlog::sinks::stdout_sink_mt)) || \
583 (typeid(*(sink)) == typeid(spdlog::sinks::ansicolor_stdout_sink_st)) || \
584 (typeid(*(sink)) == typeid(spdlog::sinks::ansicolor_stdout_sink_mt))
585
587 public:
588 explicit LoggerProgress(std::shared_ptr<spdlog::logger> logger,
589 std::string desc = "", unsigned int total = 0,
590 bool ascii = false, unsigned int /*width*/ = 0,
591 spdlog::level::level_enum level = spdlog::level::warn)
592 : BaseProgress(desc, total, ascii), StatusLine(level) {
593 auto progress_logger = std::make_shared<spdmon::terminal_stdout_sink_mt>();
594
595 std::vector<spdlog::sink_ptr> sinks;
596 for (const auto &sink : logger->sinks()) {
597 if (not(IS_ONE_OF_TYPE(sink))) {
598 sinks.push_back(sink);
599 }
600 }
601 sinks.push_back(progress_logger);
602 custom_logger_ =
603 std::make_shared<spdlog::logger>(desc, sinks.begin(), sinks.end());
604
605 default_logger_ = spdlog::default_logger();
606 spdlog::set_default_logger(custom_logger_);
607 StatusLine::RegisterSinks(custom_logger_);
608 }
609
610 explicit LoggerProgress(std::string desc = "", unsigned int total = 0,
611 bool ascii = false, unsigned int /*width*/ = 0,
612 spdlog::level::level_enum level = spdlog::level::warn)
613 : BaseProgress(desc, total, ascii), StatusLine(level) {
614 default_logger_ = spdlog::default_logger();
615 custom_logger_ = spdmon::stdout_terminal_mt(desc);
616 custom_logger_->set_pattern(
617 "[%Y-%m-%d %H:%M:%S.%e] [%n] [%=8t] [%^%=7l%$] %v");
618 custom_logger_->set_level(spdlog::get_level());
619 spdlog::set_default_logger(custom_logger_);
620 StatusLine::RegisterSinks(custom_logger_);
621 }
622
624 spdlog::set_default_logger(default_logger_);
625 spdlog::drop(custom_logger_->name());
626 };
627
630
631 void ShowProgress(timepoint_t now = clock_t::now()) final {
632 if (!ShouldLog()) {
633 // early quit if our logger has loglevel below ourselves
634 return;
635 }
636 const duration_t delta_time = now - last_update_;
638 if (delta_time > mininterval_) {
639 last_update_ = now;
640
641 fmt::memory_buffer buf;
642 BaseProgress::RenderProgress(now, 60, buf);
644 }
645 }
646
647 void RenderStatusLine(fmt::memory_buffer &buf, unsigned int width) final {
648 BaseProgress::RenderProgress(clock_t::now(), width, buf);
649 }
650
651 std::shared_ptr<spdlog::logger> GetLogger() { return this->custom_logger_; }
652
653 private:
654 timepoint_t last_update_{std::chrono::seconds(0)};
655 duration_t mininterval_{std::chrono::milliseconds(500)};
656 std::shared_ptr<spdlog::logger> default_logger_{nullptr};
657 std::shared_ptr<spdlog::logger> custom_logger_{nullptr};
658};
659
660template <typename Iterable> class IterableProgressMonitor {
661 private:
662 std::shared_ptr<LoggerProgress> progress_logger_;
663 Iterable iter_;
664 std::size_t size_;
665 decltype(std::begin(iter_)) begin_;
666 const decltype(std::end(iter_)) end_;
667
668 public:
669 IterableProgressMonitor(Iterable iter, std::string name = "Progress logger")
670 : iter_(iter), size_(0), begin_(std::begin(iter)), end_(std::end(iter)) {
671 progress_logger_ =
672 std::make_shared<LoggerProgress>(name, std::distance(begin_, end_));
673 }
674
675 const IterableProgressMonitor &begin() const { return *this; }
676
677 const IterableProgressMonitor &end() const { return *this; }
678
680 return begin_ != end_;
681 }
682
683 void operator++() {
684 ++(*progress_logger_);
685 ++begin_;
686 ++size_;
687 }
688
689 auto operator*() const
690 -> std::pair<std::shared_ptr<spdlog::logger>, decltype(*begin_)> {
691 return {progress_logger_->GetLogger(), *begin_};
692 }
693};
694
695template <typename Iterable>
697 return {std::forward<Iterable>(iter)};
698}
699} // namespace spdmon
clock_t::duration duration_t
Definition spdmon.hpp:99
void operator+=(unsigned int n)
Definition spdmon.hpp:124
void SetTotal(unsigned int n)
Definition spdmon.hpp:126
void FormatBarTo(fmt::memory_buffer &buf, unsigned int width, float frac)
Definition spdmon.hpp:130
virtual void ShowProgress(timepoint_t now=clock_t::now())=0
std::chrono::steady_clock clock_t
Definition spdmon.hpp:97
virtual ~BaseProgress()=default
void RenderProgress(timepoint_t now, unsigned int width, fmt::memory_buffer &buf)
Definition spdmon.hpp:185
void Update(unsigned int n=1)
Definition spdmon.hpp:165
BaseProgress(std::string desc="", unsigned int total=0, bool ascii=false)
Definition spdmon.hpp:101
void Restart(std::string desc="", unsigned int total=0)
Definition spdmon.hpp:110
unsigned int Size()
Definition spdmon.hpp:128
BaseProgress & operator++()
Definition spdmon.hpp:119
clock_t::time_point timepoint_t
Definition spdmon.hpp:98
unsigned int Count()
Definition spdmon.hpp:117
const IterableProgressMonitor & begin() const
Definition spdmon.hpp:675
bool operator!=(const IterableProgressMonitor &) const
Definition spdmon.hpp:679
const IterableProgressMonitor & end() const
Definition spdmon.hpp:677
auto operator*() const -> std::pair< std::shared_ptr< spdlog::logger >, decltype(*begin_)>
Definition spdmon.hpp:689
IterableProgressMonitor(Iterable iter, std::string name="Progress logger")
Definition spdmon.hpp:669
LoggerProgress(std::shared_ptr< spdlog::logger > logger, std::string desc="", unsigned int total=0, bool ascii=false, unsigned int=0, spdlog::level::level_enum level=spdlog::level::warn)
Definition spdmon.hpp:588
void RenderStatusLine(fmt::memory_buffer &buf, unsigned int width) final
Definition spdmon.hpp:647
void ShowProgress(timepoint_t now=clock_t::now()) final
Definition spdmon.hpp:631
std::shared_ptr< spdlog::logger > GetLogger()
Definition spdmon.hpp:651
LoggerProgress(std::string desc="", unsigned int total=0, bool ascii=false, unsigned int=0, spdlog::level::level_enum level=spdlog::level::warn)
Definition spdmon.hpp:610
void UpdateTermWidth()
Definition spdmon.hpp:275
~Progress() override=default
const std::string kTermMoveUp
Definition spdmon.hpp:293
void ShowProgress(timepoint_t now=clock_t::now()) final
Definition spdmon.hpp:283
Progress(std::string desc="", unsigned int total=0, bool ascii=false, FILE *file=stderr, unsigned int width=0)
Definition spdmon.hpp:259
virtual ~SigwinchMixin()
Definition spdmon.hpp:411
SigwinchMixin(const SigwinchMixin &other)=delete
const std::vector< StatusLine * > & GetStatusLines()
Definition spdmon.hpp:317
void AddStatusLine(StatusLine *msg)
Definition spdmon.hpp:311
virtual ~StatusLineRegistry()=default
void RemoveStatusLine(StatusLine *msg)
Definition spdmon.hpp:312
virtual void PrintStatusLineRegistry()=0
virtual ~StatusLine()
Definition spdmon.hpp:330
static const char * MagicFilename()
Definition spdmon.hpp:372
StatusLine(spdlog::level::level_enum level)
Definition spdmon.hpp:328
void SendLogMsg(fmt::memory_buffer &buf)
Definition spdmon.hpp:381
virtual void RenderStatusLine(fmt::memory_buffer &buf, unsigned int width)=0
void TriggerPrintStatusLines()
Definition spdmon.hpp:358
void RegisterSinks(std::shared_ptr< spdlog::logger > logger)
Definition spdmon.hpp:346
spdlog::level::level_enum GetLevel()
Definition spdmon.hpp:379
void log(const spdlog::details::log_msg &msg) final
Definition spdmon.hpp:487
void Print(const spdlog::details::log_msg *msg)
Definition spdmon.hpp:492
~TerminalSink() final=default
typename ConsoleMutex::mutex_t mutex_t
Definition spdmon.hpp:471
spdlog::sinks::ansicolor_sink< ConsoleMutex > log_sink
Definition spdmon.hpp:470
void PrintStatusLineRegistry() final
Definition spdmon.hpp:490
static const char * kBarSymsUnicode[]
Definition spdmon.hpp:75
static const char * kBarSymsAscii[]
Definition spdmon.hpp:88
auto LogProgress(Iterable &&iter) -> IterableProgressMonitor< Iterable >
Definition spdmon.hpp:696
std::shared_ptr< spdlog::logger > stderr_terminal_st(const std::string &logger_name)
Definition spdmon.hpp:576
std::shared_ptr< spdlog::logger > stderr_terminal_mt(const std::string &logger_name)
Definition spdmon.hpp:565
TerminalSink< spdlog::details::console_nullmutex > terminal_stdout_sink_st
Definition spdmon.hpp:551
std::shared_ptr< spdlog::logger > stdout_terminal_mt(const std::string &logger_name)
Definition spdmon.hpp:559
TerminalSink< spdlog::details::console_mutex > terminal_stdout_sink_mt
Definition spdmon.hpp:550
TerminalSink< spdlog::details::console_mutex > terminal_stderr_sink_mt
Definition spdmon.hpp:553
std::shared_ptr< spdlog::logger > stdout_terminal_st(const std::string &logger_name)
Definition spdmon.hpp:571
TerminalSink< spdlog::details::console_nullmutex > terminal_stderr_sink_st
Definition spdmon.hpp:554
#define IS_ONE_OF_TYPE(sink)
Definition spdmon.hpp:580
#define SPDMON_DECLARE_NON_MOVEABLE(classInst)
Definition spdmon.hpp:52
#define SPDMON_DECLARE_NON_COPYABLE(classInst)
Definition spdmon.hpp:44