statusbarlog 1.0
This api is used for creating statusbars and for better logging alongside these statusbars.
Loading...
Searching...
No Matches
statusbarLog Documentation

Overview

StatusbarLog is a C++ utility for simultaneous logging and multiple stacked statusbar displays in terminal applications.

Features:

  • Multiple stacked statusbars with configurable text, sizes, and positions
  • Logging with severity levels: ERROR, WARN, INFO, DEBUG
  • Spinner animation for "busy" statusbars
  • Cursor manipulation so log messages and statusbars do not overwrite each other
  • Cross-platform design goals

Usage Example

Example code snippet (from docs/example/main.cpp):

// -- statusbarlog/test/src/statusbarlog_main.cpp
#include <cstddef>
#include <iostream>
#include <string>
#include <thread>
#include "statusbarlog/statusbarlog.h"
const std::string kFilename = "main.cpp";
int main() {
std::cout << "Start to be kept <- " << std::flush;
std::cout << "Temporary message that might be long" << std::flush;
std::this_thread::sleep_for(std::chrono::seconds(2));
std::cout << "Clean message" << std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds(500));
statusbar_log::LogInf(kFilename, "Starting test...");
std::cout << "\n\n";
int err = 0;
const int total_steps1 = 15;
const int total_steps2 = 100;
statusbar_log::StatusbarHandle h;
h, {2, 1}, // <-- Postions
{20, 10}, // <-- Bar widths
{"first: ", "second: "}, // <-- prefixes
{" -- 15 total steps", " -- 100 total steps"} // <-- postfixes
);
if (err != 0) {
statusbar_log::LogErr(kFilename, "Failed to create statusbar. Errorcode %d", err);
return err;
}
for (std::size_t i = 0; i <= total_steps1; ++i) {
double percent = static_cast<double>(i) / total_steps1 * 100.0;
if (i % 10 == 0 && i != 0) {
statusbar_log::LogInf(kFilename, "10 Ticks reached");
}
for (std::size_t j = 0; j <= total_steps2; ++j) {
double percent = static_cast<double>(j) / total_steps2 * 100.0;
std::this_thread::sleep_for(std::chrono::milliseconds(30));
}
}
if (err != 0) {
statusbar_log::LogErr(kFilename, "Failed to destroy statusbar. Errorcode %d", err);
return err;
}
return 0;
}
int UpdateStatusbar(StatusbarHandle &statusbar_handle, const std::size_t idx, const double percent)
void ClearToEndOfLine()
void SaveCursorPosition()
int CreateStatusbarHandle(StatusbarHandle &statusbar_handle, const std::vector< unsigned int > _positions, const std::vector< unsigned int > _bar_sizes, const std::vector< std::string > _prefixes, const std::vector< std::string > _postfixes)
void RestoreCursorPosition()
int DestroyStatusbarHandle(StatusbarHandle &statusbar_handle)
const std::string kFilename

