A production-grade, hardware-agnostic, cross-platform reference implementation and reusable library demonstrating canonical diagnostic logging best practices for command-line interfaces (CLIs) spanning C, C++, and Fortran.
┌──────────────────────────────┐
│ polyglot-cli │
│ │
│ CLI & Environment Parser │
│ Crash & Signal Handlers │
│ Positional Arguments / -- │
└──────────────┬───────────────┘
│
▼
┌──────────────────────────────┐
│ Polyglot Logging API │
│ │
│ C ABI (polyglot_log.h) │
│ C++ Stream (polyglot_log.hpp│
│ Fortran ISO_C (logging_mod) │
│ Caller Source Location │
│ Fast-Path Enabled Checks │
│ Fallback Bootstrap Sink │
└──────────────┬───────────────┘
│
▼
┌──────────────────────────────┐
│ Core Backend (spdlog) │
│ Permissive Root (TRACE) │
└──────────────┬───────────────┘
│
┌─────────────┴─────────────┐
▼ ▼
┌─────────────────┐ ┌─────────────────┐
│ Console Sink │ │ File Sink │
│ (stderr) │ │ (file.log) │
├─────────────────┤ ├─────────────────┤
│ Level: Dynamic │ │ Level: TRACE │
│ Stripped noise │ │ Source Location │
│ ANSI colors │ │ ISO-8601 UTC │
│ NO_COLOR aware │ │ PID / Thread ID │
│ Auto-detect TTY │ │ Text or NDJSON │
│ --color switch │ │ Rotating 10MBx3 │
└─────────────────┘ └─────────────────┘
stdoutbelongs exclusively to program data: JSON payloads, tabular numerical output, binary streams, or pipeline payloads (tool --verbose | jq .).stderris reserved for all diagnostic logs: Informational notices, debug traces, warnings, and fatal errors.- Pipeline Composability: When output is redirected (
tool -v > results.dat), diagnostic messages remain clearly visible on the terminal screen viastderrwhileresults.datremains completely unpolluted.
- Interactive Console Sink (
stderr):- Filtered dynamically via
-q(quiet),--silent(off), defaultINFO,-v(debug),-vv(trace), or--log-level <LEVEL>. - Clean formatting (
%^[%l]%$ %v) using ANSI colors when attached to an interactive TTY. - Compliant with the NO_COLOR standard: suppresses ANSI color escapes when
NO_COLORis present. Configurable via--color auto|always|never. - Suppresses microsecond timestamps, thread IDs, and source file locations to minimize cognitive load.
- Filtered dynamically via
- Forensic File Sink (
-l <path>/--log-file <path>):- Forensic disk sink capturing down to
TRACElevel by default (independently configurable via--log-file-level <LEVEL>). - Plain text or single-line NDJSON format (
--log-format text|json). - High-precision ISO-8601 timestamps, process ID (PID), thread ID, component tag, and exact caller source locations (
[%s:%#]). - Size-based rotation (10 MB per file, 3 generations) to prevent runaway disk consumption.
- Forensic disk sink capturing down to
- The central root logger is configured to
TRACE(most permissive). - Individual sinks filter independently.
- Accurate Fast-Path Semantics:
logger_is_enabled(level)tracks the active thresholds of both the console and file sinks directly, guaranteeing that expensive numerical serialization is skipped when neither sink accepts the event.
- Atomic Pointer Access:
g_loggeris managed viastd::atomic_loadandstd::atomic_storeacross all dispatch and reconfiguration calls, guaranteeing memory safety under heavy multi-threaded contention. - Bootstrap Fallback Logger: Statically initialized bootstrap sink ensures pre-init and post-shutdown log events never fault.
- Selective Logger Dropping: Drops only
"polyglot_cli", leaving loggers from other libraries intact. - Initialization Error Reporting: Returns explicit status codes (
LOGGER_OK,LOGGER_ERR_INVALID_ARG,LOGGER_ERR_FILE_OPEN) and creates parent directories automatically.
- C/C++: Exposes
LOG_TRACE,LOG_DEBUG,LOG_INFO, etc. passing__FILE__,__LINE__, and__func__. - Fortran 2008: Preprocessor enabled (
-cpp//fpp) providingF_LOG_INFO,F_LOG_DEBUG,F_LOG_TRACE.
- Dedicated zero-dependency
include/polyglot_log.hppheader provides type-safe C++17 fold-expression stream logging (LOG_CPP_INFO("CLI", "Processing ", count, " elements")).
- Numerical subsystems return integer status codes (
int run_c_computation(),integer(c_int) function run_fortran_solver()). - CLI driver verifies and logs failures, exiting non-zero if any subsystem fails.
Configuration resolves according to standard Unix hierarchy:
Defaults ──► Environment Variables ──► CLI Arguments (Highest Precedence)
| Setting | Default | Environment Variable | CLI Switch |
|---|---|---|---|
| Console Level | INFO |
POLYGLOT_LOG_LEVEL |
-v, -vv, -q, --silent, --log-level=LEVEL |
| File Path | None | POLYGLOT_LOG_FILE |
-l PATH, --log-file PATH, --log-file=PATH |
| File Level | TRACE |
POLYGLOT_LOG_FILE_LEVEL |
--log-file-level=LEVEL |
| Color Mode | auto |
NO_COLOR (forces off) |
--color auto|always|never |
| File Format | text |
None | --log-format text|json |
| Max File Size | 10 MB |
None | --log-max-size <MB> |
| Max Rotations | 3 files |
None | --log-max-files <NUM> |
.
├── .editorconfig # Consistent cross-editor whitespace & indentation
├── .clang-format # Standardized C/C++ code formatting rules
├── .gitignore # Git ignore rules for build, logs, and packages
├── CMakeLists.txt # Modern CMake 3.24+ (spdlog, CPack, CTest, export)
├── LICENSE # MIT License (FLOSS)
├── README.md # Architecture guide and documentation
├── .github/workflows/ci.yml # GitHub Actions CI matrix (Linux, macOS, Windows)
├── cmake/
│ └── run_cli_test.cmake # Cross-platform CTest execution & stream assertor
├── include/
│ ├── polyglot_log.h # Pure reusable C ABI logging facade
│ ├── polyglot_log.hpp # Type-safe C++17 stream wrapper
│ ├── c_subsystem.h # Pure C computational component header
│ └── fortran_solver.h # Fortran solver component header
├── src/
│ ├── polyglot_log.cpp # C++ spdlog dual-sink core & atomic C ABI export
│ ├── c_subsystem.c # Pure C computational component
│ ├── logging_mod.f90 # Fortran 2008 ISO_C_BINDING module & solver routine
│ └── main.cpp # Production CLI entry point
├── tests/
│ └── test_multithreaded.cpp # Multi-threaded concurrency stress test (8 threads)
└── examples/ # Standalone zero-dependency MWEs
├── CMakeLists.txt # Integrated example build rules
├── standalone_c/ # Pure C99 dual-sink minimal CLI (thread-safe)
├── standalone_cpp/ # Pure C++17 fold-expression minimal CLI (thread-safe)
├── standalone_fortran_modern/ # Modern Fortran 2008 (iso_fortran_env) CLI
└── standalone_fortran_legacy/ # Legacy FORTRAN 77 (Unit 0, COMMON block) CLI
- GCC Toolchain: GCC 11+ (C11, C++17) + GFortran 11+ (Linux, macOS, Windows via MSYS2 UCRT64)
- LLVM / Clang: Clang 16+ (C11, C++17) + GFortran runtime linkage (Linux, macOS)
- Intel oneAPI: Intel
icx/icpx+ Intel Fortranifx(Linux, Windows) - Microsoft Visual Studio: MSVC 2019/2022 + Intel Fortran
ifx(Windows) - MSYS2 UCRT64: Native Windows MinGW-w64 GCC 15 + GFortran 15 (standalone portable binaries)
To build completely self-contained binaries with zero dynamic runtime compiler dependencies:
cmake -B build -G Ninja -DCMAKE_BUILD_TYPE=Release -DPOLYGLOT_BUILD_STATIC=ON
cmake --build build --target cli_tool# Configure build with tests and examples enabled
cmake -B build -G Ninja -DCMAKE_BUILD_TYPE=Release -DBUILD_TESTING=ON -DBUILD_EXAMPLES=ON
# Compile all targets
cmake --build buildUsage: polyglot-cli [OPTIONS] [--] [ARGUMENTS...]
Options:
-v, --verbose Increase console verbosity (-v for DEBUG, -vv for TRACE)
-q, --quiet Quiet mode: display only errors on console
--silent Silent mode: disable all console logging (LOG_LVL_OFF)
--log-level LEVEL Explicitly set console level (trace|debug|info|warn|error|off)
-l, --log-file PATH Enable rotating file sink at specified path
--log-file-level LEVEL Set file sink level independently (default: trace)
--color MODE Terminal color mode (auto|always|never)
--log-format FORMAT File sink format (text|json)
-h, --help Display this help message and exit
--version Display version information and exit
-- End of options delimiter
# Pipeline execution: stdout payload captured to results.dat, diagnostics stay on terminal
./build/polyglot-cli -v -l logs/execution.log -- input.mesh output.h5 > results.datTerminal (stderr):
[info] [CLI] Application starting
[debug] [CLI] Parsed CLI config: verbosity=1, quiet=0, silent=0, log_file='logs/execution.log'
[debug] [CLI] Received 2 positional arguments
[info] [C-Subsystem] Initializing sparse matrix allocation
[debug] [C-Subsystem] Allocated 4096 bytes for CSR row pointers
[info] [C-Subsystem] Matrix factorization complete
[info] [Fortran-Solver] Initializing Krylov subspace iterative solver
[debug] [Fortran-Solver] Iteration 1: Residual norm = 1.420E-02
[debug] [Fortran-Solver] Iteration 2: Residual norm = 8.150E-06
[info] [Fortran-Solver] Solver converged in 2 iterations (tol=1.0e-05)
[info] [CLI] Application completed successfully
Output Payload (results.dat via stdout):
COMPUTATION_SUCCESS: 42
Forensic Disk Log (logs/execution.log with Source Locations):
[2026-09-03T11:15:00.123+02:00] [18420:18420] [info] [main.cpp:218] [CLI] Application starting
[2026-09-03T11:15:00.124+02:00] [18420:18420] [debug] [main.cpp:221] [CLI] Parsed CLI config: verbosity=1, quiet=0, silent=0, log_file='logs/execution.log'
[2026-09-03T11:15:00.124+02:00] [18420:18420] [info] [c_subsystem.c:13] [C-Subsystem] Initializing sparse matrix allocation
[2026-09-03T11:15:00.124+02:00] [18420:18420] [debug] [c_subsystem.c:17] [C-Subsystem] Allocated 4096 bytes for CSR row pointers
[2026-09-03T11:15:00.125+02:00] [18420:18420] [trace] [c_subsystem.c:19] [C-Subsystem] CSR index verification passed [dim=64x64, nnz=256]
[2026-09-03T11:15:00.125+02:00] [18420:18420] [info] [c_subsystem.c:21] [C-Subsystem] Matrix factorization complete
[2026-09-03T11:15:00.125+02:00] [18420:18420] [info] [logging_mod.f90:108] [Fortran-Solver] Initializing Krylov subspace iterative solver
[2026-09-03T11:15:00.126+02:00] [18420:18420] [debug] [logging_mod.f90:98] [Fortran-Solver] Iteration 1: Residual norm = 1.420E-02
[2026-09-03T11:15:00.126+02:00] [18420:18420] [trace] [logging_mod.f90:114] [Fortran-Solver] Vector dot product <r, r> = 2.0164e-04
[2026-09-03T11:15:00.126+02:00] [18420:18420] [debug] [logging_mod.f90:98] [Fortran-Solver] Iteration 2: Residual norm = 8.150E-06
[2026-09-03T11:15:00.127+02:00] [18420:18420] [info] [logging_mod.f90:118] [Fortran-Solver] Solver converged in 2 iterations (tol=1.0e-05)
[2026-09-03T11:15:00.127+02:00] [18420:18420] [info] [main.cpp:253] [CLI] Application completed successfully
The project exports canonical CMake package configuration targets. Downstream projects can consume the library directly:
find_package(PolyglotLog CONFIG REQUIRED)
add_executable(my_app main.cpp)
target_link_libraries(my_app PRIVATE PolyglotLog::polyglot_logger_core)
# If consuming Fortran module:
target_link_libraries(my_app PRIVATE PolyglotLog::polyglot_logger_fortran)In your C or C++ application:
#include <polyglot_log.h> // C ABI
#include <polyglot_log.hpp> // Modern C++ stream wrapper
int main() {
logger_init(LOG_LVL_INFO, "run.log", LOG_LVL_TRACE);
LOG_CPP_INFO("MyApp", "Starting calculation with ", 4, " threads");
logger_shutdown();
}In your Fortran application:
use logging_mod
call f_log(LOG_LVL_INFO, "Solver", "Step completed")All tests execute via the headless CMake runner script (cmake/run_cli_test.cmake), ensuring cross-platform reliability without shell redirection bugs.
ctest --test-dir build --output-on-failuretest_stdout_data_cleanliness: Validates zero diagnostic leakage ontostdout.test_default_verbosity_filtering: Asserts defaultINFOemits withoutDEBUGorTRACE.test_verbose_debug_flag: Asserts-vunlocks[debug]logs.test_trace_verbosity_flag: Asserts-vvunlocks[trace]logs.test_quiet_mode_flag: Asserts-qsuppressesINFO,DEBUG, andTRACE.test_silent_mode_flag: Asserts--silentsuppresses 100% of console output.test_named_log_level_flag: Asserts--log-level debugexplicitly controls threshold.test_dual_sink_file_generation: Verifies ISO timestamps, process/thread IDs, and disk persistence.test_file_level_independence: Verifies--log-file-level infosuppresses disk trace logs independently.test_env_var_override: ValidatesPOLYGLOT_LOG_LEVELenvironment variable control.test_no_color_compliance: AssertsNO_COLOR=1suppresses ANSI color escapes.test_conflicting_flags_error: Validates mutual exclusion (-q+-vproduces exit code 1).test_help_flag: Asserts--helpemits usage cleanly and exits 0.test_polyglot_solver_logging: Confirms C and Fortran subsystems both log through the unified facade.test_multithreaded_concurrency: Stress-tests 8 concurrent threads actively logging 1,600 events to file under heavy contention.test_color_mode_flags: Validates--color=neverand--color=always.test_json_log_format: Validates structured single-line NDJSON file logging.test_json_log_escaping: Asserts anti-injection character escaping (quotes, backslashes, tabs, newlines) preserves valid single-line NDJSON.test_positional_arguments_and_delimiter: Validates positional parameters and--delimiter.test_invalid_log_level_error: Validates error handling on invalid CLI switches.test_color_always_overrides_no_color: Validates explicit CLI switch--color=alwaysoverridesNO_COLORper no-color.org.test_rotation_policy_flags: Validates--log-max-sizeand--log-max-filesparameters.test_standalone_c: Asserts standalone C99 stream isolation.test_standalone_cpp: Asserts standalone C++17 stream isolation.test_standalone_fortran_modern: Asserts standalone Fortran 2008 stream isolation.test_standalone_fortran_legacy: Asserts standalone FORTRAN 77 stream isolation.
Generate clean release packages with standard GNUInstallDirs directory hierarchies:
cd build
cpack -G "ZIP;TGZ"This project is licensed under the MIT License — see LICENSE for details. Free and Open Source Software (FLOSS).