415int Log(
const LogLevel log_level,
const std::string& filename,
const char* fmt,
417 if (log_level > kLogLevel)
return kStatusbarLogSuccess;
418 std::unique_lock<std::mutex> console_lock(_console_mutex, std::defer_lock);
419 std::unique_lock<std::mutex> registry_lock(_registry_mutex, std::defer_lock);
420 std::lock(console_lock, registry_lock);
423 const bool statusbars_active = !_statusbar_registry.empty();
425 const char* prefix =
"";
428 case kLogLevelErr: prefix =
"ERROR";
break;
429 case kLogLevelWrn: prefix =
"WARNING";
break;
430 case kLogLevelInf: prefix =
"INFO";
break;
431 case kLogLevelDbg: prefix =
"DEBUG";
break;
437 if (statusbars_active) {
438 for (std::size_t i = 0; i < _statusbar_registry.size(); ++i) {
439 for (std::size_t j = 0; j < _statusbar_registry[i].positions.size();
441 int current_pos = _statusbar_registry[i].positions[j];
442 if (current_pos > move) {
452 if (statusbars_active) printf(
"\r\033[2K\r");
454 va_copy(args_copy, args);
455 unsigned int size = std::vsnprintf(
nullptr, 0, fmt, args_copy);
456 size = std::min(size, kMaxLogLength);
457 std::vector<char> buffer(size + 1);
458 std::vsnprintf(buffer.data(), buffer.size(), fmt, args);
459 std::string message = _SanitizeStringWithNewline(buffer.data());
462 std::string sanitized_filename = _SanitizeStringWithNewline(filename);
463 if (sanitized_filename.length() > kMaxFilenameLength) {
464 sanitized_filename.resize(kMaxFilenameLength - 3);
465 sanitized_filename +=
"...";
468 printf(
"%s [%s]: %s\n", prefix, sanitized_filename.c_str(), message.c_str());
470 _MoveCursorUp(-move);
472 if (statusbars_active) {
473 for (std::size_t i = 0; i < _statusbar_registry.size(); ++i) {
474 for (std::size_t j = 0; j < _statusbar_registry[i].positions.size();
476 _DrawStatusbarComponent(_statusbar_registry[i].
percentages[j],
485 return kStatusbarLogSuccess;
489 const std::vector<unsigned int> _positions,
490 const std::vector<unsigned int> _bar_sizes,
491 const std::vector<std::string> _prefixes,
492 const std::vector<std::string> _postfixes) {
493 statusbar_handle.valid =
false;
494 statusbar_handle.id = 0;
495 if (_positions.size() != _bar_sizes.size() ||
496 _bar_sizes.size() != _prefixes.size() ||
497 _prefixes.size() != _postfixes.size()) {
499 "Failed to create statusbar_handle The vecotors '_positions', "
500 "'_bar_sizes', '_prefixes' and "
501 "'_postfixes' must have the same size! Got: '_positions': %d, "
502 "'_bar_sizes': %d, '_prefixes': %d, '_postfixes': %d.",
503 _positions.size(), _bar_sizes.size(), _prefixes.size(),
508 if (_statusbar_registry.size() - _statusbar_free_handles.size() >=
512 "Failed to create statusbar handle. Maximum status bars (%zu) reached",
513 statusbar_log::kMaxHandles);
517 std::unique_lock<std::mutex> console_lock(_console_mutex, std::defer_lock);
518 std::unique_lock<std::mutex> registry_lock(_registry_mutex, std::defer_lock);
519 std::unique_lock<std::mutex> ID_count_lock(_id_count_mutex, std::defer_lock);
520 std::lock(console_lock, registry_lock, ID_count_lock);
523 if (_handle_id_count == 0) {
524 console_lock.unlock();
525 registry_lock.unlock();
527 "Max number of possible statusbar handle.ids reached, looping back "
529 std::lock(console_lock, registry_lock);
533 const std::size_t num_bars = _positions.size();
534 const std::vector<double>
percentages(num_bars, 0.0);
535 const std::vector<std::size_t>
spin_idxs(num_bars, 0);
537 std::vector<std::string> sanitized_prefixes;
538 sanitized_prefixes.reserve(_prefixes.size());
539 std::vector<std::string> sanitized_postfixes;
540 sanitized_prefixes.reserve(_postfixes.size());
541 std::vector<unsigned int> sanitized_bar_sizes;
542 sanitized_bar_sizes.reserve(_bar_sizes.size());
543 for (std::size_t i = 0; i < _prefixes.size(); ++i) {
544 std::string _prefix = _prefixes[i];
545 if (_prefix.length() > kMaxPrefixLength) {
546 _prefix.resize(kMaxPrefixLength - 3);
549 sanitized_prefixes.push_back(_SanitizeString(_prefix));
551 std::string _postfix = _postfixes[i];
552 if (_postfix.length() > kMaxPostfixLength) {
553 _postfix.resize(kMaxPostfixLength - 3);
556 sanitized_postfixes.push_back(_SanitizeString(_postfix));
558 sanitized_bar_sizes.push_back(
559 std::min<unsigned int>(_bar_sizes[i], kMaxBarWidth));
562 if (!_statusbar_free_handles.empty()) {
563 StatusbarHandle free_handle = _statusbar_free_handles.back();
564 _statusbar_free_handles.pop_back();
565 statusbar_handle.idx = free_handle.idx;
566 _statusbar_registry[statusbar_handle.idx] = {
568 sanitized_bar_sizes, sanitized_prefixes,
570 _handle_id_count,
false};
572 statusbar_handle.idx = _statusbar_registry.size();
573 _statusbar_registry.emplace_back(Statusbar{
574 percentages, _positions, sanitized_bar_sizes, sanitized_prefixes,
575 sanitized_postfixes,
spin_idxs, _handle_id_count,
false});
577 statusbar_handle.id = _handle_id_count;
578 statusbar_handle.valid =
true;
579 for (std::size_t idx = 0; idx < num_bars; idx++) {
580 _DrawStatusbarComponent(
581 0.0, _statusbar_registry[statusbar_handle.idx].bar_sizes[idx],
582 _statusbar_registry[statusbar_handle.idx].prefixes[idx],
583 _statusbar_registry[statusbar_handle.idx].postfixes[idx],
584 _statusbar_registry[statusbar_handle.idx].spin_idxs[idx],
585 _statusbar_registry[statusbar_handle.idx].positions[idx]);
587 return kStatusbarLogSuccess;
591 std::unique_lock<std::mutex> console_lock(_console_mutex, std::defer_lock);
592 std::unique_lock<std::mutex> registry_lock(_registry_mutex, std::defer_lock);
593 std::lock(console_lock, registry_lock);
595 const int err = _IsValidHandle(statusbar_handle);
596 if (err != kStatusbarLogSuccess) {
597 console_lock.unlock();
598 registry_lock.unlock();
599 _IsValidHandleVerbose(statusbar_handle);
600 LogErr(
kFilename,
"Failed to destory statusbar_handle!");
603 Statusbar& target = _statusbar_registry[statusbar_handle.idx];
605 for (std::size_t i = 0; i < target.positions.size(); i++) {
606 _MoveCursorUp(target.positions[i]);
608 _MoveCursorUp(-target.positions[i]);
612 target.percentages.clear();
613 target.positions.clear();
614 target.bar_sizes.clear();
616 for (std::string& str : target.prefixes) {
617 std::fill(str.begin(), str.end(),
'\0');
619 for (std::string& str : target.postfixes) {
620 std::fill(str.begin(), str.end(),
'\0');
622 target.prefixes.clear();
623 target.postfixes.clear();
626 target.spin_idxs.clear();
628 _statusbar_free_handles.push_back(statusbar_handle);
630 statusbar_handle.valid =
false;
631 statusbar_handle.id = 0;
633 return kStatusbarLogSuccess;
637 const double percent) {
638 std::unique_lock<std::mutex> console_lock(_console_mutex, std::defer_lock);
639 std::unique_lock<std::mutex> registry_lock(_registry_mutex, std::defer_lock);
640 std::lock(console_lock, registry_lock);
644 const int err = _IsValidHandle(statusbar_handle);
645 if (err != kStatusbarLogSuccess) {
646 console_lock.unlock();
647 registry_lock.unlock();
648 _IsValidHandleVerbose(statusbar_handle);
649 LogErr(
kFilename,
"Failed to update statusbar: Invalid handle.");
653 if (percent > 100.0 || percent < 0.0) {
654 console_lock.unlock();
655 registry_lock.unlock();
656 LogErr(
kFilename,
"Failed to update statusbar: Invalid percentage.");
660 Statusbar& statusbar = _statusbar_registry[statusbar_handle.idx];
662 if (idx >= statusbar.percentages.size()) {
663 console_lock.unlock();
664 registry_lock.unlock();
665 LogErr(
kFilename,
"Failed to update statusbar: Invalid bar index.");
669 statusbar.percentages[idx] = percent;
670 statusbar.spin_idxs[idx] = statusbar.spin_idxs[idx] + 1;
671 int bar_error_code = _DrawStatusbarComponent(
672 percent, statusbar.bar_sizes[idx], statusbar.prefixes[idx],
673 statusbar.postfixes[idx], statusbar.spin_idxs[idx],
674 statusbar.positions[idx]);
676 if (bar_error_code != kStatusbarLogSuccess && !statusbar.error_reported) {
677 statusbar.error_reported =
true;
679 switch (bar_error_code) {
681 why =
"Terminal width detection failed (Windows)";
684 why =
"Terminal width detection failed (Linux)";
687 why =
"Truncating was needed";
691 "Terminal width detection failed (Windows) and truncation was "
696 "Terminal width detection failed (Linux) and truncation was "
700 LogErr(
kFilename,
"%s on statusbar with ID %u at bar idx %zu!", why,
704 return kStatusbarLogSuccess;