Brief explenation

  1. Set compile-time log level (optional)
    The log level is set by CMake when generating the header. This ensure only log messages with higher or equal log priority (ERROR, WARNING, INFO, DEBUG) to the log level will be printed. Override via:
    cmake -DSTATUSBARLOG_LOG_LEVEL=kLogLevelWrn ...
    (all options: kLogLevelDbg, kLogLevelInf, kLogLevelWrn, kLogLevelErr, kLogLevelOff)
  2. Define filename for every cpp file in which you want to log
    const std::string kFilename = "StatusbarLog_main.cpp";
  3. Now a simple log message can be done like:
    statusbarlog::LogDbg(kFilename, "Funny debug message");
    statusbarlog::LogInf(kFilename, "Starting test...");
    statusbarlog::LogWrn(kFilename, "Couldn't obtain viscosity. Using 1.6e-5 m^2/s");
    statusbarlog::LogErr(kFilename, "Failed to compute rhs");
  4. Create a stacked statusbar (here: two statusbars ontop of each other)
    statusbarlog::StatusbarHandle handle;
    std::vector<unsigned int> positions = {2, 1};
    std::vector<unsigned int> bar_sizes = {20, 10};
    std::vector<std::string> prefixes = {"first", "second"};
    std::vector<std::string> postfixes = {"20 long", "10 long"};
    int err_code = statusbarlog::CreateStatusbarHandle(
    std::vector< unsigned int > positions
    Vertical positions (1=topmost).
    std::vector< unsigned int > bar_sizes
    Total width (characters) of each bar.
    std::vector< std::string > prefixes
    Text displayed before each bar.
    std::vector< std::string > postfixes
    Text displayed after each bar.
  5. Updating a statusbar
    statusbarlog::UpdateStatusbar(handle, 0, percent); // top bar
    statusbarlog::UpdateStatusbar(handle, 1, percent); // lower bar
    Note: For printing the statusbar the first time just use the percentage 0.
  6. Log while updating
    statusbarlog::LogInf(kFilename, "10 ticks reached");
    The log messages now nicely display above the statusbar.
  7. Cleanup
    int err_code = statusbarlog::DestroyStatusbarHandle(handle);

Building

prerequisites

All Platforms:

  • C++20 capable compiler (Clang, GCC, or MSVC)
  • CMake >= 3.20

All Platforms:

For Doxygen documentation:

  • doxygen
  • graphviz (for diagrams)

Linux (Debian/Ubuntu):

sudo apt install build-essential cmake

For Doxygen documentation:

sudo apt install doxygen graphviz

Linux (Arch):

sudo pacman -S base-devel cmake

For Doxygen documentation:

sudo pacman -S base-devel doxygen graphviz

Windows:

  • Visual Studio 2019 or later with individual components:
    • MSBuild
    • Windows 11 SDK
    • MSBuild support for LLVM (clang-cl) toolset
    • C++ Clang compiler for Windows
    • MSVC v143 - VS 2022 C++ ARM build tools (Latest)
    • MSVC v143 - VS 2022 C++ ARM Spectre-mitigated libs (Latest)
    • MSVC v143 - VS 2022 C++ ARM64/ARM64EC build tools (Latest)
    • MSVC v143 - VS 2022 C++ ARM64/ARM64EC Spectre-mitigated libs (Latest)
    • MSVC v143 - VS 2022 C++ x64/x86 build tools (Latest)
    • MSVC v143 - VS 2022 C++ x64/x86 Spectre-mitigated libs (Latest)
    • C++ Cmake tools for Windows
    • C++ Cmake tools for Linux (These are just the components i have installed, not all might be required and others might work)
  • Cmake (can be installed manually or using visual studio)
  • Ninja
    winget install Ninja-build.Ninja
  • For Dxygen documentation:
    • Doxygen
    • graphviz
      winget install doxygen
      winget install graphviz
  • Don't forget to add the graphvize binaries to PATH! (usually located at C:/Program Files/Graphviz/bin)

Building on Linux/macOS

mkdir -p build && cd build
cmake -S .. -B . build -DCMAKE_BUILD_TYPE=Release -DSTATUSBARLOG_LOG_LEVEL=kLogLevelInf
cmake --build . -j$(nproc) --config Release

Building on Windows

Method 1: Using Visual Studio Developer Command Prompt

open "Developer Command Promt for VS 2022" or similar

mkdir build
cd build
cmake -S .. -B . -DCMAKE_BUILD_TYPE=Release -DSTATUSBARLOG_LOG_LEVEL=kLogLevelInf
cmake --build . --config Release --parallel

Method 2: Using Ninja (Recommended)

mkdir build
cd build
cmake -S .. -B . -G "Ninja" -DCMAKE_BUILD_TYPE=Release -DSTATUSBARLOG_LOG_LEVEL=kLogLevelInf
cmake --build . --parallel

Method 3: Using Visual Studio IDE

mkdir build
cd build
cmake -S .. -B . -G "Visual Studio 17 2022" -A x64

Then open the generated .sln in Visual Studio

Important CMake Options

Option Type Default Description
CMAKE_BUILD_TYPE STRING Release Standard CMake build type
STATUSBARLOG_INSTALL BOOL OFF Generate installation targets
STATUSBARLOG_BUILD_TESTS BOOL OFF Build test suite
STATUSBARLOG_BUILD_TEST_MAIN BOOL OFF Build test main executable
STATUSBARLOG_LOG_LEVEL STRING kLogLevelDbg Compile-time log level (kLogLevelOff, kLogLevelErr, kLogLevelWrn, kLogLevelInf, kLogLevelDbg)

Example usage:

cmake -S . -B build -DCMAKE_BUILD_TYPE=Release -DSTATUSBARLOG_LOG_LEVEL=kLogLevelDbg

Or when consuming via add_subdirectory():

set(STATUSBARLOG_LOG_LEVEL kLogLevelWrn CACHE STRING "statusbarlog default")
add_subdirectory(path/to/statusbarlog)

Performance Notes for Windows

  • Use Ninja generator for fastest build times
  • MSVC compiler with */O2* and LTO provides best runtime performance
  • Consider Profile-Guided Optimization (PGO) for maximum performance in release builds

Generating Documentation

  1. Ensure Doxygen and Graphviz are installed
  2. Adjust the Doxyfile to point to this mainpage:
    INPUT = src include docs
    FILE_PATTERNS = *.h *.hpp *.cpp *.md
    MAINPAGE = docs/mainpage.md
    EXCLUDE_PATTERNS = README.md
  3. Run:
    doxygen Doxyfile

HTML output is usually in docs/html.

TODO / Roadmap

  • โœ… CMake integration with configurable STATUSBARLOG_LOG_LEVEL
  • ๐Ÿ”ง Make usable as git submodule / cmake module
  • ๐Ÿ”ง Stream selection for logs and statusbars
  • ๐Ÿ”ง Optional flush control for performance
  • โš™๏ธ Add cross-platform support (Windows)
  • ๐Ÿงช Expand unit test coverage:
    • Destroying handles / invalid handles
    • Out-of-bounds indices
    • Mutex and thread safety
    • Truncation and string sanitization
    • Race conditions
    • Edge cases and boundary tests
  • ๐Ÿ“˜ Follow Google C++ Style Guide:
    • Replace macros with constexpr or inline functions
    • Consistent naming: PascalCase for functions, UpperCamel for types
    • Avoid global state

Unit Test Plan (Summary)

String & Utility Functions

TEST(StringSanitization, SanitizeString_NoChangesNeeded)
TEST(StringSanitization, SanitizeString_ControlCharacters)
TEST(StringSanitization, SanitizeString_UnicodeReplacement)
TEST(StringSanitization, SanitizeStringWithNewline_PreservesNewlines)
TEST(StringSanitization, SanitizeString_TruncatesLongStrings)

Terminal Utility Tests

TEST(TerminalUtils, GetTerminalWidth_Success)
TEST(TerminalUtils, GetTerminalWidth_FallbackToDefault)
TEST(TerminalUtils, ClearCurrentLine_NoCrash)
TEST(TerminalUtils, CursorPosition_SaveRestore)
TEST(TerminalUtils, FlushOutput_Behavior)

Integration Tests

TEST(Logging, LogWithActiveStatusbars)
TEST(Logging, LogDifferentLevels)
TEST(Logging, LogWithFormatting)
TEST(Logging, LogWithLongMessages_Truncation)

Concurrency

TEST(Concurrency, MultipleHandlesSimultaneousCreation)
TEST(Concurrency, UpdatesFromDifferentThreads_NoCrash)
TEST(Concurrency, LogWhileStatusbarActive)

Edge Cases

TEST(EdgeCases, RapidSequentialUpdates)
TEST(EdgeCases, ManyStatusbarsSimultaneously)
TEST(EdgeCases, EmptyVectors_ErrorHandling)
TEST(EdgeCases, VeryLongPrefixPostfix_Truncation)
TEST(EdgeCases, BoundaryPercentages_0_and_100)

```