diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml index 4e97d077..a7a61dd3 100644 --- a/.github/workflows/linux.yml +++ b/.github/workflows/linux.yml @@ -18,9 +18,8 @@ jobs: fail-fast: false matrix: config: - - { compiler: gcc, version: 7, build_type: Release, cppstd: 11 } - - { compiler: gcc, version: 9, build_type: Release, cppstd: 17 } - - { compiler: gcc, version: 11, build_type: Debug, cppstd: 20 } + - { compiler: gcc, version: 9, build_type: Release, cppstd: 11 } + - { compiler: gcc, version: 11, build_type: Debug, cppstd: 17 } - { compiler: gcc, version: 12, build_type: Release, cppstd: 20 } - { compiler: gcc, version: 12, build_type: Debug, cppstd: 20, asan: ON } - { compiler: clang, version: 12, build_type: Debug, cppstd: 17 } diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index 710e4090..e3b547c8 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -75,74 +75,5 @@ jobs: run: | build\tests\${{ matrix.config.BUILD_TYPE }}\spdlog-utests.exe - # ----------------------------------------------------------------------- - # MSVC 2019 build matrix - # ----------------------------------------------------------------------- - build_2019: - runs-on: windows-2019 - strategy: - fail-fast: true - matrix: - config: - - GENERATOR: "Visual Studio 16 2019" - BUILD_TYPE: Release - BUILD_SHARED: 'ON' - FATAL_ERRORS: 'ON' - WCHAR: 'OFF' - WCHAR_FILES: 'OFF' - BUILD_EXAMPLE: 'ON' - USE_STD_FORMAT: 'OFF' - CXX_STANDARD: 17 - - GENERATOR: "Visual Studio 16 2019" - BUILD_TYPE: Release - BUILD_SHARED: 'ON' - FATAL_ERRORS: 'ON' - WCHAR: 'OFF' - WCHAR_FILES: 'OFF' - BUILD_EXAMPLE: 'ON' - USE_STD_FORMAT: 'OFF' - CXX_STANDARD: 14 - - GENERATOR: "Visual Studio 16 2019" - BUILD_TYPE: Release - BUILD_SHARED: 'ON' - FATAL_ERRORS: 'ON' - WCHAR: 'OFF' - WCHAR_FILES: 'OFF' - BUILD_EXAMPLE: 'ON' - USE_STD_FORMAT: 'OFF' - CXX_STANDARD: 11 - - steps: - - name: Checkout code - uses: actions/checkout@v4 - - name: CMake ${{ matrix.config.GENERATOR }} CXX=${{matrix.config.CXX_STANDARD}} WCHAR=${{matrix.config.WCHAR_FILES}} STD_FORMAT=${{matrix.config.USE_STD_FORMAT}} - shell: pwsh - run: | - mkdir build - cd build - cmake -G "${{ matrix.config.GENERATOR }}" -A x64 ` - -D CMAKE_BUILD_TYPE=${{ matrix.config.BUILD_TYPE }} ` - -D BUILD_SHARED_LIBS=${{ matrix.config.BUILD_SHARED }} ` - -D SPDLOG_WCHAR_SUPPORT=${{ matrix.config.WCHAR }} ` - -D SPDLOG_WCHAR_FILENAMES=${{ matrix.config.WCHAR_FILES }} ` - -D SPDLOG_BUILD_EXAMPLE=${{ matrix.config.BUILD_EXAMPLE }} ` - -D SPDLOG_BUILD_EXAMPLE_HO=${{ matrix.config.BUILD_EXAMPLE }} ` - -D SPDLOG_BUILD_TESTS=ON ` - -D SPDLOG_BUILD_TESTS_HO=OFF ` - -D SPDLOG_BUILD_WARNINGS=${{ matrix.config.FATAL_ERRORS }} ` - -D SPDLOG_USE_STD_FORMAT=${{ matrix.config.USE_STD_FORMAT }} ` - -D CMAKE_CXX_STANDARD=${{ matrix.config.CXX_STANDARD }} .. - - - name: Build - shell: pwsh - run: | - cd build - cmake --build . --parallel --config ${{ matrix.config.BUILD_TYPE }} - - - name: Run Tests - shell: pwsh - env: - PATH: ${{ env.PATH }};${{ github.workspace }}\build\_deps\catch2-build\src\${{ matrix.config.BUILD_TYPE }};${{ github.workspace }}\build\${{ matrix.config.BUILD_TYPE }} - run: | - build\tests\${{ matrix.config.BUILD_TYPE }}\spdlog-utests.exe + diff --git a/CMakeLists.txt b/CMakeLists.txt index 3368e4dd..882aa90e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -62,6 +62,9 @@ option(SPDLOG_ENABLE_PCH "Build static or shared library using precompiled heade # build position independent code option(SPDLOG_BUILD_PIC "Build position independent code (-fPIC)" OFF) +# debug build postfix +set(SPDLOG_DEBUG_POSTFIX "d" CACHE STRING "Filename postfix for libraries in debug builds") + # example options option(SPDLOG_BUILD_EXAMPLE "Build example" ${SPDLOG_MASTER_PROJECT}) option(SPDLOG_BUILD_EXAMPLE_HO "Build header only example" OFF) @@ -191,7 +194,7 @@ spdlog_enable_warnings(spdlog) set_target_properties(spdlog PROPERTIES VERSION ${SPDLOG_VERSION} SOVERSION ${SPDLOG_VERSION_MAJOR}.${SPDLOG_VERSION_MINOR}) -set_target_properties(spdlog PROPERTIES DEBUG_POSTFIX d) +set_target_properties(spdlog PROPERTIES DEBUG_POSTFIX ${SPDLOG_DEBUG_POSTFIX}) if(COMMAND target_precompile_headers AND SPDLOG_ENABLE_PCH) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/cmake/pch.h.in ${PROJECT_BINARY_DIR}/spdlog_pch.h @ONLY) diff --git a/README.md b/README.md index e8c8c31d..a558a6e4 100644 --- a/README.md +++ b/README.md @@ -80,7 +80,7 @@ int main() spdlog::info("Positional args are {1} {0}..", "too", "supported"); spdlog::info("{:<30}", "left aligned"); - spdlog::set_level(spdlog::level::debug); // Set global log level to debug + spdlog::set_level(spdlog::level::debug); // Set *global* log level to debug spdlog::debug("This message should be displayed.."); // change log pattern @@ -224,7 +224,7 @@ void binary_example() ```c++ // create a logger with 2 targets, with different log levels and formats. -// The console will show only warnings or errors, while the file will log all. +// The console will show only warnings or errors, while the file will log all. void multi_sink_example() { auto console_sink = std::make_shared(); @@ -241,6 +241,29 @@ void multi_sink_example() } ``` +--- +#### Register several loggers - change global level +```c++ + +// Creation of loggers. Set levels to all registered loggers. +void set_level_example() +{ + auto logger1 = spdlog::basic_logger_mt("logger1", "logs/logger1.txt"); + auto logger2 = spdlog::basic_logger_mt("logger2", "logs/logger2.txt"); + + spdlog::set_default_logger(logger2); + spdlog::default_logger()->set_level(spdlog::level::trace); // set level for the default logger (logger2) to trace + + spdlog::trace("trace message to the logger2 (specified as default)"); + + spdlog::set_level(spdlog::level::off) // (sic!) set level for *all* registered loggers to off (disable) + + logger1.warn("warn message will not appear because the level set to off"); + logger2.warn("warn message will not appear because the level set to off"); + spdlog::warn("warn message will not appear because the level set to off"); +} +``` + --- #### User-defined callbacks about log events ```c++ diff --git a/include/spdlog/sinks/ringbuffer_sink.h b/include/spdlog/sinks/ringbuffer_sink.h index 6156c6a5..bcdf0ffc 100644 --- a/include/spdlog/sinks/ringbuffer_sink.h +++ b/include/spdlog/sinks/ringbuffer_sink.h @@ -21,7 +21,11 @@ template class ringbuffer_sink final : public base_sink { public: explicit ringbuffer_sink(size_t n_items) - : q_{n_items} {} + : q_{n_items} { + if (n_items == 0) { + throw_spdlog_ex("ringbuffer_sink: n_items cannot be zero"); + } + } std::vector last_raw(size_t lim = 0) { std::lock_guard lock(base_sink::mutex_); diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index f6b17272..457504c3 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -49,7 +49,8 @@ set(SPDLOG_UTESTS_SOURCES test_time_point.cpp test_stopwatch.cpp test_circular_q.cpp - test_bin_to_hex.cpp) + test_bin_to_hex.cpp + test_ringbuffer.cpp) if(NOT SPDLOG_NO_EXCEPTIONS) list(APPEND SPDLOG_UTESTS_SOURCES test_errors.cpp) diff --git a/tests/test_ringbuffer.cpp b/tests/test_ringbuffer.cpp new file mode 100644 index 00000000..da473df5 --- /dev/null +++ b/tests/test_ringbuffer.cpp @@ -0,0 +1,53 @@ +#include "includes.h" +#include "spdlog/sinks/ringbuffer_sink.h" + +TEST_CASE("ringbuffer invalid size", "[ringbuffer]") { + REQUIRE_THROWS_AS(spdlog::sinks::ringbuffer_sink_mt(0), spdlog::spdlog_ex); +} + +TEST_CASE("ringbuffer stores formatted messages", "[ringbuffer]") { + spdlog::sinks::ringbuffer_sink_st sink(3); + sink.set_pattern("%v"); + + sink.log(spdlog::details::log_msg{"test", spdlog::level::info, "msg1"}); + sink.log(spdlog::details::log_msg{"test", spdlog::level::info, "msg2"}); + sink.log(spdlog::details::log_msg{"test", spdlog::level::info, "msg3"}); + + auto formatted = sink.last_formatted(); + REQUIRE(formatted.size() == 3); + using spdlog::details::os::default_eol; + REQUIRE(formatted[0] == spdlog::fmt_lib::format("msg1{}", default_eol)); + REQUIRE(formatted[1] == spdlog::fmt_lib::format("msg2{}", default_eol)); + REQUIRE(formatted[2] == spdlog::fmt_lib::format("msg3{}", default_eol)); +} + +TEST_CASE("ringbuffer overrun keeps last items", "[ringbuffer]") { + spdlog::sinks::ringbuffer_sink_st sink(2); + sink.set_pattern("%v"); + + sink.log(spdlog::details::log_msg{"test", spdlog::level::info, "first"}); + sink.log(spdlog::details::log_msg{"test", spdlog::level::info, "second"}); + sink.log(spdlog::details::log_msg{"test", spdlog::level::info, "third"}); + + auto formatted = sink.last_formatted(); + REQUIRE(formatted.size() == 2); + using spdlog::details::os::default_eol; + REQUIRE(formatted[0] == spdlog::fmt_lib::format("second{}", default_eol)); + REQUIRE(formatted[1] == spdlog::fmt_lib::format("third{}", default_eol)); +} + +TEST_CASE("ringbuffer retrieval limit", "[ringbuffer]") { + spdlog::sinks::ringbuffer_sink_st sink(3); + sink.set_pattern("%v"); + + sink.log(spdlog::details::log_msg{"test", spdlog::level::info, "A"}); + sink.log(spdlog::details::log_msg{"test", spdlog::level::info, "B"}); + sink.log(spdlog::details::log_msg{"test", spdlog::level::info, "C"}); + + auto formatted = sink.last_formatted(2); + REQUIRE(formatted.size() == 2); + using spdlog::details::os::default_eol; + REQUIRE(formatted[0] == spdlog::fmt_lib::format("B{}", default_eol)); + REQUIRE(formatted[1] == spdlog::fmt_lib::format("C{}", default_eol)); +} +