From 9a3539d4bc0eb6d2166fa938aadb1ebc22400f6c Mon Sep 17 00:00:00 2001 From: Anthony West Date: Sat, 10 Oct 2026 17:13:55 -0700 Subject: [PATCH 01/12] Update ASWLog description and add/update header descriptions --- AGENTS.md | 2 +- ASWLog/ASWLog_Base.h | 6 +++++- ASWLog/ASWLog_CategoryLog.h | 5 ++++- ASWLog/ASWLog_Config.h | 6 ++++-- ASWLog/ASWLog_ConsoleLog.h | 5 ++++- ASWLog/ASWLog_CrashHandler.h | 5 ++++- ASWLog/ASWLog_DebuggerLog.h | 5 ++++- ASWLog/ASWLog_Fields.h | 5 +++-- ASWLog/ASWLog_FileLog.h | 5 ++++- ASWLog/ASWLog_Formatter.h | 6 ++++-- ASWLog/ASWLog_Interface.h | 5 ++++- ASWLog/ASWLog_Limiter.h | 3 +++ ASWLog/ASWLog_MemoryLog.h | 5 ++++- ASWLog/ASWLog_MultiLog.h | 5 ++++- ASWLog/ASWLog_NullLog.h | 5 ++++- ASWLog/ASWLog_SyslogLog.h | 5 ++++- ASWLog/ASWLog_TextLogBase.h | 6 +++++- ASWLog/ASWLog_Types.h | 5 +++-- ASWLog/ASWLog_Unicode.h | 5 +++-- ASWLog/ASWLog_Utils.h | 5 +++-- ASWLog/ASWLog_Version.h | 5 ++++- ASWLog/ASWLog_WindowsEventLog.h | 3 +++ CMakeLists.txt | 2 ++ README.md | 12 ++++++++++-- 24 files changed, 93 insertions(+), 28 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 6d21c27..2e0badf 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -6,7 +6,7 @@ These instructions apply to the entire repository unless a more specific `AGENTS ## Repository Overview -ASWLog is a thread-safe light-weight C++ logging tool for Windows and Linux projects. +ASWLog is a thread-safe, dependency-free C++20 logging library for Windows and Linux. - `ASWLog/` contains the framework implementation. - `tests/` contains the unit tests: test modules (`Test_ASWLog_`, the tests of `ASWLog_`) and shared test helpers (`UT_Helper_`, e.g. `UT_Helper_DateTime`) in `tests/tests/`, their CMake project in `tests/cmake/`, their RAD Studio console project in `tests/rad370/`, and their RAD Studio VCL GUI runner project in `tests/vcl/gui/rad370/` (built from the submodule's `vcl/gui/src`). `tests/compile_checks/` holds "must not compile" checks, which `tests/cmake/CMakeLists.txt` runs with `try_compile` when configuring (a failed check stops the configure). `tests/package/` is a project that builds against an installed ASWLog with `find_package` (CI installs the library and runs it). diff --git a/ASWLog/ASWLog_Base.h b/ASWLog/ASWLog_Base.h index 685181a..1a6cf3f 100644 --- a/ASWLog/ASWLog_Base.h +++ b/ASWLog/ASWLog_Base.h @@ -2,7 +2,11 @@ ASWLog_Base.h Author: Anthony S. West - ASW Software -A light-weight logging tool. +A logging library. + +TASWLogBase, the base of the built-in loggers: the minimum level, the +enabled flag, the backtrace, the config and the error reporting that every +logger shares. Requires C++ 20 or higher. diff --git a/ASWLog/ASWLog_CategoryLog.h b/ASWLog/ASWLog_CategoryLog.h index f674423..58c20f8 100644 --- a/ASWLog/ASWLog_CategoryLog.h +++ b/ASWLog/ASWLog_CategoryLog.h @@ -2,7 +2,10 @@ ASWLog_CategoryLog.h Author: Anthony S. West - ASW Software -A light-weight logging tool. +A logging library. + +TASWCategoryLog, a named category of entries (e.g. "Net") with a minimum +level of its own, which wraps another logger. Requires C++ 20 or higher. diff --git a/ASWLog/ASWLog_Config.h b/ASWLog/ASWLog_Config.h index 8920a8b..f3b08bd 100644 --- a/ASWLog/ASWLog_Config.h +++ b/ASWLog/ASWLog_Config.h @@ -2,9 +2,11 @@ ASWLog_Config.h Author: Anthony S. West - ASW Software -A light-weight logging tool. +A logging library. -Source for the ASWLog config options. +TASWLogConfig, the settings of a logger, and the structs that group them +(line layout, file, asynchronous writing, backtrace, startup and shutdown +lines, and the settings of the system loggers). Requires C++ 20 or higher. diff --git a/ASWLog/ASWLog_ConsoleLog.h b/ASWLog/ASWLog_ConsoleLog.h index 3ea3338..11e5fd1 100644 --- a/ASWLog/ASWLog_ConsoleLog.h +++ b/ASWLog/ASWLog_ConsoleLog.h @@ -2,7 +2,10 @@ ASWLog_ConsoleLog.h Author: Anthony S. West - ASW Software -A light-weight logging tool. +A logging library. + +TASWConsoleLog, a text logger that writes to the console (stdout, and +stderr for warnings and errors), optionally in color. Requires C++ 20 or higher. diff --git a/ASWLog/ASWLog_CrashHandler.h b/ASWLog/ASWLog_CrashHandler.h index cc27630..b176262 100644 --- a/ASWLog/ASWLog_CrashHandler.h +++ b/ASWLog/ASWLog_CrashHandler.h @@ -2,7 +2,10 @@ ASWLog_CrashHandler.h Author: Anthony S. West - ASW Software -A light-weight logging tool. +A logging library. + +Crash handlers that flush every text logger and write a "Crash: " +line when the application crashes (InstallCrashHandlers(), HandleCrash()). Requires C++ 20 or higher. diff --git a/ASWLog/ASWLog_DebuggerLog.h b/ASWLog/ASWLog_DebuggerLog.h index 5c5c6e6..64ab5aa 100644 --- a/ASWLog/ASWLog_DebuggerLog.h +++ b/ASWLog/ASWLog_DebuggerLog.h @@ -2,7 +2,10 @@ ASWLog_DebuggerLog.h Author: Anthony S. West - ASW Software -A light-weight logging tool. +A logging library. + +TASWDebuggerLog, a text logger that writes to the debugger's output on +Windows (OutputDebugStringW); it writes nothing on other platforms. Requires C++ 20 or higher. diff --git a/ASWLog/ASWLog_Fields.h b/ASWLog/ASWLog_Fields.h index ed8eb86..3bf8c20 100644 --- a/ASWLog/ASWLog_Fields.h +++ b/ASWLog/ASWLog_Fields.h @@ -2,9 +2,10 @@ ASWLog_Fields.h Author: Anthony S. West - ASW Software -A light-weight logging tool. +A logging library. -Source for the ASWLog structured fields and scoped context. +Structured fields: TASWLogField, a named value attached to one entry, and +TASWLogScope, context that every entry logged on the thread carries. Requires C++ 20 or higher. diff --git a/ASWLog/ASWLog_FileLog.h b/ASWLog/ASWLog_FileLog.h index 80e08ba..4746515 100644 --- a/ASWLog/ASWLog_FileLog.h +++ b/ASWLog/ASWLog_FileLog.h @@ -2,7 +2,10 @@ ASWLog_FileLog.h Author: Anthony S. West - ASW Software -A light-weight logging tool. +A logging library. + +TASWFileLog, a text logger that writes to a file, with rotation by size and +by day, backup cleanup, and flush and sync settings for crash durability. Requires C++ 20 or higher. diff --git a/ASWLog/ASWLog_Formatter.h b/ASWLog/ASWLog_Formatter.h index ca9b42c..d5c9922 100644 --- a/ASWLog/ASWLog_Formatter.h +++ b/ASWLog/ASWLog_Formatter.h @@ -2,9 +2,11 @@ ASWLog_Formatter.h Author: Anthony S. West - ASW Software -A light-weight logging tool. +A logging library. -Source for the ASWLog line formatters. +IASWLogFormatter, which turns an entry into the line a text logger writes, +and the built-in formatters: TASWTextFormatter (the default layout), +TASWPatternFormatter and TASWJSONFormatter (JSON Lines). Requires C++ 20 or higher. diff --git a/ASWLog/ASWLog_Interface.h b/ASWLog/ASWLog_Interface.h index e3cc936..ee8a5d0 100644 --- a/ASWLog/ASWLog_Interface.h +++ b/ASWLog/ASWLog_Interface.h @@ -2,7 +2,10 @@ ASWLog_Interface.h Author: Anthony S. West - ASW Software -A light-weight logging tool. +A logging library. + +IASWLog, the interface of every logger, with its logging methods: plain, +formatted (*Fmt, checked at compile time), raw and forced. Requires C++ 20 or higher. diff --git a/ASWLog/ASWLog_Limiter.h b/ASWLog/ASWLog_Limiter.h index 8bcf342..6639388 100644 --- a/ASWLog/ASWLog_Limiter.h +++ b/ASWLog/ASWLog_Limiter.h @@ -4,6 +4,9 @@ Author: Anthony S. West - ASW Software A logging library. +Rate-limited logging for entries that can repeat often: the ASWLOG_ONCE, +ASWLOG_EVERY_N and ASWLOG_EVERY_INTERVAL macros, and TASWLogLimiter. + Requires C++ 20 or higher. Copyright 2026 ASW Software diff --git a/ASWLog/ASWLog_MemoryLog.h b/ASWLog/ASWLog_MemoryLog.h index b0bc05c..7918925 100644 --- a/ASWLog/ASWLog_MemoryLog.h +++ b/ASWLog/ASWLog_MemoryLog.h @@ -2,7 +2,10 @@ ASWLog_MemoryLog.h Author: Anthony S. West - ASW Software -A light-weight logging tool. +A logging library. + +TASWMemoryLog, a text logger that keeps its newest lines in memory, e.g. +for an in-app log viewer, a crash report or tests. Requires C++ 20 or higher. diff --git a/ASWLog/ASWLog_MultiLog.h b/ASWLog/ASWLog_MultiLog.h index eaa6ebd..a169b0f 100644 --- a/ASWLog/ASWLog_MultiLog.h +++ b/ASWLog/ASWLog_MultiLog.h @@ -2,7 +2,10 @@ ASWLog_MultiLog.h Author: Anthony S. West - ASW Software -A light-weight logging tool. +A logging library. + +TASWMultiLog, which passes each entry on to several loggers, e.g. a file +logger and a console logger. Requires C++ 20 or higher. diff --git a/ASWLog/ASWLog_NullLog.h b/ASWLog/ASWLog_NullLog.h index 52a654e..03fdb42 100644 --- a/ASWLog/ASWLog_NullLog.h +++ b/ASWLog/ASWLog_NullLog.h @@ -2,7 +2,10 @@ ASWLog_NullLog.h Author: Anthony S. West - ASW Software -A light-weight logging tool. +A logging library. + +TASWNullLog, a logger that writes nothing, e.g. to turn logging off without +changing the code that logs, or to pass to code under test. Requires C++ 20 or higher. diff --git a/ASWLog/ASWLog_SyslogLog.h b/ASWLog/ASWLog_SyslogLog.h index 013dec8..a2e126f 100644 --- a/ASWLog/ASWLog_SyslogLog.h +++ b/ASWLog/ASWLog_SyslogLog.h @@ -2,7 +2,10 @@ ASWLog_SyslogLog.h Author: Anthony S. West - ASW Software -A light-weight logging tool. +A logging library. + +TASWSyslogLog, a text logger that sends its lines to the Linux system log +(and the systemd journal); it writes nothing on Windows. Requires C++ 20 or higher. diff --git a/ASWLog/ASWLog_TextLogBase.h b/ASWLog/ASWLog_TextLogBase.h index 69c49b9..bbcc4cb 100644 --- a/ASWLog/ASWLog_TextLogBase.h +++ b/ASWLog/ASWLog_TextLogBase.h @@ -2,7 +2,11 @@ ASWLog_TextLogBase.h Author: Anthony S. West - ASW Software -A light-weight logging tool. +A logging library. + +TASWTextLogBase, the base of the loggers that write each entry as a line of +text: locking, formatting, asynchronous writing and the startup lines. A +custom text logger derives from it and implements only its output. Requires C++ 20 or higher. diff --git a/ASWLog/ASWLog_Types.h b/ASWLog/ASWLog_Types.h index 95ea589..de6855f 100644 --- a/ASWLog/ASWLog_Types.h +++ b/ASWLog/ASWLog_Types.h @@ -2,9 +2,10 @@ ASWLog_Types.h Author: Anthony S. West - ASW Software -A light-weight logging tool. +A logging library. -Source for the ASWLog types. +The basic types: Level and the other enums, TASWLogRecord (an entry as a +logger receives it) and TASWLogError (a logger's internal failure). Requires C++ 20 or higher. diff --git a/ASWLog/ASWLog_Unicode.h b/ASWLog/ASWLog_Unicode.h index e64cb93..0f68a10 100644 --- a/ASWLog/ASWLog_Unicode.h +++ b/ASWLog/ASWLog_Unicode.h @@ -4,8 +4,9 @@ Author: Anthony S. West - ASW Software A logging library. -Source for logging wide (UTF-16 and UTF-32) text: conversions to and from UTF-8, and the text wrappers the logging -methods and the *Fmt arguments take. +Wide-string support: TASWWideText (wchar_t and char16_t messages), the +Wide() and UTF8() wrappers for *Fmt arguments, and conversions between +UTF-8 and UTF-16 or UTF-32. Requires C++ 20 or higher. diff --git a/ASWLog/ASWLog_Utils.h b/ASWLog/ASWLog_Utils.h index 99d1bf5..0613531 100644 --- a/ASWLog/ASWLog_Utils.h +++ b/ASWLog/ASWLog_Utils.h @@ -2,9 +2,10 @@ ASWLog_Utils.h Author: Anthony S. West - ASW Software -A light-weight logging tool. +A logging library. -Source for the ASWLog utility functions, etc. +Helpers the loggers use, which an application can use too: log file names, +process and system information, paths, time formatting and JSON escaping. Requires C++ 20 or higher. diff --git a/ASWLog/ASWLog_Version.h b/ASWLog/ASWLog_Version.h index cb65b4a..cb787d0 100644 --- a/ASWLog/ASWLog_Version.h +++ b/ASWLog/ASWLog_Version.h @@ -2,7 +2,10 @@ ASWLog_Version.h Author: Anthony S. West - ASW Software -Single source for the ASWLog semantic version (https://semver.org). +A logging library. + +The ASWLog version (https://semver.org), as macros and constants: the only +place where the version is set. Requires C++ 20 or higher. diff --git a/ASWLog/ASWLog_WindowsEventLog.h b/ASWLog/ASWLog_WindowsEventLog.h index 787075d..048fcfe 100644 --- a/ASWLog/ASWLog_WindowsEventLog.h +++ b/ASWLog/ASWLog_WindowsEventLog.h @@ -4,6 +4,9 @@ Author: Anthony S. West - ASW Software A logging library. +TASWWindowsEventLog, a text logger that reports its lines to the Windows +Event Log; it writes nothing on other platforms. + Requires C++ 20 or higher. Copyright 2026 ASW Software diff --git a/CMakeLists.txt b/CMakeLists.txt index 0117f0b..e881b47 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -13,6 +13,8 @@ endforeach() project(ASWLog VERSION ${ASWLOG_VERSION_MAJOR}.${ASWLOG_VERSION_MINOR}.${ASWLOG_VERSION_PATCH} + DESCRIPTION "A thread-safe, dependency-free C++20 logging library for Windows and Linux" + HOMEPAGE_URL "https://github.com/ASWSoftware/asw-log" LANGUAGES CXX ) diff --git a/README.md b/README.md index 3f4ce05..80f9265 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,14 @@ # ASWLog - https://github.com/ASWSoftware/asw-log -ASWLog is a thread-safe light-weight C++ logging tool for Windows and Linux projects. +ASWLog is a thread-safe, dependency-free C++20 logging library for Windows and Linux. + +## Design + +ASWLog is a folder of standard C++ sources, or one CMake target, with no third-party code. Its defaults put crash +durability first: a logging call is synchronous and every entry is flushed before the call returns, so the last +entries before a crash are in the file. A call below the logger's level costs a few nanoseconds, so Debug and Trace +calls can stay in release builds and be turned on at run time. The rest (asynchronous writing, backtrace, JSON and +pattern formatters, crash handlers, and the other extras below) is opt-in. ## Features @@ -67,7 +75,7 @@ ASWLog is a thread-safe light-weight C++ logging tool for Windows and Linux proj # Donations: -If you find this tool helpful, donations are always appreciated: +If you find this library helpful, donations are always appreciated: PayPal: donate@aswsoftware.com From b693e6ced2a3f27fc75023ac4a34d92b7ee74c33 Mon Sep 17 00:00:00 2001 From: Anthony West Date: Sat, 10 Oct 2026 18:15:33 -0700 Subject: [PATCH 02/12] Update documentation in prep for 1.0 --- AGENTS.md | 4 +- Deploy.bat | 7 ++ README.md | 126 ++++++++++++++++++++++++- docs/Configuration.md | 211 ++++++++++++++++++++++++++++++++++++++++++ docs/CustomLoggers.md | 155 +++++++++++++++++++++++++++++++ docs/Guarantees.md | 93 +++++++++++++++++++ example/src/main.cpp | 36 +++++-- 7 files changed, 620 insertions(+), 12 deletions(-) create mode 100644 docs/Configuration.md create mode 100644 docs/CustomLoggers.md create mode 100644 docs/Guarantees.md diff --git a/AGENTS.md b/AGENTS.md index 2e0badf..670ad39 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -15,7 +15,8 @@ ASWLog is a thread-safe, dependency-free C++20 logging library for Windows and L - `.github/workflows/ci.yml` builds and runs the unit tests on Windows (MSVC, MinGW) and Linux (GCC, Clang), plus Linux Clang builds with ThreadSanitizer and with AddressSanitizer + UBSan (`ASWLOG_SANITIZE`); the non-sanitizer jobs also check the installed CMake package (`tests/package/`). - `example/` contains example app that uses the logger. - `example/rad370/` contains the RAD Studio 13.1 project and Windows build scripts. -- `README.md` contains repo details. +- `README.md` contains repo details: features, quick start, project setup, API overview, versions and tests. +- `docs/` contains the reference documentation: `Configuration.md` (every `TASWLogConfig` setting, its default and which loggers use it, and the environment variables), `Guarantees.md` (thread safety, order, callback threads, lifetimes, crash durability) and `CustomLoggers.md` (custom formatters and loggers). - `CHANGELOG.md` records notable changes per release (see Changelog below). - `CONTRIBUTING.md` contains the guidelines for contributors (issues, branches, commit history, pull requests, and bug reports); it defers to this file for coding rules, so keep the two consistent. - `.uncrustify.cfg` and `.githooks/` define the repository formatting workflow. @@ -54,6 +55,7 @@ Prefer standard C++ and portable library facilities. Avoid compiler-, IDE-, or o - Follow the surrounding naming, indentation, brace, include, and comment style. Avoid unrelated formatting changes. - Keep declarations and definitions consistent, and update all relevant project or build files when adding source files. - Add or update focused tests for behavior changes, including error and platform-specific cases where applicable. +- Keep the documentation in step: a new or changed `TASWLogConfig` setting or environment key goes in `docs/Configuration.md`, a new logger in the README's API overview, and a change to threading, lifetimes or durability in `docs/Guarantees.md`. Add a new docs file to `Deploy.bat`. ## Building and Testing diff --git a/Deploy.bat b/Deploy.bat index 8657210..d85cd89 100644 --- a/Deploy.bat +++ b/Deploy.bat @@ -67,6 +67,13 @@ if errorlevel 1 exit /b 1 call :CopyFile "cmake\ASWLogConfig.cmake.in" "%TARGET_DIR%\cmake\ASWLogConfig.cmake.in" if errorlevel 1 exit /b 1 +call :CopyFile "docs\Configuration.md" "%TARGET_DIR%\docs\Configuration.md" +if errorlevel 1 exit /b 1 +call :CopyFile "docs\CustomLoggers.md" "%TARGET_DIR%\docs\CustomLoggers.md" +if errorlevel 1 exit /b 1 +call :CopyFile "docs\Guarantees.md" "%TARGET_DIR%\docs\Guarantees.md" +if errorlevel 1 exit /b 1 + call :CopyFile "ASWLog\ASWLog_Base.cpp" "%TARGET_DIR%\ASWLog\ASWLog_Base.cpp" if errorlevel 1 exit /b 1 call :CopyFile "ASWLog\ASWLog_Base.h" "%TARGET_DIR%\ASWLog\ASWLog_Base.h" diff --git a/README.md b/README.md index 80f9265..766fd92 100644 --- a/README.md +++ b/README.md @@ -55,6 +55,10 @@ pattern formatters, crash handlers, and the other extras below) is opt-in. - Rate-limited logging for entries that can repeat often: `ASWLOG_ONCE`, `ASWLOG_EVERY_N` and `ASWLOG_EVERY_INTERVAL` (`ASWLog_Limiter.h`), e.g. `ASWLOG_EVERY_INTERVAL(log, std::chrono::seconds(5), ASWLog::Level::Warn, "Retrying {}", host);`, which counts the skipped entries in a `suppressed` field. +- Settings from environment variables (`TASWLogConfig::ApplyEnvironment()`), e.g. `ASWLOG_LEVEL=Trace` to see + everything a deployed release build logs, without rebuilding it. +- Wide-string messages: every logging method also takes `wchar_t` or `char16_t` text (e.g. `L"..."`, a + `std::wstring`, or C++Builder's `UnicodeString::c_str()`), converted to UTF-8 only if the entry is written. - A hook to drop or change entries before they are written (`TASWLogConfig::OnBeforeWrite`), e.g. to redact secrets or drop noisy entries by content, category or field. - Structured fields per entry, e.g. `logger.LogInfo("Order placed", {{"orderId", 17}})`, and scoped context that every @@ -85,13 +89,64 @@ Bitcoin: # How to Use -Add the source in `ASWLog` to your C++ project. +## Quick start -## CMake +```cpp +#include "ASWLog_CrashHandler.h" +#include "ASWLog_FileLog.h" + +int main() +{ + ASWLog::TASWLogConfig config; + config.File.FilePath = "myapp.txt"; // In the "logs" folder + config.ApplyEnvironment(); // Optional: e.g. ASWLOG_LEVEL=Debug overrides the level + + auto& log = ASWLog::TASWFileLog::GetInstance(); + if (!log.Initialize(config)) + return 1; + + ASWLog::InstallCrashHandlers(); // Flushes the log and adds a "Crash:" line if the application crashes + + log.LogInfo("Started"); + log.LogWarnFmt("Disk {} is {}% full", "C:", 93); // Checked against its arguments at compile time + log.LogInfo("Order placed", { { "orderId", 17 }, { "total", 9.99 } }); + log.LogDebug("Not written: below the minimum level (Info by default)"); + + return 0; +} +``` + +writes `logs/myapp.txt`, after the startup lines (time, OS, drive, memory, application; see `TASWLogConfig::Startup`): + +```text +[2026-10-11T00:24:25.089Z][INFO][P:6180][T:6648]: Started +[2026-10-11T00:24:25.089Z][WARN][P:6180][T:6648]: Disk C: is 93% full +[2026-10-11T00:24:25.089Z][INFO][P:6180][T:6648][orderId=17 total=9.99]: Order placed +[2026-10-11T00:24:25.089Z][INFO][P:6180][T:6648]: Logger shutdown: 2026-10-11T00:24:25.089Z +``` + +The `example/src/main.cpp` app shows more: console, multi-log, categories, scopes, rate limiting and wide text. + +## Adding ASWLog to a project + +### Copied sources (any build system) + +Add every `.cpp` file in `ASWLog/` to the project, and the `ASWLog` folder to its include path, and compile as C++20. +On Windows, link `psapi` and `advapi32` (RAD Studio links them by default); on Linux, the threads library +(`-pthread`). `Deploy.bat ` copies the library sources, the examples and the docs to a folder, e.g. for a +release package. + +### RAD Studio + +Add the `ASWLog/*.cpp` files to the project (Project > Add to Project) and the `ASWLog` folder to the include path +(Project > Options > Building > C++ Shared Options > Include path). RAD Studio 13.1 or later with the modern Clang +toolchain (Win64x). `example/rad370/ASWLogExample.cbproj` is a working project to copy settings from. + +### CMake The repository's root `CMakeLists.txt` defines the static library target `ASWLog::ASWLog`. Linking to it adds the -`ASWLog` include folder, C++20, and the system libraries the logger needs (the threads library, and `psapi` on -Windows). Add it from a copy of the repository, such as a git submodule: +`ASWLog` include folder, C++20, and the system libraries the logger needs (the threads library, and `psapi` and +`advapi32` on Windows). Add it from a copy of the repository, such as a git submodule: ``` add_subdirectory(third_party/asw-log) @@ -146,6 +201,60 @@ cmake --build example/cmake/build --config Release The executable is written to `example/build/bin/Release/ASWLogExample.exe`, alongside RAD Studio output. +## API overview + +**Loggers.** Each implements `ASWLog::IASWLog` (`ASWLog_Interface.h`), so code that logs can take an `IASWLog&` and +not care where the entries go. Most have a `GetInstance()` singleton, and any of them can also be created as an +ordinary object. + +| Class | Header | Writes to | +|---|---|---| +| `TASWFileLog` | `ASWLog_FileLog.h` | A file, with rotation, daily rolling and backup cleanup | +| `TASWConsoleLog` | `ASWLog_ConsoleLog.h` | stdout, and stderr for Warn and above, in color on a terminal | +| `TASWDebuggerLog` | `ASWLog_DebuggerLog.h` | The debugger's output (Windows) | +| `TASWMemoryLog` | `ASWLog_MemoryLog.h` | Memory: the newest lines, e.g. for an in-app log viewer | +| `TASWSyslogLog` | `ASWLog_SyslogLog.h` | The system log and the systemd journal (Linux) | +| `TASWWindowsEventLog` | `ASWLog_WindowsEventLog.h` | The Windows Event Log (Windows) | +| `TASWNullLog` | `ASWLog_NullLog.h` | Nothing | +| `TASWMultiLog` | `ASWLog_MultiLog.h` | Several loggers at once, e.g. a file and the console | +| `TASWCategoryLog` | `ASWLog_CategoryLog.h` | Another logger, marking the entries with a category (e.g. `[Net]`) that can have a level of its own | + +The loggers that write to only one platform build on both and write nothing on the other, so the same code can add +them everywhere. + +**Logging.** On any logger: + +- `LogTrace()`, `LogDebug()`, `LogInfo()`, `LogWarn()`, `LogError()`, `LogCritical()`, and `Log(level, ...)`. +- `LogInfoFmt("Opened {} in {} ms", name, ms)` and the other `*Fmt` methods: `std::format`, with the format string + checked against its arguments at compile time (wrap a format string built at run time in `ASWLog::RuntimeFormat()`). + An entry below the minimum level isn't formatted. +- `LogRaw()` writes the message as it is, without the line layout; `LogForce()` and `LogForceRaw()` write it whatever + the minimum level. +- Fields: `LogInfo("Order placed", {{"orderId", 17}})`, `LogInfoFmt({{"orderId", id}}, "Order {} placed", id)`, and + `ASWLog::TASWLogScope scope{{"requestId", id}};` for fields that every entry on the thread carries while it exists + (`ASWLog_Fields.h`). +- Wide text: `LogInfo(L"...")`, `LogInfoFmt(L"... {}", ...)`, and `ASWLog::Wide(text)` / `ASWLog::UTF8(text)` for + arguments (`ASWLog_Unicode.h`). +- The caller's function and source line are captured automatically (shown with `Line.ShowFunctionName` and + `Line.ShowSourceLine`). + +**Control.** `Initialize(config)`, `Reconfigure(config)`, `GetConfig()`, `SetMinimumLevel()`, `ShouldLog(level)` (to +skip building an expensive message), `SetEnabled()`, `Flush()`, `Open()`, `Close()` and `DumpBacktrace()`; a file +logger also has `RotateLogFiles()` and `DeleteOldLogs()`. + +**More.** `ASWLog::InstallCrashHandlers()` (`ASWLog_CrashHandler.h`), the `ASWLOG_ONCE`, `ASWLOG_EVERY_N` and +`ASWLOG_EVERY_INTERVAL` macros (`ASWLog_Limiter.h`), `TASWLogConfig::ApplyEnvironment()`, the formatters +(`ASWLog_Formatter.h`), and the version (`ASWLog_Version.h`). The header comments document every class and method. + +## Documentation + +- [docs/Configuration.md](docs/Configuration.md): every setting, its default, and which loggers use it, plus the + environment variables. +- [docs/Guarantees.md](docs/Guarantees.md): thread safety, the order of entries, which thread runs each callback, + object lifetimes, and choosing settings for crash durability. +- [docs/CustomLoggers.md](docs/CustomLoggers.md): writing a formatter or a logger of your own. +- [CHANGELOG.md](CHANGELOG.md): the changes in each release. + ## Versions ASWLog follows [Semantic Versioning](https://semver.org). Releases are tagged on `main` (e.g. `v1.1.0`). Between @@ -161,6 +270,15 @@ and as constants in the `ASWLog` namespace: #endif ``` +### Upgrading from 0.x + +1.0.0 is the first release with a stable interface; the 0.x releases changed it as the design settled. The releases +that can need changes in code that uses ASWLog are 0.43.0, 0.45.0, 0.65.0, 0.75.0 (only for a class that implements +`IASWLog` directly) and 1.0.0. In [CHANGELOG.md](CHANGELOG.md), read the **Changed** and **Removed** sections, and +the entries marked "Breaking", of every release after the one you use: each says what existing code must change. +Projects that list the ASWLog sources must also add the files that new releases added (the CHANGELOG names them, e.g. +`ASWLog_Unicode.cpp`). + # Unit Tests Using the logger only requires the `ASWLog` source. The unit tests in `tests` additionally use the diff --git a/docs/Configuration.md b/docs/Configuration.md new file mode 100644 index 0000000..de42c30 --- /dev/null +++ b/docs/Configuration.md @@ -0,0 +1,211 @@ +# Configuration reference + +Every logger takes a `ASWLog::TASWLogConfig` (`ASWLog_Config.h`) in `Initialize()`. Its settings are grouped by +concern, and a logger ignores the groups it doesn't use, so one config can be passed to several loggers (a multi-log +passes its config on to the loggers it holds). + +```cpp +ASWLog::TASWLogConfig config; +config.InitialMinimumLevel = ASWLog::Level::Debug; +config.File.FolderPath = "logs"; +config.File.FilePath = "myapp.txt"; +config.File.EnableRotation = true; +config.ApplyEnvironment(); // Optional: lets ASWLOG_* environment variables override the settings (see below) + +auto& log = ASWLog::TASWFileLog::GetInstance(); +log.Initialize(config); +``` + +To change the settings of a running logger, copy its current config, change the copy, and pass it to `Reconfigure()`, +which is safe while other threads log: + +```cpp +auto config = *log.GetConfig(); +config.Line.ShowThreadId = false; +log.Reconfigure(config); +``` + +`Reconfigure()` doesn't change the minimum level (use `SetMinimumLevel()`) and doesn't write the startup lines again. + +The header comments in `ASWLog_Config.h` have the full details of each setting; this page is the overview. + +## Which logger uses what + +| Group | Used by | +|---|---| +| `InitialMinimumLevel` | Every logger, including the multi-log (its own pre-filter) | +| `Line`, `Startup`, `Shutdown`, `Async` | The text loggers: file, console, debugger, memory, syslog, Windows Event Log, and loggers derived from `TASWTextLogBase` | +| `File` | `TASWFileLog` | +| `Backtrace` | Every logger except the multi-log (each of its loggers keeps its own), the category logger and the null logger | +| `Memory` | `TASWMemoryLog` | +| `Syslog` | `TASWSyslogLog` | +| `EventLog` | `TASWWindowsEventLog` | +| `OnBeforeWrite` | Every logger; a multi-log calls its own once per entry, before passing the entry on | +| `OnLogEntry`, `OnLogEntryMinimumLevel` | The text loggers | +| `OnError`, `ErrorReportInterval` | Every logger; a multi-log passes them on, and each of its loggers reports its own failures | + +A category logger (`TASWCategoryLog`) and the null logger (`TASWNullLog`) take no config: the category's output +belongs to the logger it wraps. + +## Top level + +| Setting | Default | What it does | +|---|---|---| +| `InitialMinimumLevel` | `Level::Info` | The minimum level `Initialize()` sets. Change it later with `SetMinimumLevel()`; this field doesn't follow it. | +| `OnBeforeWrite` | empty | Called for each entry that passes the level checks, before it is written: return `false` to drop it, or change it with `entry.SetMessage()`, `SetField()` or `RemoveField()` (e.g. to redact secrets). Runs on the logging thread, before the logger's lock, possibly on several threads at once. | +| `OnLogEntry` | empty | Called after an entry at or above `OnLogEntryMinimumLevel` was written, with the record and the line as written (e.g. for alerting). Runs outside the logger's lock; with `Async.Enabled`, on the logger's own thread. Exceptions are swallowed. | +| `OnLogEntryMinimumLevel` | `Level::Error` | The level an entry needs for `OnLogEntry`. `Level::Off` = never. | +| `OnError` | empty | Receives the logger's internal failures (a file that can't be opened, written, flushed or rotated, an invalid setting, ...) as a `TASWLogError`. Empty: each is written to stderr as one line. Runs outside the logger's lock. | +| `ErrorReportInterval` | 1 minute | Each kind of failure is reported at most once per interval; the next report says how many were left out. 0 = report every failure. | + +## `Line`: the line layout (`TASWLineConfig`) + +| Setting | Default | What it does | +|---|---|---| +| `Formatter` | empty | Formats each line. Empty: the built-in layout (`TASWTextFormatter`) from the `Show*` settings. Assign a `TASWPatternFormatter` (e.g. `"{time} {level:5} {message}"`), a `TASWJSONFormatter` (JSON Lines) or your own `IASWLogFormatter`. One formatter can be shared by several loggers. | +| `Ending` | `LineEnding::LF` | Added after each formatted line (`LF` or `CRLF`); not after `LogRaw()` entries written as they are. | +| `Multiline` | `MultilineMode::Preserve` | The line breaks inside an entry: written as they are (`Preserve`), each followed by ` \| ` (`Indent`), or as `\r` and `\n` (`Escape`). | +| `TimestampZone` | `TimeZone::UTC` | `UTC` (e.g. `2026-09-28T21:02:44.342Z`) or `Local` (e.g. `2026-09-28T16:02:44.342-05:00`). Also sets when daily rolling starts a new file and the time in backup names. | +| `TimestampPrecision` | `TimePrecision::Milliseconds` | `Milliseconds`, `Microseconds` or `Nanoseconds`. | +| `ShowTimestamp` | `true` | The entry's time. | +| `ShowLevel` | `true` | The entry's level, e.g. `[INFO]`. | +| `ShowCategory` | `true` | The entry's category, e.g. `[Net]`, if it has one. | +| `ShowProcessId` | `true` | The OS process id. | +| `ShowThreadId` | `true` | The OS id of the thread that logged the entry. | +| `ShowWorkingSet` | `false` | The process's memory use. | +| `ShowPeakWorkingSet` | `false` | The process's peak memory use. | +| `ShowFunctionName` | `false` | The function that logged the entry. | +| `ShowSourceLine` | `false` | The source file and line that logged the entry. | +| `ShowFields` | `true` | The entry's fields (its own and its scopes'), if it has any. | + +The `Show*` settings are read by the built-in layout and by `TASWJSONFormatter`; a pattern decides its own fields. + +## `Startup`: the lines `Initialize()` writes (`TASWStartupConfig`) + +| Setting | Default | What it does | +|---|---|---| +| `Banner` | empty | A line written first, if set. | +| `WriteApplicationInfo` | `true` | The executable's path and build target, e.g. `App: app_exe='C:\MyApp\MyApp.exe', app_target=Win64`. | +| `WriteCommandLine` | `false` | The command line, added to the application line. | +| `WriteDriveInfo` | `true` | The disk's total, free and used space. | +| `WriteMemoryUsage` | `true` | The process's memory use (working set and peak). | +| `WriteOSInfo` | `true` | The operating system, its version and the architecture. | +| `WriteSystemMemoryInfo` | `true` | The system's total and available memory. | +| `WriteTimeInfo` | `true` | The time in UTC, and in local time with its offset. | + +## `Shutdown`: the lines at shutdown and on a crash (`TASWShutdownConfig`) + +| Setting | Default | What it does | +|---|---|---| +| `WriteLine` | `true` | "Logger shutdown: