From f1c106728b08beae5440d060dcc13138669f7765 Mon Sep 17 00:00:00 2001 From: Benjamin Sergeant Date: Sat, 11 Apr 2020 13:31:39 -0700 Subject: [PATCH] (third_party deps) fix #177, update bundled spdlog to 1.6.0 --- CMake/FindJsonCpp.cmake | 2 +- docs/CHANGELOG.md | 4 + ixwebsocket/IXWebSocketVersion.h | 2 +- .../spdlog/{scripts => }/.clang-format | 0 third_party/spdlog/{scripts => }/.clang-tidy | 41 ++- third_party/spdlog/.travis.yml | 1 + third_party/spdlog/CMakeLists.txt | 91 ++++-- third_party/spdlog/LICENSE | 4 + third_party/spdlog/README.md | 76 ++++- third_party/spdlog/appveyor.yml | 2 +- third_party/spdlog/bench/bench.cpp | 56 ++-- third_party/spdlog/bench/formatter-bench.cpp | 2 +- third_party/spdlog/bench/latency.cpp | 109 ++++--- third_party/spdlog/cmake/pch.h.in | 258 +++++++++++++++++ third_party/spdlog/cmake/spdlogCPack.cmake | 30 +- third_party/spdlog/cmake/utils.cmake | 23 +- third_party/spdlog/cmake/version.rc.in | 42 +++ third_party/spdlog/example/CMakeLists.txt | 6 +- third_party/spdlog/example/example.cpp | 50 +++- .../spdlog/include/spdlog/async_logger-inl.h | 4 +- .../spdlog/include/spdlog/async_logger.h | 2 +- third_party/spdlog/include/spdlog/cfg/argv.h | 45 +++ third_party/spdlog/include/spdlog/cfg/env.h | 36 +++ .../spdlog/include/spdlog/cfg/helpers-inl.h | 103 +++++++ .../spdlog/include/spdlog/cfg/helpers.h | 28 ++ .../spdlog/include/spdlog/cfg/log_levels.h | 47 ++++ .../spdlog/include/spdlog/common-inl.h | 19 ++ third_party/spdlog/include/spdlog/common.h | 35 +-- .../include/spdlog/details/backtracer.h | 2 +- .../include/spdlog/details/file_helper-inl.h | 8 +- .../include/spdlog/details/file_helper.h | 2 +- .../include/spdlog/details/fmt_helper.h | 28 +- .../spdlog/include/spdlog/details/log_msg.h | 2 +- .../include/spdlog/details/log_msg_buffer.h | 2 +- .../spdlog/include/spdlog/details/os-inl.h | 93 +++--- .../spdlog/include/spdlog/details/os.h | 50 ++-- .../include/spdlog/details/periodic_worker.h | 2 +- .../include/spdlog/details/registry-inl.h | 25 +- .../spdlog/include/spdlog/details/registry.h | 9 +- .../spdlog/details/tcp_client-windows.h | 175 ++++++++++++ .../include/spdlog/details/tcp_client.h | 145 ++++++++++ .../include/spdlog/details/thread_pool-inl.h | 6 +- .../include/spdlog/details/thread_pool.h | 2 +- .../include/spdlog/details/windows_include.h | 11 + .../spdlog/include/spdlog/fmt/bin_to_hex.h | 101 +++++-- .../include/spdlog/fmt/bundled/chrono.h | 11 +- .../include/spdlog/fmt/bundled/compile.h | 12 +- .../spdlog/include/spdlog/fmt/bundled/core.h | 20 +- .../include/spdlog/fmt/bundled/format.h | 61 +--- .../include/spdlog/fmt/bundled/printf.h | 30 +- third_party/spdlog/include/spdlog/fmt/fmt.h | 22 +- third_party/spdlog/include/spdlog/fmt/ostr.h | 6 +- third_party/spdlog/include/spdlog/fwd.h | 14 + .../spdlog/include/spdlog/logger-inl.h | 3 +- third_party/spdlog/include/spdlog/logger.h | 7 +- .../{details => }/pattern_formatter-inl.h | 48 +++- .../spdlog/{details => }/pattern_formatter.h | 37 ++- .../include/spdlog/sinks/android_sink.h | 2 +- .../include/spdlog/sinks/ansicolor_sink-inl.h | 7 +- .../include/spdlog/sinks/ansicolor_sink.h | 8 +- .../include/spdlog/sinks/base_sink-inl.h | 2 +- .../spdlog/include/spdlog/sinks/base_sink.h | 6 + .../include/spdlog/sinks/daily_file_sink.h | 41 ++- .../spdlog/include/spdlog/sinks/dist_sink.h | 2 +- .../spdlog/include/spdlog/sinks/msvc_sink.h | 1 + .../spdlog/sinks/rotating_file_sink-inl.h | 12 +- .../include/spdlog/sinks/rotating_file_sink.h | 6 +- .../spdlog/include/spdlog/sinks/sink.h | 2 +- .../include/spdlog/sinks/stdout_sinks-inl.h | 2 +- .../include/spdlog/sinks/stdout_sinks.h | 4 + .../include/spdlog/sinks/systemd_sink.h | 2 +- .../spdlog/include/spdlog/sinks/tcp_sink.h | 81 ++++++ .../include/spdlog/sinks/win_eventlog_sink.h | 266 ++++++++++++++++++ .../include/spdlog/sinks/wincolor_sink-inl.h | 7 +- .../include/spdlog/sinks/wincolor_sink.h | 6 +- .../spdlog/include/spdlog/spdlog-inl.h | 2 +- third_party/spdlog/include/spdlog/spdlog.h | 48 ++-- third_party/spdlog/include/spdlog/tweakme.h | 9 +- third_party/spdlog/include/spdlog/version.h | 2 +- .../spdlog/logos/jetbrains-variant-4.svg | 43 +++ third_party/spdlog/meson.build | 7 +- third_party/spdlog/scripts/clang_tidy.sh | 5 - third_party/spdlog/scripts/format.sh | 8 +- third_party/spdlog/src/async.cpp | 11 +- third_party/spdlog/src/cfg.cpp | 8 + third_party/spdlog/src/color_sinks.cpp | 38 +-- third_party/spdlog/src/file_sinks.cpp | 18 +- third_party/spdlog/src/fmt.cpp | 189 ++++++++++--- third_party/spdlog/src/spdlog.cpp | 30 +- third_party/spdlog/src/stdout_sinks.cpp | 34 +-- third_party/spdlog/tests/CMakeLists.txt | 12 +- third_party/spdlog/tests/includes.h | 3 +- third_party/spdlog/tests/meson.build | 3 +- third_party/spdlog/tests/test_async.cpp | 53 ++-- third_party/spdlog/tests/test_cfg.cpp | 93 ++++++ .../spdlog/tests/test_daily_logger.cpp | 9 +- third_party/spdlog/tests/test_dup_filter.cpp | 18 +- third_party/spdlog/tests/test_errors.cpp | 11 +- third_party/spdlog/tests/test_eventlog.cpp | 71 +++++ third_party/spdlog/tests/test_file_helper.cpp | 10 +- .../spdlog/tests/test_file_logging.cpp | 21 +- third_party/spdlog/tests/test_fmt_helper.cpp | 8 + third_party/spdlog/tests/test_macros.cpp | 7 +- third_party/spdlog/tests/test_misc.cpp | 77 ++++- third_party/spdlog/tests/test_mpmc_q.cpp | 11 +- .../spdlog/tests/test_pattern_formatter.cpp | 89 +++++- third_party/spdlog/tests/test_registry.cpp | 4 +- third_party/spdlog/tests/utils.cpp | 16 +- third_party/spdlog/tests/utils.h | 4 +- 109 files changed, 2792 insertions(+), 689 deletions(-) rename third_party/spdlog/{scripts => }/.clang-format (100%) rename third_party/spdlog/{scripts => }/.clang-tidy (58%) create mode 100644 third_party/spdlog/cmake/pch.h.in create mode 100644 third_party/spdlog/cmake/version.rc.in create mode 100644 third_party/spdlog/include/spdlog/cfg/argv.h create mode 100644 third_party/spdlog/include/spdlog/cfg/env.h create mode 100644 third_party/spdlog/include/spdlog/cfg/helpers-inl.h create mode 100644 third_party/spdlog/include/spdlog/cfg/helpers.h create mode 100644 third_party/spdlog/include/spdlog/cfg/log_levels.h create mode 100644 third_party/spdlog/include/spdlog/details/tcp_client-windows.h create mode 100644 third_party/spdlog/include/spdlog/details/tcp_client.h create mode 100644 third_party/spdlog/include/spdlog/details/windows_include.h create mode 100644 third_party/spdlog/include/spdlog/fwd.h rename third_party/spdlog/include/spdlog/{details => }/pattern_formatter-inl.h (96%) rename third_party/spdlog/include/spdlog/{details => }/pattern_formatter.h (67%) create mode 100644 third_party/spdlog/include/spdlog/sinks/tcp_sink.h create mode 100644 third_party/spdlog/include/spdlog/sinks/win_eventlog_sink.h create mode 100644 third_party/spdlog/logos/jetbrains-variant-4.svg delete mode 100755 third_party/spdlog/scripts/clang_tidy.sh create mode 100644 third_party/spdlog/src/cfg.cpp create mode 100644 third_party/spdlog/tests/test_cfg.cpp create mode 100644 third_party/spdlog/tests/test_eventlog.cpp diff --git a/CMake/FindJsonCpp.cmake b/CMake/FindJsonCpp.cmake index cdc6eabc..40032a19 100644 --- a/CMake/FindJsonCpp.cmake +++ b/CMake/FindJsonCpp.cmake @@ -5,7 +5,7 @@ include(FindPackageHandleStandardArgs) find_path(JSONCPP_INCLUDE_DIRS json/json.h) find_library(JSONCPP_LIBRARY jsoncpp) -find_package_handle_standard_args(JSONCPP +find_package_handle_standard_args(JsonCpp FOUND_VAR JSONCPP_FOUND REQUIRED_VARS diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index 3f5dd489..317eab6a 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -1,6 +1,10 @@ # Changelog All changes to this project will be documented in this file. +## [9.2.2] - 2020-04-04 + +(third_party deps) fix #177, update bundled spdlog to 1.6.0 + ## [9.2.1] - 2020-04-04 (windows) when using OpenSSL, the system store is used to populate the cacert. No need to ship a cacert.pem file with your app. diff --git a/ixwebsocket/IXWebSocketVersion.h b/ixwebsocket/IXWebSocketVersion.h index 96fed3f5..e49ce7c2 100644 --- a/ixwebsocket/IXWebSocketVersion.h +++ b/ixwebsocket/IXWebSocketVersion.h @@ -6,4 +6,4 @@ #pragma once -#define IX_WEBSOCKET_VERSION "9.2.1" +#define IX_WEBSOCKET_VERSION "9.2.2" diff --git a/third_party/spdlog/scripts/.clang-format b/third_party/spdlog/.clang-format similarity index 100% rename from third_party/spdlog/scripts/.clang-format rename to third_party/spdlog/.clang-format diff --git a/third_party/spdlog/scripts/.clang-tidy b/third_party/spdlog/.clang-tidy similarity index 58% rename from third_party/spdlog/scripts/.clang-tidy rename to third_party/spdlog/.clang-tidy index c3802ca0..f21675c9 100644 --- a/third_party/spdlog/scripts/.clang-tidy +++ b/third_party/spdlog/.clang-tidy @@ -1,19 +1,32 @@ -Checks: '\ -cppcoreguidelines-*,\ -performance-*,\ --performance-unnecessary-value-param,\ -modernize-*,\ --modernize-use-trailing-return-type,\ -google-*,\ --google-runtime-references,\ -misc-*,\ --misc-non-private-member-variables-in-classes,\ -cert-*,\ -readability-*,\ -clang-analyzer-*' +Checks: 'cppcoreguidelines-*, +performance-*, +modernize-*, +google-*, +misc-*, +cert-*, +readability-*, +clang-analyzer-*, +-performance-unnecessary-value-param, +-modernize-use-trailing-return-type, +-google-runtime-references, +-misc-non-private-member-variables-in-classes, +-readability-braces-around-statements, +-google-readability-braces-around-statements, +-cppcoreguidelines-avoid-magic-numbers, +-readability-magic-numbers, +-readability-magic-numbers, +-cppcoreguidelines-pro-type-vararg, +-cppcoreguidelines-pro-bounds-pointer-arithmetic, +-cppcoreguidelines-avoid-c-arrays, +-modernize-avoid-c-arrays, +-cppcoreguidelines-pro-bounds-array-to-pointer-decay, +-readability-named-parameter, +-cert-env33-c +' + WarningsAsErrors: '' -HeaderFilterRegex: 'async.h|async_logger.h|common.h|details|formatter.h|logger.h|sinks|spdlog.h|tweakme.h|version.h' +HeaderFilterRegex: '*spdlog/[^f].*' AnalyzeTemporaryDtors: false FormatStyle: none diff --git a/third_party/spdlog/.travis.yml b/third_party/spdlog/.travis.yml index b3137c6d..4d0a4c76 100644 --- a/third_party/spdlog/.travis.yml +++ b/third_party/spdlog/.travis.yml @@ -97,6 +97,7 @@ script: -DCMAKE_CXX_STANDARD=$CPP \ -DSPDLOG_BUILD_EXAMPLE=ON \ -DSPDLOG_BUILD_EXAMPLE_HO=ON \ + -DSPDLOG_ENABLE_WARNINGS=ON \ -DSPDLOG_BUILD_BENCH=OFF \ -DSPDLOG_BUILD_TESTS=ON \ -DSPDLOG_BUILD_TESTS_HO=OFf \ diff --git a/third_party/spdlog/CMakeLists.txt b/third_party/spdlog/CMakeLists.txt index 4f6b0788..b4987219 100644 --- a/third_party/spdlog/CMakeLists.txt +++ b/third_party/spdlog/CMakeLists.txt @@ -3,15 +3,27 @@ cmake_minimum_required(VERSION 3.2) +if(${CMAKE_VERSION} VERSION_LESS 3.11) + cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}) +else() + cmake_policy(VERSION 3.11) +endif() + +ENABLE_LANGUAGE(C) + #--------------------------------------------------------------------------------------- # Start spdlog project #--------------------------------------------------------------------------------------- -include(GNUInstallDirs) include(cmake/utils.cmake) include(cmake/ide.cmake) spdlog_extract_version() +project(spdlog VERSION ${SPDLOG_VERSION} LANGUAGES CXX) +message(STATUS "Build spdlog: ${SPDLOG_VERSION}") + +include(GNUInstallDirs) + #--------------------------------------------------------------------------------------- # Set default build to release #--------------------------------------------------------------------------------------- @@ -19,15 +31,21 @@ if(NOT CMAKE_BUILD_TYPE) set(CMAKE_BUILD_TYPE "Release" CACHE STRING "Choose Release or Debug" FORCE) endif() -project(spdlog VERSION ${SPDLOG_VERSION} LANGUAGES CXX) -message(STATUS "Build spdlog: ${SPDLOG_VERSION}") #--------------------------------------------------------------------------------------- # Compiler config #--------------------------------------------------------------------------------------- -set(CMAKE_CXX_STANDARD 11) -set(CMAKE_CXX_STANDARD_REQUIRED ON) -set(CMAKE_CXX_EXTENSIONS OFF) +if (NOT CMAKE_CXX_STANDARD) + set(CMAKE_CXX_STANDARD 11) + set(CMAKE_CXX_STANDARD_REQUIRED ON) +endif() + +set(CMAKE_CXX_EXTENSIONS OFF) + +if(CMAKE_SYSTEM_NAME MATCHES "CYGWIN") + set(CMAKE_CXX_EXTENSIONS ON) +endif() + #--------------------------------------------------------------------------------------- # Set SPDLOG_MASTER_PROJECT to ON if we are building spdlog @@ -42,16 +60,17 @@ if (NOT DEFINED SPDLOG_MASTER_PROJECT) endif () # build shared option -if(NOT WIN32) - option(SPDLOG_BUILD_SHARED "Build shared library" OFF) -endif() +option(SPDLOG_BUILD_SHARED "Build shared library" OFF) + +# precompiled headers option +option(SPDLOG_ENABLE_PCH "Build static or shared library using precompiled header to speed up compilation time" OFF) # example options option(SPDLOG_BUILD_EXAMPLE "Build example" ${SPDLOG_MASTER_PROJECT}) option(SPDLOG_BUILD_EXAMPLE_HO "Build header only example" OFF) # testing options -option(SPDLOG_BUILD_TESTS "Build tests" ${SPDLOG_MASTER_PROJECT}) +option(SPDLOG_BUILD_TESTS "Build tests" OFF) option(SPDLOG_BUILD_TESTS_HO "Build tests using the header only version" OFF) # bench options @@ -60,6 +79,9 @@ option(SPDLOG_BUILD_BENCH "Build benchmarks (Requires https://github.com/google/ # sanitizer options option(SPDLOG_SANITIZE_ADDRESS "Enable address sanitizer in tests" OFF) +# warning options +option(SPDLOG_BUILD_WARNINGS "Enable compiler warnings" OFF) + # install options option(SPDLOG_INSTALL "Generate the install target" ${SPDLOG_MASTER_PROJECT}) option(SPDLOG_FMT_EXTERNAL "Use external fmt library instead of bundled" OFF) @@ -84,6 +106,17 @@ option(SPDLOG_NO_THREAD_ID "prevent spdlog from querying the thread id on each l option(SPDLOG_NO_TLS "prevent spdlog from using thread local storage" OFF) option(SPDLOG_NO_ATOMIC_LEVELS "prevent spdlog from using of std::atomic log levels (use only if your code never modifies log levels concurrently" OFF) +# clang-tidy +if(${CMAKE_VERSION} VERSION_GREATER "3.5") + option(SPDLOG_TIDY "run clang-tidy" OFF) +endif() + +if(SPDLOG_TIDY) + set(CMAKE_CXX_CLANG_TIDY "clang-tidy") + set(CMAKE_EXPORT_COMPILE_COMMANDS ON) + message(STATUS "Enabled clang-tidy") +endif() + find_package(Threads REQUIRED) message(STATUS "Build type: " ${CMAKE_BUILD_TYPE}) #--------------------------------------------------------------------------------------- @@ -92,20 +125,29 @@ message(STATUS "Build type: " ${CMAKE_BUILD_TYPE}) set(SPDLOG_SRCS src/spdlog.cpp src/stdout_sinks.cpp - src/color_sinks.cpp + src/color_sinks.cpp src/file_sinks.cpp - src/async.cpp) - + src/async.cpp + src/cfg.cpp) if(NOT SPDLOG_FMT_EXTERNAL AND NOT SPDLOG_FMT_EXTERNAL_HO) list(APPEND SPDLOG_SRCS src/fmt.cpp) endif() +if(WIN32 AND SPDLOG_BUILD_SHARED) + list(APPEND SPDLOG_SRCS ${CMAKE_CURRENT_BINARY_DIR}/version.rc) +endif() + if (SPDLOG_BUILD_SHARED) - if(WIN32) - message(FATAL_ERROR "spdlog shared lib is not yet supported under windows") - endif() add_library(spdlog SHARED ${SPDLOG_SRCS} ${SPDLOG_ALL_HEADERS}) + target_compile_definitions(spdlog PUBLIC SPDLOG_SHARED_LIB) + if(WIN32) + target_compile_options(spdlog PUBLIC /wd4251 /wd4275) + configure_file(${CMAKE_CURRENT_SOURCE_DIR}/cmake/version.rc.in ${CMAKE_CURRENT_BINARY_DIR}/version.rc @ONLY) + endif() + if(NOT SPDLOG_FMT_EXTERNAL AND NOT SPDLOG_FMT_EXTERNAL_HO) + target_compile_definitions(spdlog PRIVATE FMT_EXPORT PUBLIC FMT_SHARED) + endif() else() add_library(spdlog STATIC ${SPDLOG_SRCS} ${SPDLOG_ALL_HEADERS}) endif() @@ -122,6 +164,11 @@ spdlog_enable_warnings(spdlog) set_target_properties(spdlog PROPERTIES VERSION ${SPDLOG_VERSION} SOVERSION ${SPDLOG_VERSION_MAJOR}) set_target_properties(spdlog PROPERTIES DEBUG_POSTFIX d) +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) + target_precompile_headers(spdlog PRIVATE ${PROJECT_BINARY_DIR}/spdlog_pch.h) +endif() + #--------------------------------------------------------------------------------------- # Header only version #--------------------------------------------------------------------------------------- @@ -209,8 +256,12 @@ endif() # Build binaries #--------------------------------------------------------------------------------------- if(SPDLOG_BUILD_EXAMPLE OR SPDLOG_BUILD_EXAMPLE_HO) - message(STATUS "Generating examples") + message(STATUS "Generating example(s)") add_subdirectory(example) + spdlog_enable_warnings(example) + if(SPDLOG_BUILD_EXAMPLE_HO) + spdlog_enable_warnings(example_header_only) + endif() endif() if(SPDLOG_BUILD_TESTS OR SPDLOG_BUILD_TESTS_HO) @@ -241,7 +292,10 @@ if (SPDLOG_INSTALL) # Include files #--------------------------------------------------------------------------------------- install(DIRECTORY include/ DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}" PATTERN "fmt/bundled" EXCLUDE) - install(TARGETS spdlog spdlog_header_only EXPORT spdlog DESTINATION "${CMAKE_INSTALL_LIBDIR}") + install(TARGETS spdlog spdlog_header_only EXPORT spdlog + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) if(NOT SPDLOG_FMT_EXTERNAL AND NOT SPDLOG_FMT_EXTERNAL_HO) install(DIRECTORY include/${PROJECT_NAME}/fmt/bundled/ @@ -277,6 +331,5 @@ if (SPDLOG_INSTALL) # Support creation of installable packages #--------------------------------------------------------------------------------------- include(cmake/spdlogCPack.cmake) - endif () diff --git a/third_party/spdlog/LICENSE b/third_party/spdlog/LICENSE index 4b43e064..0526b0b6 100644 --- a/third_party/spdlog/LICENSE +++ b/third_party/spdlog/LICENSE @@ -20,3 +20,7 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +-- NOTE: Third party dependecy used by this sofware -- +This software depends on the fmt lib (MIT License), +and users must comply to its license: https://github.com/fmtlib/fmt/blob/master/LICENSE.rst + diff --git a/third_party/spdlog/README.md b/third_party/spdlog/README.md index 0f45b9a0..5d3cc2fd 100644 --- a/third_party/spdlog/README.md +++ b/third_party/spdlog/README.md @@ -1,8 +1,6 @@ # spdlog -Very fast, header-only/compiled, C++ logging library. [![Build Status](https://travis-ci.org/gabime/spdlog.svg?branch=master)](https://travis-ci.org/gabime/spdlog)  [![Build status](https://ci.appveyor.com/api/projects/status/d2jnxclg20vd0o50?svg=true)](https://ci.appveyor.com/project/gabime/spdlog) - - +Very fast, header-only/compiled, C++ logging library. [![Build Status](https://travis-ci.org/gabime/spdlog.svg?branch=master)](https://travis-ci.org/gabime/spdlog)  [![Build status](https://ci.appveyor.com/api/projects/status/d2jnxclg20vd0o50?svg=true)](https://ci.appveyor.com/project/gabime/spdlog) [![Release](https://img.shields.io/github/release/gabime/spdlog.svg)](https://github.com/gabime/spdlog/releases/latest) ## Install #### Header only version @@ -25,20 +23,22 @@ $ cmake .. && make -j ## Package managers: * Homebrew: `brew install spdlog` +* MacPorts: `sudo port install spdlog` * FreeBSD: `cd /usr/ports/devel/spdlog/ && make install clean` * Fedora: `yum install spdlog` * Gentoo: `emerge dev-libs/spdlog` -* Arch Linux: `yaourt -S spdlog-git` +* Arch Linux: `pacman -S spdlog` * vcpkg: `vcpkg install spdlog` -* conan: `spdlog/[>=1.4.1]@bincrafters/stable` +* conan: `spdlog/[>=1.4.1]` +* conda: `conda install -c conda-forge spdlog` ## Features * Very fast (see [benchmarks](#benchmarks) below). -* Headers only, just copy and use. Or use as a compiled library. +* Headers only or compiled version * Feature rich formatting, using the excellent [fmt](https://github.com/fmtlib/fmt) library. -* **New!** [Backtrace](#backtrace-support) support - store debug or other messages in a ring buffer and display later on demand. -* Fast asynchronous mode (optional) +* **New!** [Backtrace](#backtrace-support) support - store debug messages in a ring buffer and display later on demand. +* Asynchronous mode (optional) * [Custom](https://github.com/gabime/spdlog/wiki/3.-Custom-formatting) formatting. * Multi/Single threaded loggers. * Various log targets: @@ -48,7 +48,8 @@ $ cmake .. && make -j * syslog. * Windows debugger (```OutputDebugString(..)```) * Easily extendable with custom log targets (just implement a single function in the [sink](include/spdlog/sinks/sink.h) interface). -* Severity based filtering - threshold levels can be modified in runtime as well as in compile time. +* Log filtering - log levels can be modified in runtime as well as in compile time. +* Support for loading log levels from argv or from environment var. ## Usage samples @@ -77,15 +78,30 @@ int main() // Compile time log levels // define SPDLOG_ACTIVE_LEVEL to desired level - SPDLOG_TRACE("Some trace message with param {}", {}); + SPDLOG_TRACE("Some trace message with param {}", 42); SPDLOG_DEBUG("Some debug message"); // Set the default logger to file logger auto file_logger = spdlog::basic_logger_mt("basic_logger", "logs/basic.txt"); spdlog::set_default_logger(file_logger); } + ``` -#### create stdout/stderr logger object +#### Load log levels from env variable or from argv +```c++ +#include "spdlog/cfg/env.h" +void load_levels_example() +{ + // Set the log level to "info" and mylogger to to "trace": + // SPDLOG_LEVEL=info,mylogger=trace && ./example + spdlog::cfg::load_env_levels(); + // or from command line: + // ./example SPDLOG_LEVEL=info,mylogger=trace + // #include "spdlog/cfg/argv.h" // for loading levels from argv + // spdlog::cfg::load_argv_levels(args, argv); +} +``` +#### Create stdout/stderr logger object ```c++ #include "spdlog/spdlog.h" #include "spdlog/sinks/stdout_color_sinks.h" @@ -158,7 +174,7 @@ spdlog::dump_backtrace(); // log them now! show the last 32 messages #### Periodic flush ```c++ // periodically flush all *registered* loggers every 3 seconds: -// warning: only use if all your loggers are thread safe! +// warning: only use if all your loggers are thread safe ("_mt" loggers) spdlog::flush_every(std::chrono::seconds(3)); ``` @@ -266,6 +282,37 @@ void user_defined_example() } ``` + +--- +#### User defined flags in the log pattern +```c++ +// Log patterns can contain custom flags. +// the following example will add new flag '%*' - which will be bound to a instance. +#include "spdlog/pattern_formatter.h" +class my_formatter_flag : public spdlog::custom_flag_formatter +{ +public: + void format(const spdlog::details::log_msg &, const std::tm &, spdlog::memory_buf_t &dest) override + { + std::string some_txt = "custom-flag"; + dest.append(some_txt.data(), some_txt.data() + some_txt.size()); + } + + std::unique_ptr clone() const override + { + return spdlog::details::make_unique(); + } +}; + +void custom_flags_example() +{ + auto formatter = std::make_unique(); + formatter->add_flag('*').set_pattern("[%n] [%*] [%^%l%$] %v"); + spdlog::set_formatter(std::move(formatter)); +} + +``` + --- #### Custom error handler ```c++ @@ -277,6 +324,8 @@ void err_handler_example() } ``` + + --- #### syslog ```c++ @@ -321,7 +370,7 @@ Below are some [benchmarks](https://github.com/gabime/spdlog/blob/v1.x/bench/ben [info] daily_st Elapsed: 0.42 secs 2,393,298/sec [info] null_st Elapsed: 0.04 secs 27,446,957/sec [info] ************************************************************** -[info] 10 threads sharing same logger, 1,000,000 iterations +[info] 10 threads, competing over the same logger object, 1,000,000 iterations [info] ************************************************************** [info] basic_mt Elapsed: 0.60 secs 1,659,613/sec [info] rotating_mt Elapsed: 0.62 secs 1,612,493/sec @@ -335,7 +384,6 @@ Below are some [benchmarks](https://github.com/gabime/spdlog/blob/v1.x/bench/ben [info] Threads : 10 [info] Queue : 8,192 slots [info] Queue memory : 8,192 x 272 = 2,176 KB -[info] Total iters : 3 [info] ------------------------------------------------- [info] [info] ********************************* diff --git a/third_party/spdlog/appveyor.yml b/third_party/spdlog/appveyor.yml index d76d3791..b3fb0796 100644 --- a/third_party/spdlog/appveyor.yml +++ b/third_party/spdlog/appveyor.yml @@ -30,7 +30,7 @@ build_script: set PATH=%PATH%:C:\Program Files\Git\usr\bin - cmake .. -G %GENERATOR% -DCMAKE_BUILD_TYPE=%BUILD_TYPE% -DSPDLOG_WCHAR_SUPPORT=%WCHAR% -DSPDLOG_BUILD_EXAMPLE=ON -DSPDLOG_BUILD_EXAMPLE_HO=ON -DSPDLOG_BUILD_TESTS=ON -DSPDLOG_BUILD_TESTS_HO=OFF + cmake .. -G %GENERATOR% -DCMAKE_BUILD_TYPE=%BUILD_TYPE% -DSPDLOG_WCHAR_SUPPORT=%WCHAR% -DSPDLOG_BUILD_EXAMPLE=ON -DSPDLOG_BUILD_EXAMPLE_HO=ON -DSPDLOG_BUILD_TESTS=ON -DSPDLOG_BUILD_TESTS_HO=OFF -DSPDLOG_ENABLE_WARNINGS=ON cmake --build . --config %BUILD_TYPE% diff --git a/third_party/spdlog/bench/bench.cpp b/third_party/spdlog/bench/bench.cpp index 591057bd..424333fc 100644 --- a/third_party/spdlog/bench/bench.cpp +++ b/third_party/spdlog/bench/bench.cpp @@ -19,19 +19,15 @@ #include #include -using namespace std; -using namespace std::chrono; -using namespace spdlog; -using namespace spdlog::sinks; -using namespace utils; - void bench(int howmany, std::shared_ptr log); void bench_mt(int howmany, std::shared_ptr log, int thread_count); -void bench_default_api(int howmany, std::shared_ptr log); -void bench_c_string(int howmany, std::shared_ptr log); -static size_t file_size = 30 * 1024 * 1024; -static size_t rotating_files = 5; +// void bench_default_api(int howmany, std::shared_ptr log); +// void bench_c_string(int howmany, std::shared_ptr log); + +static const size_t file_size = 30 * 1024 * 1024; +static const size_t rotating_files = 5; +static const int max_threads = 1000; void bench_threaded_logging(int threads, int iters) { @@ -116,9 +112,18 @@ int main(int argc, char *argv[]) { if (argc > 1) - iters = atoi(argv[1]); + { + iters = std::stoi(argv[1]); + } if (argc > 2) - threads = atoi(argv[2]); + { + threads = std::stoi(argv[2]); + } + + if (threads > max_threads) + { + throw std::runtime_error(fmt::format("Number of threads exceeds maximum({}})", max_threads)); + } bench_single_threaded(iters); bench_threaded_logging(1, iters); @@ -134,7 +139,10 @@ int main(int argc, char *argv[]) void bench(int howmany, std::shared_ptr log) { + using std::chrono::duration; + using std::chrono::duration_cast; using std::chrono::high_resolution_clock; + auto start = high_resolution_clock::now(); for (auto i = 0; i < howmany; ++i) { @@ -150,17 +158,21 @@ void bench(int howmany, std::shared_ptr log) void bench_mt(int howmany, std::shared_ptr log, int thread_count) { + using std::chrono::duration; + using std::chrono::duration_cast; using std::chrono::high_resolution_clock; - vector threads; + + std::vector threads; + threads.reserve(thread_count); auto start = high_resolution_clock::now(); for (int t = 0; t < thread_count; ++t) { - threads.push_back(std::thread([&]() { + threads.emplace_back([&]() { for (int j = 0; j < howmany / thread_count; j++) { log->info("Hello logger: msg number {}", j); } - })); + }); } for (auto &t : threads) @@ -174,9 +186,13 @@ void bench_mt(int howmany, std::shared_ptr log, int thread_count spdlog::drop(log->name()); } +/* void bench_default_api(int howmany, std::shared_ptr log) { using std::chrono::high_resolution_clock; + using std::chrono::duration; + using std::chrono::duration_cast; + auto orig_default = spdlog::default_logger(); spdlog::set_default_logger(log); auto start = high_resolution_clock::now(); @@ -194,18 +210,22 @@ void bench_default_api(int howmany, std::shared_ptr log) void bench_c_string(int howmany, std::shared_ptr log) { + using std::chrono::high_resolution_clock; + using std::chrono::duration; + using std::chrono::duration_cast; + const char *msg = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum pharetra metus cursus " "lacus placerat congue. Nulla egestas, mauris a tincidunt tempus, enim lectus volutpat mi, eu consequat sem " "libero nec massa. In dapibus ipsum a diam rhoncus gravida. Etiam non dapibus eros. Donec fringilla dui sed " "augue pretium, nec scelerisque est maximus. Nullam convallis, sem nec blandit maximus, nisi turpis ornare " "nisl, sit amet volutpat neque massa eu odio. Maecenas malesuada quam ex, posuere congue nibh turpis duis."; - using std::chrono::high_resolution_clock; + auto orig_default = spdlog::default_logger(); spdlog::set_default_logger(log); auto start = high_resolution_clock::now(); for (auto i = 0; i < howmany; ++i) { - spdlog::log(level::info, msg); + spdlog::log(spdlog::level::info, msg); } auto delta = high_resolution_clock::now() - start; @@ -214,3 +234,5 @@ void bench_c_string(int howmany, std::shared_ptr log) spdlog::set_default_logger(std::move(orig_default)); spdlog::info("{:<30} Elapsed: {:0.2f} secs {:>16n}/sec", log->name(), delta_d, int(howmany / delta_d)); } + +*/ \ No newline at end of file diff --git a/third_party/spdlog/bench/formatter-bench.cpp b/third_party/spdlog/bench/formatter-bench.cpp index 405707c9..34407c10 100644 --- a/third_party/spdlog/bench/formatter-bench.cpp +++ b/third_party/spdlog/bench/formatter-bench.cpp @@ -6,7 +6,7 @@ #include "benchmark/benchmark.h" #include "spdlog/spdlog.h" -#include "spdlog/details/pattern_formatter.h" +#include "spdlog/pattern_formatter.h" void bench_formatter(benchmark::State &state, std::string pattern) { diff --git a/third_party/spdlog/bench/latency.cpp b/third_party/spdlog/bench/latency.cpp index cd8717d9..a3f12c48 100644 --- a/third_party/spdlog/bench/latency.cpp +++ b/third_party/spdlog/bench/latency.cpp @@ -51,11 +51,21 @@ void bench_disabled_macro(benchmark::State &state, std::shared_ptrUseRealTime(); + spdlog::drop("/dev/null_st"); + + auto dev_null_mt = spdlog::basic_logger_mt("/dev/null_mt", "/dev/null"); + benchmark::RegisterBenchmark("/dev/null_mt", bench_logger, std::move(dev_null_mt))->UseRealTime(); + spdlog::drop("/dev/null_mt"); +} +#endif // __linux__ + int main(int argc, char *argv[]) { - - using spdlog::sinks::basic_file_sink_mt; - using spdlog::sinks::basic_file_sink_st; using spdlog::sinks::null_sink_mt; using spdlog::sinks::null_sink_st; @@ -63,6 +73,8 @@ int main(int argc, char *argv[]) size_t rotating_files = 5; int n_threads = benchmark::CPUInfo::Get().num_cpus; + auto full_bench = argc > 1 && std::string(argv[1]) == "full"; + // disabled loggers auto disabled_logger = std::make_shared("bench", std::make_shared()); disabled_logger->set_level(spdlog::level::off); @@ -81,54 +93,61 @@ int main(int argc, char *argv[]) tracing_null_logger_st->enable_backtrace(64); benchmark::RegisterBenchmark("null_sink_st/backtrace", bench_logger, tracing_null_logger_st); - // basic_st - auto basic_st = spdlog::basic_logger_st("basic_st", "latency_logs/basic_st.log", true); - benchmark::RegisterBenchmark("basic_st", bench_logger, std::move(basic_st))->UseRealTime(); - spdlog::drop("basic_st"); - // with backtrace of 64 - auto tracing_basic_st = spdlog::basic_logger_st("tracing_basic_st", "latency_logs/tracing_basic_st.log", true); - tracing_basic_st->enable_backtrace(64); - benchmark::RegisterBenchmark("basic_st/backtrace", bench_logger, std::move(tracing_basic_st))->UseRealTime(); - spdlog::drop("tracing_basic_st"); +#ifdef __linux + bench_dev_null(); +#endif // __linux__ - // rotating st - auto rotating_st = spdlog::rotating_logger_st("rotating_st", "latency_logs/rotating_st.log", file_size, rotating_files); - benchmark::RegisterBenchmark("rotating_st", bench_logger, std::move(rotating_st))->UseRealTime(); - spdlog::drop("rotating_st"); - // with backtrace of 64 - auto tracing_rotating_st = - spdlog::rotating_logger_st("tracing_rotating_st", "latency_logs/tracing_rotating_st.log", file_size, rotating_files); - benchmark::RegisterBenchmark("rotating_st/backtrace", bench_logger, std::move(tracing_rotating_st))->UseRealTime(); - spdlog::drop("tracing_rotating_st"); + if (full_bench) + { + // basic_st + auto basic_st = spdlog::basic_logger_st("basic_st", "latency_logs/basic_st.log", true); + benchmark::RegisterBenchmark("basic_st", bench_logger, std::move(basic_st))->UseRealTime(); + spdlog::drop("basic_st"); + // with backtrace of 64 + auto tracing_basic_st = spdlog::basic_logger_st("tracing_basic_st", "latency_logs/tracing_basic_st.log", true); + tracing_basic_st->enable_backtrace(64); + benchmark::RegisterBenchmark("basic_st/backtrace", bench_logger, std::move(tracing_basic_st))->UseRealTime(); + spdlog::drop("tracing_basic_st"); - // daily st - auto daily_st = spdlog::daily_logger_mt("daily_st", "latency_logs/daily_st.log"); - benchmark::RegisterBenchmark("daily_st", bench_logger, std::move(daily_st))->UseRealTime(); - spdlog::drop("daily_st"); - auto tracing_daily_st = spdlog::daily_logger_mt("tracing_daily_st", "latency_logs/daily_st.log"); - benchmark::RegisterBenchmark("daily_st/backtrace", bench_logger, std::move(tracing_daily_st))->UseRealTime(); - spdlog::drop("tracing_daily_st"); + // rotating st + auto rotating_st = spdlog::rotating_logger_st("rotating_st", "latency_logs/rotating_st.log", file_size, rotating_files); + benchmark::RegisterBenchmark("rotating_st", bench_logger, std::move(rotating_st))->UseRealTime(); + spdlog::drop("rotating_st"); + // with backtrace of 64 + auto tracing_rotating_st = + spdlog::rotating_logger_st("tracing_rotating_st", "latency_logs/tracing_rotating_st.log", file_size, rotating_files); + benchmark::RegisterBenchmark("rotating_st/backtrace", bench_logger, std::move(tracing_rotating_st))->UseRealTime(); + spdlog::drop("tracing_rotating_st"); - // - // Multi threaded bench, 10 loggers using same logger concurrently - // - auto null_logger_mt = std::make_shared("bench", std::make_shared()); - benchmark::RegisterBenchmark("null_sink_mt", bench_logger, null_logger_mt)->Threads(n_threads)->UseRealTime(); + // daily st + auto daily_st = spdlog::daily_logger_mt("daily_st", "latency_logs/daily_st.log"); + benchmark::RegisterBenchmark("daily_st", bench_logger, std::move(daily_st))->UseRealTime(); + spdlog::drop("daily_st"); + auto tracing_daily_st = spdlog::daily_logger_mt("tracing_daily_st", "latency_logs/daily_st.log"); + benchmark::RegisterBenchmark("daily_st/backtrace", bench_logger, std::move(tracing_daily_st))->UseRealTime(); + spdlog::drop("tracing_daily_st"); - // basic_mt - auto basic_mt = spdlog::basic_logger_mt("basic_mt", "latency_logs/basic_mt.log", true); - benchmark::RegisterBenchmark("basic_mt", bench_logger, std::move(basic_mt))->Threads(n_threads)->UseRealTime(); - spdlog::drop("basic_mt"); + // + // Multi threaded bench, 10 loggers using same logger concurrently + // + auto null_logger_mt = std::make_shared("bench", std::make_shared()); + benchmark::RegisterBenchmark("null_sink_mt", bench_logger, null_logger_mt)->Threads(n_threads)->UseRealTime(); - // rotating mt - auto rotating_mt = spdlog::rotating_logger_mt("rotating_mt", "latency_logs/rotating_mt.log", file_size, rotating_files); - benchmark::RegisterBenchmark("rotating_mt", bench_logger, std::move(rotating_mt))->Threads(n_threads)->UseRealTime(); - spdlog::drop("rotating_mt"); + // basic_mt + auto basic_mt = spdlog::basic_logger_mt("basic_mt", "latency_logs/basic_mt.log", true); + benchmark::RegisterBenchmark("basic_mt", bench_logger, std::move(basic_mt))->Threads(n_threads)->UseRealTime(); + spdlog::drop("basic_mt"); - // daily mt - auto daily_mt = spdlog::daily_logger_mt("daily_mt", "latency_logs/daily_mt.log"); - benchmark::RegisterBenchmark("daily_mt", bench_logger, std::move(daily_mt))->Threads(n_threads)->UseRealTime(); - spdlog::drop("daily_mt"); + // rotating mt + auto rotating_mt = spdlog::rotating_logger_mt("rotating_mt", "latency_logs/rotating_mt.log", file_size, rotating_files); + benchmark::RegisterBenchmark("rotating_mt", bench_logger, std::move(rotating_mt))->Threads(n_threads)->UseRealTime(); + spdlog::drop("rotating_mt"); + + // daily mt + auto daily_mt = spdlog::daily_logger_mt("daily_mt", "latency_logs/daily_mt.log"); + benchmark::RegisterBenchmark("daily_mt", bench_logger, std::move(daily_mt))->Threads(n_threads)->UseRealTime(); + spdlog::drop("daily_mt"); + } // async auto queue_size = 1024 * 1024 * 3; diff --git a/third_party/spdlog/cmake/pch.h.in b/third_party/spdlog/cmake/pch.h.in new file mode 100644 index 00000000..a5f94150 --- /dev/null +++ b/third_party/spdlog/cmake/pch.h.in @@ -0,0 +1,258 @@ +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) + +#pragma once + +// details/pattern_formatter-inl.h +// fmt/bin_to_hex.h +// fmt/bundled/format-inl.h +#include + +// details/file_helper-inl.h +// details/os-inl.h +// fmt/bundled/core.h +// fmt/bundled/posix.h +// logger-inl.h +// sinks/daily_file_sink.h +// sinks/stdout_sinks.h +#include + +// details/os-inl.h +// fmt/bundled/posix.h +#include + +// details/os-inl.h +// details/pattern_formatter-inl.h +// fmt/bundled/core.h +// fmt/bundled/format-inl.h +#include + +// details/os-inl.h +// details/os.h +// details/pattern_formatter-inl.h +// details/pattern_formatter.h +// fmt/bundled/chrono.h +// sinks/daily_file_sink.h +// sinks/rotating_file_sink-inl.h +#include + +// fmt/bundled/format-inl.h +#include + +// fmt/bundled/format-inl.h +#include + +// fmt/bundled/format-inl.h +// fmt/bundled/format.h +#include + +// fmt/bundled/format-inl.h +#include + +// details/file_helper-inl.h +// fmt/bundled/format.h +// fmt/bundled/posix.h +// sinks/rotating_file_sink-inl.h +#include + +// details/circular_q.h +// details/thread_pool-inl.h +// fmt/bundled/format-inl.h +#include + +// async_logger-inl.h +// cfg/helpers-inl.h +// log_levels.h +// common.h +// details/file_helper-inl.h +// details/log_msg.h +// details/os-inl.h +// details/pattern_formatter-inl.h +// details/pattern_formatter.h +// details/registry-inl.h +// details/registry.h +// details/tcp_client-windows.h +// details/tcp_client.h +// fmt/bundled/core.h +// sinks/android_sink.h +// sinks/ansicolor_sink.h +// sinks/basic_file_sink.h +// sinks/daily_file_sink.h +// sinks/dup_filter_sink.h +// sinks/msvc_sink.h +// sinks/ringbuffer_sink.h +// sinks/rotating_file_sink-inl.h +// sinks/rotating_file_sink.h +// sinks/syslog_sink.h +// sinks/tcp_sink.h +// sinks/win_eventlog_sink.h +// sinks/wincolor_sink.h +// spdlog.h: +#include + +// cfg/helpers-inl.h +// fmt/bundled/chrono.h +#include + +// fmt/bundled/ostream.h +// sinks/ostream_sink.h +#include + +// cfg/log_levels.h +// details/registry-inl.h +// details/registry.h +#include + +// details/circular_q.h +// details/pattern_formatter-inl.h +// details/pattern_formatter.h +// details/thread_pool.h +// fmt/bundled/compile.h +// logger.h +// sinks/dist_sink.h +// sinks/ringbuffer_sink.h +// sinks/win_eventlog_sink.h +#include + +// details/os-inl.h +// details/pattern_formatter-inl.h +// sinks/ansicolor_sink.h +// sinks/syslog_sink.h +// sinks/systemd_sink.h +// sinks/wincolor_sink.h +#include + +// details/file_helper-inl.h +// details/file_helper.h +// sinks/rotating_file_sink-inl.h +#include + +// details/os-inl.h +// fmt/bundled/format.h +// fmt/bundled/printf.h +#include + +// common.h +// details/backtracer.h +// details/null_mutex.h +#include + +// common.h +// details/backtracer.h +// details/null_mutex.h +#include + +// common.h +#include + +// common.h +#include + +// common.h +// details/fmt_helper.h +// fmt/bundled/core.h +// fmt/bundled/ranges.h +#include + +// cfg/helpers-inl.h +// details/null_mutex.h +// details/pattern_formatter-inl.h +#include + +// async.h +// async_logger-inl.h +// common.h +// details/pattern_formatter-inl.h +// details/pattern_formatter.h +// details/registry-inl.h +// details/registry.h +// details/thread_pool.h +// fmt/bundled/format.h +// sinks/ansicolor_sink.h +// sinks/base_sink-inl.h +// sinks/dist_sink.h +// sinks/stdout_sinks-inl.h +// sinks/wincolor_sink.h +// spdlog.h +#include + +// async.h +// common.h +// details/backtracer.h +// details/periodic_worker.h +// details/registry-inl.h +// details/registry.h +// details/thread_pool.h +// sinks/tcp_sink.h +// spdlog.h +#include + +// details/mpmc_blocking_q.h +// details/periodic_worker.h +#include + +// details/os-inl.h +// fmt/bundled/format.h +// fmt/bundled/printf.h +// sinks/dist_sink.h +#include + +// common.h +// details/file_helper-inl.h +// details/fmt_helper.h +// details/os-inl.h +// details/pattern_formatter-inl.h +// details/pattern_formatter.h +// details/periodic_worker.h +// details/registry-inl.h +// details/registry.h +// details/thread_pool.h +// fmt/bundled/chrono.h +// sinks/android_sink.h +// sinks/daily_file_sink.h +// sinks/dup_filter_sink.h +// sinks/rotating_file_sink-inl.h +// sinks/rotating_file_sink.h +// sinks/tcp_sink.h +// spdlog.h +#include + +// details/file_helper-inl.h +// details/os-inl.h +// details/pattern_formatter-inl.h +// details/periodic_worker.h +// details/thread_pool.h +// sinks/android_sink.h +#include + +// async.h +// details/backtracer.h +// details/console_globals.h +// details/mpmc_blocking_q.h +// details/pattern_formatter-inl.h +// details/periodic_worker.h +// details/registry.h +// sinks/android_sink.h +// sinks/ansicolor_sink.h +// sinks/basic_file_sink.h +// sinks/daily_file_sink.h +// sinks/dist_sink.h +// sinks/dup_filter_sink.h +// sinks/msvc_sink.h +// sinks/null_sink.h +// sinks/ostream_sink.h +// sinks/ringbuffer_sink.h +// sinks/rotating_file_sink-inl.h +// sinks/rotating_file_sink.h +// sinks/tcp_sink.h +// sinks/win_eventlog_sink.h +// sinks/wincolor_sink.h +// +// color_sinks.cpp +// file_sinks.cpp +// spdlog.cpp +// stdout_sinks.cpp +#include + +// spdlog +#include \ No newline at end of file diff --git a/third_party/spdlog/cmake/spdlogCPack.cmake b/third_party/spdlog/cmake/spdlogCPack.cmake index 6ee2e51c..471a7ea3 100644 --- a/third_party/spdlog/cmake/spdlogCPack.cmake +++ b/third_party/spdlog/cmake/spdlogCPack.cmake @@ -1,7 +1,4 @@ -set(CPACK_GENERATOR - TGZ - ZIP - ) +set(CPACK_GENERATOR "TGZ;ZIP" CACHE STRING "Semicolon separated list of generators") set(CPACK_INCLUDE_TOPLEVEL_DIRECTORY 0) set(CPACK_INSTALL_CMAKE_PROJECTS @@ -22,11 +19,32 @@ set(CPACK_PACKAGE_VERSION ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PR if (PROJECT_VERSION_TWEAK) set(CPACK_PACKAGE_VERSION ${CPACK_PACKAGE_VERSION}.${PROJECT_VERSION_TWEAK}) endif () -set(CPACK_PACKAGE_RELOCATABLE ON) +set(CPACK_PACKAGE_RELOCATABLE ON CACHE BOOL "Build relocatable package") set(CPACK_RPM_PACKAGE_LICENSE "MIT") -set(CPACK_RPM_PACKAGE_GROUP "System Environment/Libraries") +set(CPACK_RPM_PACKAGE_GROUP "Development/Libraries") set(CPACK_RPM_PACKAGE_URL ${CPACK_PROJECT_URL}) set(CPACK_RPM_PACKAGE_DESCRIPTION "Very fast, header-only/compiled, C++ logging library.") +if (CPACK_PACKAGE_NAME) + set(CPACK_RPM_FILE_NAME "${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}") +else() + set(CPACK_RPM_FILE_NAME "${PROJECT_NAME}-${CPACK_PACKAGE_VERSION}") +endif() + +if (CPACK_RPM_PACKAGE_RELEASE) + set(CPACK_RPM_FILE_NAME "${CPACK_RPM_FILE_NAME}-${CPACK_RPM_PACKAGE_RELEASE}") +endif () + +if (CPACK_RPM_PACKAGE_ARCHITECTURE) + set(CPACK_RPM_FILE_NAME "${CPACK_RPM_FILE_NAME}.${CPACK_RPM_PACKAGE_ARCHITECTURE}") +endif () +set(CPACK_RPM_FILE_NAME "${CPACK_RPM_FILE_NAME}.rpm") + +if (NOT CPACK_PACKAGE_RELOCATABLE) + # Depend on pkgconfig rpm to create the system pkgconfig folder + set(CPACK_RPM_PACKAGE_REQUIRES pkgconfig) + set(CPACK_RPM_EXCLUDE_FROM_AUTO_FILELIST_ADDITION "${CPACK_PACKAGING_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}/pkgconfig") +endif () + include(CPack) diff --git a/third_party/spdlog/cmake/utils.cmake b/third_party/spdlog/cmake/utils.cmake index f16a908d..69ee545a 100644 --- a/third_party/spdlog/cmake/utils.cmake +++ b/third_party/spdlog/cmake/utils.cmake @@ -20,19 +20,28 @@ function(spdlog_extract_version) set(ver_patch ${CMAKE_MATCH_1}) set(SPDLOG_VERSION_MAJOR ${ver_major} PARENT_SCOPE) + set(SPDLOG_VERSION_MINOR ${ver_minor} PARENT_SCOPE) + set(SPDLOG_VERSION_PATCH ${ver_patch} PARENT_SCOPE) set (SPDLOG_VERSION "${ver_major}.${ver_minor}.${ver_patch}" PARENT_SCOPE) endfunction() # Turn on warnings on the given target function(spdlog_enable_warnings target_name) - target_compile_options(${target_name} PRIVATE - $<$,$,$>: - -Wall -Wextra -Wconversion -pedantic -Wfatal-errors> - $<$:/W4>) - if(MSVC_VERSION GREATER_EQUAL 1910) #Allow non fatal security wanrnings for msvc 2015 - target_compile_options(${target_name} PRIVATE /WX) - endif() + if(SPDLOG_BUILD_WARNINGS) + if (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") + list(APPEND MSVC_OPTIONS "/W3") + if(MSVC_VERSION GREATER 1900) #Allow non fatal security wanrnings for msvc 2015 + list(APPEND MSVC_OPTIONS "/WX") + endif() + endif() + + target_compile_options(${target_name} PRIVATE + $<$,$,$>: + -Wall -Wextra -Wconversion -pedantic -Wfatal-errors> + $<$:${MSVC_OPTIONS}>) + endif() + endfunction() diff --git a/third_party/spdlog/cmake/version.rc.in b/third_party/spdlog/cmake/version.rc.in new file mode 100644 index 00000000..f32808d5 --- /dev/null +++ b/third_party/spdlog/cmake/version.rc.in @@ -0,0 +1,42 @@ +#define APSTUDIO_READONLY_SYMBOLS +#include "winres.h" +#undef APSTUDIO_READONLY_SYMBOLS + +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US + + +VS_VERSION_INFO VERSIONINFO + FILEVERSION @SPDLOG_VERSION_MAJOR@,@SPDLOG_VERSION_MINOR@,@SPDLOG_VERSION_PATCH@,0 + PRODUCTVERSION @SPDLOG_VERSION_MAJOR@,@SPDLOG_VERSION_MINOR@,@SPDLOG_VERSION_PATCH@,0 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x40004L + FILETYPE 0x2L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "FileDescription", "spdlog dll\0" + VALUE "FileVersion", "@SPDLOG_VERSION@.0\0" + VALUE "InternalName", "spdlog.dll\0" + VALUE "LegalCopyright", "Copyright (C) spdlog\0" + VALUE "ProductName", "spdlog\0" + VALUE "ProductVersion", "@SPDLOG_VERSION@.0\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END + + + + + diff --git a/third_party/spdlog/example/CMakeLists.txt b/third_party/spdlog/example/CMakeLists.txt index 458ca952..bb5be0bb 100644 --- a/third_party/spdlog/example/CMakeLists.txt +++ b/third_party/spdlog/example/CMakeLists.txt @@ -1,7 +1,7 @@ # Copyright(c) 2019 spdlog authors # Distributed under the MIT License (http://opensource.org/licenses/MIT) -cmake_minimum_required(VERSION 3.1) +cmake_minimum_required(VERSION 3.2) project(spdlog_examples CXX) if(NOT TARGET spdlog) @@ -13,15 +13,13 @@ endif() # Example of using pre-compiled library #--------------------------------------------------------------------------------------- add_executable(example example.cpp) -spdlog_enable_warnings(example) target_link_libraries(example PRIVATE spdlog::spdlog) #--------------------------------------------------------------------------------------- # Example of using header-only library #--------------------------------------------------------------------------------------- if(SPDLOG_BUILD_EXAMPLE_HO) - add_executable(example_header_only example.cpp) - spdlog_enable_warnings(example_header_only) + add_executable(example_header_only example.cpp) target_link_libraries(example_header_only PRIVATE spdlog::spdlog_header_only) endif() diff --git a/third_party/spdlog/example/example.cpp b/third_party/spdlog/example/example.cpp index 0bc838bd..ef8f23ff 100644 --- a/third_party/spdlog/example/example.cpp +++ b/third_party/spdlog/example/example.cpp @@ -6,6 +6,7 @@ #include +void load_levels_example(); void stdout_logger_example(); void basic_example(); void rotating_example(); @@ -17,12 +18,18 @@ void multi_sink_example(); void user_defined_example(); void err_handler_example(); void syslog_example(); +void custom_flags_example(); #include "spdlog/spdlog.h" +#include "spdlog/cfg/env.h" // for loading levels from the environment variable int main(int, char *[]) { + // Log levels can be loaded from argv/env using "SPDLOG_LEVEL" + load_levels_example(); + spdlog::info("Welcome to spdlog version {}.{}.{} !", SPDLOG_VER_MAJOR, SPDLOG_VER_MINOR, SPDLOG_VER_PATCH); + spdlog::warn("Easy padding in numbers like {:08d}", 12); spdlog::critical("Support for int: {0:d}; hex: {0:x}; oct: {0:o}; bin: {0:b}", 42); spdlog::info("Support for floats {:03.2f}", 1.23456); @@ -64,6 +71,7 @@ int main(int, char *[]) user_defined_example(); err_handler_example(); trace_example(); + custom_flags_example(); // Flush all *registered* loggers using a worker thread every 3 seconds. // note: registered loggers *must* be thread safe for this to work correctly! @@ -116,6 +124,18 @@ void daily_example() auto daily_logger = spdlog::daily_logger_mt("daily_logger", "logs/daily.txt", 2, 30); } +#include "spdlog/cfg/env.h" +void load_levels_example() +{ + // Set the log level to "info" and mylogger to to "trace": + // SPDLOG_LEVEL=info,mylogger=trace && ./example + spdlog::cfg::load_env_levels(); + // or from command line: + // ./example SPDLOG_LEVEL=info,mylogger=trace + // #include "spdlog/cfg/argv.h" // for loading levels from argv + // spdlog::cfg::load_argv_levels(args, argv); +} + #include "spdlog/async.h" void async_example() { @@ -154,6 +174,8 @@ void binary_example() // logger->info("uppercase: {:X}", spdlog::to_hex(buf)); // logger->info("uppercase, no delimiters: {:Xs}", spdlog::to_hex(buf)); // logger->info("uppercase, no delimiters, no position info: {:Xsp}", spdlog::to_hex(buf)); + // logger->info("hexdump style: {:a}", spdlog::to_hex(buf)); + // logger->info("hexdump style, 20 chars per line {:a}", spdlog::to_hex(buf, 20)); } // Compile time log levels. @@ -230,5 +252,31 @@ void android_example() auto android_logger = spdlog::android_logger_mt("android", tag); android_logger->critical("Use \"adb shell logcat\" to view this message."); } - #endif + +// Log patterns can contain custom flags. +// this will add custom flag '%*' which will be bound to a instance +#include "spdlog/pattern_formatter.h" +class my_formatter_flag : public spdlog::custom_flag_formatter +{ +public: + void format(const spdlog::details::log_msg &, const std::tm &, spdlog::memory_buf_t &dest) override + { + std::string some_txt = "custom-flag"; + dest.append(some_txt.data(), some_txt.data() + some_txt.size()); + } + + std::unique_ptr clone() const override + { + return spdlog::details::make_unique(); + } +}; + +void custom_flags_example() +{ + + using spdlog::details::make_unique; // for pre c++14 + auto formatter = make_unique(); + formatter->add_flag('*').set_pattern("[%n] [%*] [%^%l%$] %v"); + spdlog::set_formatter(std::move(formatter)); +} diff --git a/third_party/spdlog/include/spdlog/async_logger-inl.h b/third_party/spdlog/include/spdlog/async_logger-inl.h index 356db0e7..f8c9694c 100644 --- a/third_party/spdlog/include/spdlog/async_logger-inl.h +++ b/third_party/spdlog/include/spdlog/async_logger-inl.h @@ -32,7 +32,7 @@ SPDLOG_INLINE void spdlog::async_logger::sink_it_(const details::log_msg &msg) } else { - SPDLOG_THROW(spdlog_ex("async log: thread pool doesn't exist anymore")); + throw_spdlog_ex("async log: thread pool doesn't exist anymore"); } } @@ -45,7 +45,7 @@ SPDLOG_INLINE void spdlog::async_logger::flush_() } else { - SPDLOG_THROW(spdlog_ex("async flush: thread pool doesn't exist anymore")); + throw_spdlog_ex("async flush: thread pool doesn't exist anymore"); } } diff --git a/third_party/spdlog/include/spdlog/async_logger.h b/third_party/spdlog/include/spdlog/async_logger.h index 829c5acc..6f299672 100644 --- a/third_party/spdlog/include/spdlog/async_logger.h +++ b/third_party/spdlog/include/spdlog/async_logger.h @@ -30,7 +30,7 @@ namespace details { class thread_pool; } -class async_logger final : public std::enable_shared_from_this, public logger +class SPDLOG_API async_logger final : public std::enable_shared_from_this, public logger { friend class details::thread_pool; diff --git a/third_party/spdlog/include/spdlog/cfg/argv.h b/third_party/spdlog/include/spdlog/cfg/argv.h new file mode 100644 index 00000000..82bc1835 --- /dev/null +++ b/third_party/spdlog/include/spdlog/cfg/argv.h @@ -0,0 +1,45 @@ +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) + +#pragma once +#include +#include + +// +// Init log levels using each argv entry that starts with "SPDLOG_LEVEL=" +// +// set all loggers to debug level: +// example.exe "SPDLOG_LEVEL=debug" + +// set logger1 to trace level +// example.exe "SPDLOG_LEVEL=logger1=trace" + +// turn off all logging except for logger1 and logger2: +// example.exe "SPDLOG_LEVEL=off,logger1=debug,logger2=info" + +namespace spdlog { +namespace cfg { + +// search for SPDLOG_LEVEL= in the args and use it to init the levels +void load_argv_levels(int argc, const char **argv) +{ + const std::string spdlog_level_prefix = "SPDLOG_LEVEL="; + for (int i = 1; i < argc; i++) + { + std::string arg = argv[i]; + if (arg.find(spdlog_level_prefix) == 0) + { + auto levels_string = arg.substr(spdlog_level_prefix.size()); + auto levels = helpers::extract_levels(levels_string); + details::registry::instance().update_levels(std::move(levels)); + } + } +} + +void load_argv_levels(int argc, char **argv) +{ + load_argv_levels(argc, const_cast(argv)); +} + +} // namespace cfg +} // namespace spdlog diff --git a/third_party/spdlog/include/spdlog/cfg/env.h b/third_party/spdlog/include/spdlog/cfg/env.h new file mode 100644 index 00000000..115b676f --- /dev/null +++ b/third_party/spdlog/include/spdlog/cfg/env.h @@ -0,0 +1,36 @@ +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) + +#pragma once +#include +#include +#include + +// +// Init levels and patterns from env variables SPDLOG_LEVEL +// Inspired from Rust's "env_logger" crate (https://crates.io/crates/env_logger). +// Note - fallback to "info" level on unrecognized levels +// +// Examples: +// +// set global level to debug: +// export SPDLOG_LEVEL=debug +// +// turn off all logging except for logger1: +// export SPDLOG_LEVEL="off,logger1=debug" +// + +// turn off all logging except for logger1 and logger2: +// export SPDLOG_LEVEL="off,logger1=debug,logger2=info" + +namespace spdlog { +namespace cfg { +void load_env_levels() +{ + auto env_val = details::os::getenv("SPDLOG_LEVEL"); + auto levels = helpers::extract_levels(env_val); + details::registry::instance().update_levels(std::move(levels)); +} + +} // namespace cfg +} // namespace spdlog diff --git a/third_party/spdlog/include/spdlog/cfg/helpers-inl.h b/third_party/spdlog/include/spdlog/cfg/helpers-inl.h new file mode 100644 index 00000000..b0915073 --- /dev/null +++ b/third_party/spdlog/include/spdlog/cfg/helpers-inl.h @@ -0,0 +1,103 @@ +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) + +#pragma once + +#ifndef SPDLOG_HEADER_ONLY +#include +#endif + +#include +#include +#include + +#include +#include +#include + +namespace spdlog { +namespace cfg { +namespace helpers { + +// inplace convert to lowercase +inline std::string &to_lower_(std::string &str) +{ + std::transform( + str.begin(), str.end(), str.begin(), [](char ch) { return static_cast((ch >= 'A' && ch <= 'Z') ? ch + ('a' - 'A') : ch); }); + return str; +} + +// inplace trim spaces +inline std::string &trim_(std::string &str) +{ + const char *spaces = " \n\r\t"; + str.erase(str.find_last_not_of(spaces) + 1); + str.erase(0, str.find_first_not_of(spaces)); + return str; +} + +// return (name,value) trimmed pair from given "name=value" string. +// return empty string on missing parts +// "key=val" => ("key", "val") +// " key = val " => ("key", "val") +// "key=" => ("key", "") +// "val" => ("", "val") + +inline std::pair extract_kv_(char sep, const std::string &str) +{ + auto n = str.find(sep); + std::string k, v; + if (n == std::string::npos) + { + v = str; + } + else + { + k = str.substr(0, n); + v = str.substr(n + 1); + } + return std::make_pair(trim_(k), trim_(v)); +} + +// return vector of key/value pairs from sequence of "K1=V1,K2=V2,.." +// "a=AAA,b=BBB,c=CCC,.." => {("a","AAA"),("b","BBB"),("c", "CCC"),...} +inline std::unordered_map extract_key_vals_(const std::string &str) +{ + std::string token; + std::istringstream token_stream(str); + std::unordered_map rv{}; + while (std::getline(token_stream, token, ',')) + { + if (token.empty()) + { + continue; + } + auto kv = extract_kv_('=', token); + rv[kv.first] = kv.second; + } + return rv; +} + +SPDLOG_INLINE log_levels extract_levels(const std::string &input) +{ + auto key_vals = extract_key_vals_(input); + log_levels rv; + + for (auto &name_level : key_vals) + { + auto &logger_name = name_level.first; + auto level_name = to_lower_(name_level.second); + auto level = level::from_str(level_name); + // fallback to "info" if unrecognized level name + if (level == level::off && level_name != "off") + { + level = level::info; + } + rv.set(logger_name, level); + } + return rv; +} + +} // namespace helpers +} // namespace cfg +} // namespace spdlog diff --git a/third_party/spdlog/include/spdlog/cfg/helpers.h b/third_party/spdlog/include/spdlog/cfg/helpers.h new file mode 100644 index 00000000..8d750824 --- /dev/null +++ b/third_party/spdlog/include/spdlog/cfg/helpers.h @@ -0,0 +1,28 @@ +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) + +#pragma once + +#include + +namespace spdlog { +namespace cfg { +namespace helpers { +// +// Init levels from given string +// +// Examples: +// +// set global level to debug: "debug" +// turn off all logging except for logger1: "off,logger1=debug" +// turn off all logging except for logger1 and logger2: "off,logger1=debug,logger2=info" +// +SPDLOG_API log_levels extract_levels(const std::string &txt); +} // namespace helpers + +} // namespace cfg +} // namespace spdlog + +#ifdef SPDLOG_HEADER_ONLY +#include "helpers-inl.h" +#endif // SPDLOG_HEADER_ONLY diff --git a/third_party/spdlog/include/spdlog/cfg/log_levels.h b/third_party/spdlog/include/spdlog/cfg/log_levels.h new file mode 100644 index 00000000..ba3b2f75 --- /dev/null +++ b/third_party/spdlog/include/spdlog/cfg/log_levels.h @@ -0,0 +1,47 @@ +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) + +#pragma once + +#include +#include +#include + +namespace spdlog { +namespace cfg { +class log_levels +{ + std::unordered_map levels_; + spdlog::level::level_enum default_level_ = level::info; + +public: + void set(const std::string &logger_name, level::level_enum lvl) + { + if (logger_name.empty()) + { + default_level_ = lvl; + } + else + { + levels_[logger_name] = lvl; + } + } + + void set_default(level::level_enum lvl) + { + default_level_ = lvl; + } + + level::level_enum get(const std::string &logger_name) + { + auto it = levels_.find(logger_name); + return it != levels_.end() ? it->second : default_level_; + } + + level::level_enum default_level() + { + return default_level_; + } +}; +} // namespace cfg +} // namespace spdlog diff --git a/third_party/spdlog/include/spdlog/common-inl.h b/third_party/spdlog/include/spdlog/common-inl.h index a21284d2..be0d8f8e 100644 --- a/third_party/spdlog/include/spdlog/common-inl.h +++ b/third_party/spdlog/include/spdlog/common-inl.h @@ -34,6 +34,15 @@ SPDLOG_INLINE spdlog::level::level_enum from_str(const std::string &name) SPDLOG } level++; } + // check also for "warn" and "err" before giving up.. + if (name == "warn") + { + return level::warn; + } + if (name == "err") + { + return level::err; + } return level::off; } } // namespace level @@ -54,4 +63,14 @@ SPDLOG_INLINE const char *spdlog_ex::what() const SPDLOG_NOEXCEPT return msg_.c_str(); } +SPDLOG_INLINE void throw_spdlog_ex(const std::string &msg, int last_errno) +{ + SPDLOG_THROW(spdlog_ex(msg, last_errno)); +} + +SPDLOG_INLINE void throw_spdlog_ex(std::string msg) +{ + SPDLOG_THROW(spdlog_ex(std::move(msg))); +} + } // namespace spdlog diff --git a/third_party/spdlog/include/spdlog/common.h b/third_party/spdlog/include/spdlog/common.h index 830220ef..5b58c06a 100644 --- a/third_party/spdlog/include/spdlog/common.h +++ b/third_party/spdlog/include/spdlog/common.h @@ -15,22 +15,20 @@ #include #include -#ifdef _WIN32 -#ifndef NOMINMAX -#define NOMINMAX // prevent windows redefining min/max -#endif - -#ifndef WIN32_LEAN_AND_MEAN -#define WIN32_LEAN_AND_MEAN -#endif - -#include -#endif //_WIN32 - #ifdef SPDLOG_COMPILED_LIB #undef SPDLOG_HEADER_ONLY +#if defined(_WIN32) && defined(SPDLOG_SHARED_LIB) +#ifdef spdlog_EXPORTS +#define SPDLOG_API __declspec(dllexport) +#else +#define SPDLOG_API __declspec(dllimport) +#endif +#else +#define SPDLOG_API +#endif #define SPDLOG_INLINE #else +#define SPDLOG_API #define SPDLOG_HEADER_ONLY #define SPDLOG_INLINE inline #endif @@ -147,6 +145,7 @@ enum level_enum err = SPDLOG_LEVEL_ERROR, critical = SPDLOG_LEVEL_CRITICAL, off = SPDLOG_LEVEL_OFF, + n_levels }; #if !defined(SPDLOG_LEVEL_NAMES) @@ -164,9 +163,9 @@ enum level_enum } #endif -string_view_t &to_string_view(spdlog::level::level_enum l) SPDLOG_NOEXCEPT; -const char *to_short_c_str(spdlog::level::level_enum l) SPDLOG_NOEXCEPT; -spdlog::level::level_enum from_str(const std::string &name) SPDLOG_NOEXCEPT; +SPDLOG_API string_view_t &to_string_view(spdlog::level::level_enum l) SPDLOG_NOEXCEPT; +SPDLOG_API const char *to_short_c_str(spdlog::level::level_enum l) SPDLOG_NOEXCEPT; +SPDLOG_API spdlog::level::level_enum from_str(const std::string &name) SPDLOG_NOEXCEPT; using level_hasher = std::hash; } // namespace level @@ -194,7 +193,7 @@ enum class pattern_time_type // // Log exception // -class spdlog_ex : public std::exception +class SPDLOG_API spdlog_ex : public std::exception { public: explicit spdlog_ex(std::string msg); @@ -205,6 +204,9 @@ private: std::string msg_; }; +void throw_spdlog_ex(const std::string &msg, int last_errno); +void throw_spdlog_ex(std::string msg); + struct source_loc { SPDLOG_CONSTEXPR source_loc() = default; @@ -237,7 +239,6 @@ std::unique_ptr make_unique(Args &&... args) } #endif } // namespace details - } // namespace spdlog #ifdef SPDLOG_HEADER_ONLY diff --git a/third_party/spdlog/include/spdlog/details/backtracer.h b/third_party/spdlog/include/spdlog/details/backtracer.h index 0e779cab..b7476bc9 100644 --- a/third_party/spdlog/include/spdlog/details/backtracer.h +++ b/third_party/spdlog/include/spdlog/details/backtracer.h @@ -15,7 +15,7 @@ namespace spdlog { namespace details { -class backtracer +class SPDLOG_API backtracer { mutable std::mutex mutex_; std::atomic enabled_{false}; diff --git a/third_party/spdlog/include/spdlog/details/file_helper-inl.h b/third_party/spdlog/include/spdlog/details/file_helper-inl.h index cdd45f17..7cb00f2f 100644 --- a/third_party/spdlog/include/spdlog/details/file_helper-inl.h +++ b/third_party/spdlog/include/spdlog/details/file_helper-inl.h @@ -43,14 +43,14 @@ SPDLOG_INLINE void file_helper::open(const filename_t &fname, bool truncate) details::os::sleep_for_millis(open_interval_); } - SPDLOG_THROW(spdlog_ex("Failed opening file " + os::filename_to_str(filename_) + " for writing", errno)); + throw_spdlog_ex("Failed opening file " + os::filename_to_str(filename_) + " for writing", errno); } SPDLOG_INLINE void file_helper::reopen(bool truncate) { if (filename_.empty()) { - SPDLOG_THROW(spdlog_ex("Failed re opening file - was not opened before")); + throw_spdlog_ex("Failed re opening file - was not opened before"); } this->open(filename_, truncate); } @@ -75,7 +75,7 @@ SPDLOG_INLINE void file_helper::write(const memory_buf_t &buf) auto data = buf.data(); if (std::fwrite(data, 1, msg_size, fd_) != msg_size) { - SPDLOG_THROW(spdlog_ex("Failed writing to file " + os::filename_to_str(filename_), errno)); + throw_spdlog_ex("Failed writing to file " + os::filename_to_str(filename_), errno); } } @@ -83,7 +83,7 @@ SPDLOG_INLINE size_t file_helper::size() const { if (fd_ == nullptr) { - SPDLOG_THROW(spdlog_ex("Cannot use size() on closed file " + os::filename_to_str(filename_))); + throw_spdlog_ex("Cannot use size() on closed file " + os::filename_to_str(filename_)); } return os::filesize(fd_); } diff --git a/third_party/spdlog/include/spdlog/details/file_helper.h b/third_party/spdlog/include/spdlog/details/file_helper.h index 3228ce84..5395d9cb 100644 --- a/third_party/spdlog/include/spdlog/details/file_helper.h +++ b/third_party/spdlog/include/spdlog/details/file_helper.h @@ -13,7 +13,7 @@ namespace details { // When failing to open a file, retry several times(5) with a delay interval(10 ms). // Throw spdlog_ex exception on errors. -class file_helper +class SPDLOG_API file_helper { public: explicit file_helper() = default; diff --git a/third_party/spdlog/include/spdlog/details/fmt_helper.h b/third_party/spdlog/include/spdlog/details/fmt_helper.h index 85b988e6..f5a8bad5 100644 --- a/third_party/spdlog/include/spdlog/details/fmt_helper.h +++ b/third_party/spdlog/include/spdlog/details/fmt_helper.h @@ -20,10 +20,7 @@ inline spdlog::string_view_t to_string_view(const memory_buf_t &buf) SPDLOG_NOEX inline void append_string_view(spdlog::string_view_t view, memory_buf_t &dest) { auto *buf_ptr = view.data(); - if (buf_ptr != nullptr) - { - dest.append(buf_ptr, buf_ptr + view.size()); - } + dest.append(buf_ptr, buf_ptr + view.size()); } template @@ -34,10 +31,10 @@ inline void append_int(T n, memory_buf_t &dest) } template -inline unsigned count_digits(T n) +inline unsigned int count_digits(T n) { using count_type = typename std::conditional<(sizeof(T) > sizeof(uint32_t)), uint64_t, uint32_t>::type; - return static_cast(fmt::internal::count_digits(static_cast(n))); + return static_cast(fmt::internal::count_digits(static_cast(n))); } inline void pad2(int n, memory_buf_t &dest) @@ -66,11 +63,9 @@ template inline void pad_uint(T n, unsigned int width, memory_buf_t &dest) { static_assert(std::is_unsigned::value, "pad_uint must get unsigned T"); - auto digits = count_digits(n); - if (width > digits) + for (auto digits = count_digits(n); digits < width; digits++) { - const char *zeroes = "0000000000000000000"; - dest.append(zeroes, zeroes + width - digits); + dest.push_back('0'); } append_int(n, dest); } @@ -78,7 +73,18 @@ inline void pad_uint(T n, unsigned int width, memory_buf_t &dest) template inline void pad3(T n, memory_buf_t &dest) { - pad_uint(n, 3, dest); + static_assert(std::is_unsigned::value, "pad3 must get unsigned T"); + if(n < 1000) + { + dest.push_back(static_cast(n / 100 + '0')); + n = n % 100; + dest.push_back(static_cast((n / 10) + '0')); + dest.push_back(static_cast((n % 10) + '0')); + } + else + { + append_int(n, dest); + } } template diff --git a/third_party/spdlog/include/spdlog/details/log_msg.h b/third_party/spdlog/include/spdlog/details/log_msg.h index 9ae473d4..03bdbaec 100644 --- a/third_party/spdlog/include/spdlog/details/log_msg.h +++ b/third_party/spdlog/include/spdlog/details/log_msg.h @@ -8,7 +8,7 @@ namespace spdlog { namespace details { -struct log_msg +struct SPDLOG_API log_msg { log_msg() = default; log_msg(source_loc loc, string_view_t logger_name, level::level_enum lvl, string_view_t msg); diff --git a/third_party/spdlog/include/spdlog/details/log_msg_buffer.h b/third_party/spdlog/include/spdlog/details/log_msg_buffer.h index c20ae7b0..18075d67 100644 --- a/third_party/spdlog/include/spdlog/details/log_msg_buffer.h +++ b/third_party/spdlog/include/spdlog/details/log_msg_buffer.h @@ -11,7 +11,7 @@ namespace details { // Extend log_msg with internal buffer to store its payload. // THis is needed since log_msg holds string_views that points to stack data. -class log_msg_buffer : public log_msg +class SPDLOG_API log_msg_buffer : public log_msg { memory_buf_t buffer; void update_string_views(); diff --git a/third_party/spdlog/include/spdlog/details/os-inl.h b/third_party/spdlog/include/spdlog/details/os-inl.h index 8473eb09..0551be16 100644 --- a/third_party/spdlog/include/spdlog/details/os-inl.h +++ b/third_party/spdlog/include/spdlog/details/os-inl.h @@ -23,16 +23,9 @@ #ifdef _WIN32 -#ifndef NOMINMAX -#define NOMINMAX // prevent windows redefining min/max -#endif - -#ifndef WIN32_LEAN_AND_MEAN -#define WIN32_LEAN_AND_MEAN -#endif #include // _get_osfhandle and _isatty support #include // _get_pid support -#include +#include #ifdef __MINGW32__ #include @@ -126,23 +119,6 @@ SPDLOG_INLINE std::tm gmtime() SPDLOG_NOEXCEPT return gmtime(now_t); } -#ifdef SPDLOG_PREVENT_CHILD_FD -SPDLOG_INLINE void prevent_child_fd(FILE *f) -{ -#ifdef _WIN32 - auto file_handle = reinterpret_cast(_get_osfhandle(::_fileno(f))); - if (!::SetHandleInformation(file_handle, HANDLE_FLAG_INHERIT, 0)) - SPDLOG_THROW(spdlog_ex("SetHandleInformation failed", errno)); -#else - auto fd = ::fileno(f); - if (::fcntl(fd, F_SETFD, FD_CLOEXEC) == -1) - { - SPDLOG_THROW(spdlog_ex("fcntl with FD_CLOEXEC failed", errno)); - } -#endif -} -#endif // SPDLOG_PREVENT_CHILD_FD - // fopen_s on non windows for writing SPDLOG_INLINE bool fopen_s(FILE **fp, const filename_t &filename, const filename_t &mode) { @@ -152,17 +128,35 @@ SPDLOG_INLINE bool fopen_s(FILE **fp, const filename_t &filename, const filename #else *fp = ::_fsopen((filename.c_str()), mode.c_str(), _SH_DENYNO); #endif -#else // unix - *fp = ::fopen((filename.c_str()), mode.c_str()); -#endif - -#ifdef SPDLOG_PREVENT_CHILD_FD - // prevent child processes from inheriting log file descriptors +#if defined(SPDLOG_PREVENT_CHILD_FD) if (*fp != nullptr) { - prevent_child_fd(*fp); + auto file_handle = reinterpret_cast(_get_osfhandle(::_fileno(*fp))); + if (!::SetHandleInformation(file_handle, HANDLE_FLAG_INHERIT, 0)) + { + ::fclose(*fp); + *fp = nullptr; + } } #endif +#else // unix +#if defined(SPDLOG_PREVENT_CHILD_FD) + const int mode_flag = mode == SPDLOG_FILENAME_T("ab") ? O_APPEND : O_TRUNC; + const int fd = ::open((filename.c_str()), O_CREAT | O_WRONLY | O_CLOEXEC | mode_flag, mode_t(0644)); + if (fd == -1) + { + return false; + } + *fp = ::fdopen(fd, mode.c_str()); + if (*fp == nullptr) + { + ::close(fd); + } +#else + *fp = ::fopen((filename.c_str()), mode.c_str()); +#endif +#endif + return *fp == nullptr; } @@ -210,7 +204,7 @@ SPDLOG_INLINE size_t filesize(FILE *f) { if (f == nullptr) { - SPDLOG_THROW(spdlog_ex("Failed getting file size. fd is null")); + throw_spdlog_ex("Failed getting file size. fd is null"); } #if defined(_WIN32) && !defined(__CYGWIN__) int fd = ::_fileno(f); @@ -251,7 +245,8 @@ SPDLOG_INLINE size_t filesize(FILE *f) } #endif #endif - SPDLOG_THROW(spdlog_ex("Failed getting file size from fd", errno)); + throw_spdlog_ex("Failed getting file size from fd", errno); + return 0; // will not be reached. } // Return utc offset in minutes or throw spdlog_ex on failure @@ -267,7 +262,7 @@ SPDLOG_INLINE int utc_minutes_offset(const std::tm &tm) auto rv = ::GetDynamicTimeZoneInformation(&tzinfo); #endif if (rv == TIME_ZONE_ID_INVALID) - SPDLOG_THROW(spdlog::spdlog_ex("Failed getting timezone info. ", errno)); + throw_spdlog_ex("Failed getting timezone info. ", errno); int offset = -tzinfo.Bias; if (tm.tm_isdst) @@ -396,13 +391,13 @@ SPDLOG_INLINE int pid() SPDLOG_NOEXCEPT } // Determine if the terminal supports colors -// Source: https://github.com/agauniyal/rang/ +// Based on: https://github.com/agauniyal/rang/ SPDLOG_INLINE bool is_color_terminal() SPDLOG_NOEXCEPT { #ifdef _WIN32 return true; #else - static constexpr std::array Terms = { + static constexpr std::array terms = { {"ansi", "color", "console", "cygwin", "gnome", "konsole", "kterm", "linux", "msys", "putty", "rxvt", "screen", "vt100", "xterm"}}; const char *env_p = std::getenv("TERM"); @@ -412,7 +407,7 @@ SPDLOG_INLINE bool is_color_terminal() SPDLOG_NOEXCEPT } static const bool result = - std::any_of(std::begin(Terms), std::end(Terms), [&](const char *term) { return std::strstr(env_p, term) != nullptr; }); + std::any_of(terms.begin(), terms.end(), [&](const char *term) { return std::strstr(env_p, term) != nullptr; }); return result; #endif } @@ -434,7 +429,7 @@ SPDLOG_INLINE void wstr_to_utf8buf(wstring_view_t wstr, memory_buf_t &target) { if (wstr.size() > static_cast((std::numeric_limits::max)())) { - SPDLOG_THROW(spdlog::spdlog_ex("UTF-16 string is too big to be converted to UTF-8")); + throw_spdlog_ex("UTF-16 string is too big to be converted to UTF-8"); } int wstr_size = static_cast(wstr.size()); @@ -462,7 +457,7 @@ SPDLOG_INLINE void wstr_to_utf8buf(wstring_view_t wstr, memory_buf_t &target) } } - SPDLOG_THROW(spdlog::spdlog_ex(fmt::format("WideCharToMultiByte failed. Last error: {}", ::GetLastError()))); + throw_spdlog_ex(fmt::format("WideCharToMultiByte failed. Last error: {}", ::GetLastError())); } #endif // (defined(SPDLOG_WCHAR_TO_UTF8_SUPPORT) || defined(SPDLOG_WCHAR_FILENAMES)) && defined(_WIN32) @@ -536,6 +531,24 @@ SPDLOG_INLINE filename_t dir_name(filename_t path) return pos != filename_t::npos ? path.substr(0, pos) : filename_t{}; } +std::string SPDLOG_INLINE getenv(const char *field) +{ + +#if defined(_MSC_VER) +#if defined(__cplusplus_winrt) + return std::string{}; // not supported under uwp +#else + size_t len = 0; + char buf[128]; + bool ok = ::getenv_s(&len, buf, sizeof(buf), field) == 0; + return ok ? buf : std::string{}; +#endif +#else // revert to getenv + char *buf = ::getenv(field); + return buf ? buf : std::string{}; +#endif +} + } // namespace os } // namespace details } // namespace spdlog diff --git a/third_party/spdlog/include/spdlog/details/os.h b/third_party/spdlog/include/spdlog/details/os.h index 0894a6c0..cd586e14 100644 --- a/third_party/spdlog/include/spdlog/details/os.h +++ b/third_party/spdlog/include/spdlog/details/os.h @@ -10,15 +10,15 @@ namespace spdlog { namespace details { namespace os { -spdlog::log_clock::time_point now() SPDLOG_NOEXCEPT; +SPDLOG_API spdlog::log_clock::time_point now() SPDLOG_NOEXCEPT; -std::tm localtime(const std::time_t &time_tt) SPDLOG_NOEXCEPT; +SPDLOG_API std::tm localtime(const std::time_t &time_tt) SPDLOG_NOEXCEPT; -std::tm localtime() SPDLOG_NOEXCEPT; +SPDLOG_API std::tm localtime() SPDLOG_NOEXCEPT; -std::tm gmtime(const std::time_t &time_tt) SPDLOG_NOEXCEPT; +SPDLOG_API std::tm gmtime(const std::time_t &time_tt) SPDLOG_NOEXCEPT; -std::tm gmtime() SPDLOG_NOEXCEPT; +SPDLOG_API std::tm gmtime() SPDLOG_NOEXCEPT; // eol definition #if !defined(SPDLOG_EOL) @@ -38,54 +38,50 @@ static const char folder_sep = '\\'; SPDLOG_CONSTEXPR static const char folder_sep = '/'; #endif -#ifdef SPDLOG_PREVENT_CHILD_FD -void prevent_child_fd(FILE *f); -#endif - // fopen_s on non windows for writing -bool fopen_s(FILE **fp, const filename_t &filename, const filename_t &mode); +SPDLOG_API bool fopen_s(FILE **fp, const filename_t &filename, const filename_t &mode); // Remove filename. return 0 on success -int remove(const filename_t &filename) SPDLOG_NOEXCEPT; +SPDLOG_API int remove(const filename_t &filename) SPDLOG_NOEXCEPT; // Remove file if exists. return 0 on success // Note: Non atomic (might return failure to delete if concurrently deleted by other process/thread) -int remove_if_exists(const filename_t &filename) SPDLOG_NOEXCEPT; +SPDLOG_API int remove_if_exists(const filename_t &filename) SPDLOG_NOEXCEPT; -int rename(const filename_t &filename1, const filename_t &filename2) SPDLOG_NOEXCEPT; +SPDLOG_API int rename(const filename_t &filename1, const filename_t &filename2) SPDLOG_NOEXCEPT; // Return if file exists. -bool path_exists(const filename_t &filename) SPDLOG_NOEXCEPT; +SPDLOG_API bool path_exists(const filename_t &filename) SPDLOG_NOEXCEPT; // Return file size according to open FILE* object -size_t filesize(FILE *f); +SPDLOG_API size_t filesize(FILE *f); // Return utc offset in minutes or throw spdlog_ex on failure -int utc_minutes_offset(const std::tm &tm = details::os::localtime()); +SPDLOG_API int utc_minutes_offset(const std::tm &tm = details::os::localtime()); // Return current thread id as size_t // It exists because the std::this_thread::get_id() is much slower(especially // under VS 2013) -size_t _thread_id() SPDLOG_NOEXCEPT; +SPDLOG_API size_t _thread_id() SPDLOG_NOEXCEPT; // Return current thread id as size_t (from thread local storage) -size_t thread_id() SPDLOG_NOEXCEPT; +SPDLOG_API size_t thread_id() SPDLOG_NOEXCEPT; // This is avoid msvc issue in sleep_for that happens if the clock changes. // See https://github.com/gabime/spdlog/issues/609 -void sleep_for_millis(int milliseconds) SPDLOG_NOEXCEPT; +SPDLOG_API void sleep_for_millis(int milliseconds) SPDLOG_NOEXCEPT; -std::string filename_to_str(const filename_t &filename); +SPDLOG_API std::string filename_to_str(const filename_t &filename); -int pid() SPDLOG_NOEXCEPT; +SPDLOG_API int pid() SPDLOG_NOEXCEPT; // Determine if the terminal supports colors // Source: https://github.com/agauniyal/rang/ -bool is_color_terminal() SPDLOG_NOEXCEPT; +SPDLOG_API bool is_color_terminal() SPDLOG_NOEXCEPT; // Determine if the terminal attached // Source: https://github.com/agauniyal/rang/ -bool in_terminal(FILE *file) SPDLOG_NOEXCEPT; +SPDLOG_API bool in_terminal(FILE *file) SPDLOG_NOEXCEPT; #if (defined(SPDLOG_WCHAR_TO_UTF8_SUPPORT) || defined(SPDLOG_WCHAR_FILENAMES)) && defined(_WIN32) void wstr_to_utf8buf(wstring_view_t wstr, memory_buf_t &target); @@ -96,11 +92,15 @@ void wstr_to_utf8buf(wstring_view_t wstr, memory_buf_t &target); // "abc/" => "abc" // "abc" => "" // "abc///" => "abc//" -filename_t dir_name(filename_t path); +SPDLOG_API filename_t dir_name(filename_t path); // Create a dir from the given path. // Return true if succeeded or if this dir already exists. -bool create_dir(filename_t path); +SPDLOG_API bool create_dir(filename_t path); + +// non thread safe, cross platform getenv/getenv_s +// return empty string if field not found +SPDLOG_API std::string getenv(const char *field); } // namespace os } // namespace details diff --git a/third_party/spdlog/include/spdlog/details/periodic_worker.h b/third_party/spdlog/include/spdlog/details/periodic_worker.h index d3b5c639..42373665 100644 --- a/third_party/spdlog/include/spdlog/details/periodic_worker.h +++ b/third_party/spdlog/include/spdlog/details/periodic_worker.h @@ -17,7 +17,7 @@ namespace spdlog { namespace details { -class periodic_worker +class SPDLOG_API periodic_worker { public: periodic_worker(const std::function &callback_fun, std::chrono::seconds interval); diff --git a/third_party/spdlog/include/spdlog/details/registry-inl.h b/third_party/spdlog/include/spdlog/details/registry-inl.h index 562aa06c..33835d80 100644 --- a/third_party/spdlog/include/spdlog/details/registry-inl.h +++ b/third_party/spdlog/include/spdlog/details/registry-inl.h @@ -10,7 +10,7 @@ #include #include #include -#include +#include #ifndef SPDLOG_DISABLE_DEFAULT_LOGGER // support for the default stdout color logger @@ -48,6 +48,9 @@ SPDLOG_INLINE registry::registry() #endif // SPDLOG_DISABLE_DEFAULT_LOGGER } + +SPDLOG_INLINE registry::~registry() = default; + SPDLOG_INLINE void registry::register_logger(std::shared_ptr new_logger) { std::lock_guard lock(logger_map_mutex_); @@ -64,7 +67,7 @@ SPDLOG_INLINE void registry::initialize_logger(std::shared_ptr new_logge new_logger->set_error_handler(err_handler_); } - new_logger->set_level(level_); + new_logger->set_level(levels_.get(new_logger->name())); new_logger->flush_on(flush_level_); if (backtrace_n_messages_ > 0) @@ -168,7 +171,7 @@ SPDLOG_INLINE void registry::set_level(level::level_enum log_level) { l.second->set_level(log_level); } - level_ = log_level; + levels_.set_default(log_level); } SPDLOG_INLINE void registry::flush_on(level::level_enum log_level) @@ -184,7 +187,7 @@ SPDLOG_INLINE void registry::flush_on(level::level_enum log_level) SPDLOG_INLINE void registry::flush_every(std::chrono::seconds interval) { std::lock_guard lock(flusher_mutex_); - std::function clbk = std::bind(®istry::flush_all, this); + auto clbk = [this]() { this->flush_all(); }; periodic_flusher_ = details::make_unique(clbk, interval); } @@ -260,6 +263,17 @@ SPDLOG_INLINE void registry::set_automatic_registration(bool automatic_registrat automatic_registration_ = automatic_registration; } +SPDLOG_INLINE void registry::update_levels(cfg::log_levels levels) +{ + std::lock_guard lock(logger_map_mutex_); + levels_ = std::move(levels); + for (auto &l : loggers_) + { + auto &logger = l.second; + logger->set_level(levels_.get(logger->name())); + } +} + SPDLOG_INLINE registry ®istry::instance() { static registry s_instance; @@ -270,7 +284,7 @@ SPDLOG_INLINE void registry::throw_if_exists_(const std::string &logger_name) { if (loggers_.find(logger_name) != loggers_.end()) { - SPDLOG_THROW(spdlog_ex("logger with name '" + logger_name + "' already exists")); + throw_spdlog_ex("logger with name '" + logger_name + "' already exists"); } } @@ -280,5 +294,6 @@ SPDLOG_INLINE void registry::register_logger_(std::shared_ptr new_logger throw_if_exists_(logger_name); loggers_[logger_name] = std::move(new_logger); } + } // namespace details } // namespace spdlog diff --git a/third_party/spdlog/include/spdlog/details/registry.h b/third_party/spdlog/include/spdlog/details/registry.h index 6ac571dc..8be109ed 100644 --- a/third_party/spdlog/include/spdlog/details/registry.h +++ b/third_party/spdlog/include/spdlog/details/registry.h @@ -9,6 +9,7 @@ // This class is thread safe #include +#include #include #include @@ -24,7 +25,7 @@ namespace details { class thread_pool; class periodic_worker; -class registry +class SPDLOG_API registry { public: registry(const registry &) = delete; @@ -79,19 +80,21 @@ public: void set_automatic_registration(bool automatic_registration); + void update_levels(cfg::log_levels levels); + static registry &instance(); private: registry(); - ~registry() = default; + ~registry(); void throw_if_exists_(const std::string &logger_name); void register_logger_(std::shared_ptr new_logger); std::mutex logger_map_mutex_, flusher_mutex_; std::recursive_mutex tp_mutex_; std::unordered_map> loggers_; + cfg::log_levels levels_; std::unique_ptr formatter_; - level::level_enum level_ = level::info; level::level_enum flush_level_ = level::off; void (*err_handler_)(const std::string &msg); std::shared_ptr tp_; diff --git a/third_party/spdlog/include/spdlog/details/tcp_client-windows.h b/third_party/spdlog/include/spdlog/details/tcp_client-windows.h new file mode 100644 index 00000000..8f2e2fe7 --- /dev/null +++ b/third_party/spdlog/include/spdlog/details/tcp_client-windows.h @@ -0,0 +1,175 @@ +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) + +#pragma once + +#define WIN32_LEAN_AND_MEAN +// tcp client helper +#include +#include + +#include +#include +#include +#include +#include +#include + +#pragma comment(lib, "Ws2_32.lib") +#pragma comment(lib, "Mswsock.lib") +#pragma comment(lib, "AdvApi32.lib") + +namespace spdlog { +namespace details { +class tcp_client +{ + SOCKET socket_ = INVALID_SOCKET; + + static bool winsock_initialized_() + { + SOCKET s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + if (s == INVALID_SOCKET) + { + return false; + } + else + { + closesocket(s); + return true; + } + } + + static void init_winsock_() + { + WSADATA wsaData; + auto rv = WSAStartup(MAKEWORD(2, 2), &wsaData); + if (rv != 0) + { + throw_winsock_error_("WSAStartup failed", ::WSAGetLastError()); + } + } + + static void throw_winsock_error_(const std::string &msg, int last_error) + { + char buf[512]; + ::FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, last_error, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), buf, (sizeof(buf) / sizeof(char)), NULL); + + throw_spdlog_ex(fmt::format("tcp_sink - {}: {}", msg, buf)); + } + +public: + bool is_connected() const + { + return socket_ != INVALID_SOCKET; + } + + void close() + { + ::closesocket(socket_); + socket_ = INVALID_SOCKET; + WSACleanup(); + } + + SOCKET fd() const + { + return socket_; + } + + ~tcp_client() + { + close(); + } + + // try to connect or throw on failure + void connect(const std::string &host, int port) + { + // initialize winsock if needed + if (!winsock_initialized_()) + { + init_winsock_(); + } + + if (is_connected()) + { + close(); + } + struct addrinfo hints + {}; + ZeroMemory(&hints, sizeof(hints)); + + hints.ai_family = AF_INET; // IPv4 + hints.ai_socktype = SOCK_STREAM; // TCP + hints.ai_flags = AI_NUMERICSERV; // port passed as as numeric value + hints.ai_protocol = 0; + + auto port_str = std::to_string(port); + struct addrinfo *addrinfo_result; + auto rv = ::getaddrinfo(host.c_str(), port_str.c_str(), &hints, &addrinfo_result); + int last_error = 0; + if (rv != 0) + { + last_error = ::WSAGetLastError(); + WSACleanup(); + throw_winsock_error_("getaddrinfo failed", last_error); + } + + // Try each address until we successfully connect(2). + + for (auto *rp = addrinfo_result; rp != nullptr; rp = rp->ai_next) + { + socket_ = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); + if (socket_ == INVALID_SOCKET) + { + last_error = ::WSAGetLastError(); + WSACleanup(); + continue; + } + if (::connect(socket_, rp->ai_addr, (int)rp->ai_addrlen) == 0) + { + break; + } + else + { + last_error = ::WSAGetLastError(); + close(); + } + } + ::freeaddrinfo(addrinfo_result); + if (socket_ == INVALID_SOCKET) + { + WSACleanup(); + throw_winsock_error_("connect failed", last_error); + } + + // set TCP_NODELAY + int enable_flag = 1; + ::setsockopt(socket_, IPPROTO_TCP, TCP_NODELAY, (char *)&enable_flag, sizeof(enable_flag)); + } + + // Send exactly n_bytes of the given data. + // On error close the connection and throw. + void send(const char *data, size_t n_bytes) + { + size_t bytes_sent = 0; + while (bytes_sent < n_bytes) + { + const int send_flags = 0; + auto write_result = ::send(socket_, data + bytes_sent, (int)(n_bytes - bytes_sent), send_flags); + if (write_result == SOCKET_ERROR) + { + int last_error = ::WSAGetLastError(); + close(); + throw_winsock_error_("send failed", last_error); + } + + if (write_result == 0) // (probably should not happen but in any case..) + { + break; + } + bytes_sent += static_cast(write_result); + } + } +}; +} // namespace details +} // namespace spdlog diff --git a/third_party/spdlog/include/spdlog/details/tcp_client.h b/third_party/spdlog/include/spdlog/details/tcp_client.h new file mode 100644 index 00000000..8d331b0d --- /dev/null +++ b/third_party/spdlog/include/spdlog/details/tcp_client.h @@ -0,0 +1,145 @@ +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) + +#pragma once + +#ifdef _WIN32 +#error include tcp_client-windows.h instead +#endif + +// tcp client helper +#include +#include + +#include +#include +#include +#include +#include + +#include + +namespace spdlog { +namespace details { +class tcp_client +{ + int socket_ = -1; + +public: + bool is_connected() const + { + return socket_ != -1; + } + + void close() + { + if (is_connected()) + { + ::close(socket_); + socket_ = -1; + } + } + + int fd() const + { + return socket_; + } + + ~tcp_client() + { + close(); + } + + // try to connect or throw on failure + void connect(const std::string &host, int port) + { + close(); + struct addrinfo hints + {}; + memset(&hints, 0, sizeof(struct addrinfo)); + hints.ai_family = AF_INET; // IPv4 + hints.ai_socktype = SOCK_STREAM; // TCP + hints.ai_flags = AI_NUMERICSERV; // port passed as as numeric value + hints.ai_protocol = 0; + + auto port_str = std::to_string(port); + struct addrinfo *addrinfo_result; + auto rv = ::getaddrinfo(host.c_str(), port_str.c_str(), &hints, &addrinfo_result); + if (rv != 0) + { + auto msg = fmt::format("::getaddrinfo failed: {}", gai_strerror(rv)); + throw_spdlog_ex(msg); + } + + // Try each address until we successfully connect(2). + int last_errno = 0; + for (auto *rp = addrinfo_result; rp != nullptr; rp = rp->ai_next) + { + int const flags = SOCK_CLOEXEC; + socket_ = ::socket(rp->ai_family, rp->ai_socktype | flags, rp->ai_protocol); + if (socket_ == -1) + { + last_errno = errno; + continue; + } + rv = ::connect(socket_, rp->ai_addr, rp->ai_addrlen); + if (rv == 0) + { + break; + } + else + { + last_errno = errno; + ::close(socket_); + socket_ = -1; + } + } + ::freeaddrinfo(addrinfo_result); + if (socket_ == -1) + { + throw_spdlog_ex("::connect failed", last_errno); + } + + // set TCP_NODELAY + int enable_flag = 1; + ::setsockopt(socket_, IPPROTO_TCP, TCP_NODELAY, (char *)&enable_flag, sizeof(enable_flag)); + + // prevent sigpipe on systems where MSG_NOSIGNAL is not available +#if defined(SO_NOSIGPIPE) && !defined(MSG_NOSIGNAL) + ::setsockopt(socket_, SOL_SOCKET, SO_NOSIGPIPE, (char *)&enable_flag, sizeof(enable_flag)); +#endif + +#if !defined(SO_NOSIGPIPE) && !defined(MSG_NOSIGNAL) +#error "tcp_sink would raise SIGPIPE since niether SO_NOSIGPIPE nor MSG_NOSIGNAL are available" +#endif + } + + // Send exactly n_bytes of the given data. + // On error close the connection and throw. + void send(const char *data, size_t n_bytes) + { + size_t bytes_sent = 0; + while (bytes_sent < n_bytes) + { +#if defined(MSG_NOSIGNAL) + const int send_flags = MSG_NOSIGNAL; +#else + const int send_flags = 0; +#endif + auto write_result = ::send(socket_, data + bytes_sent, n_bytes - bytes_sent, send_flags); + if (write_result < 0) + { + close(); + throw_spdlog_ex("write(2) failed", errno); + } + + if (write_result == 0) // (probably should not happen but in any case..) + { + break; + } + bytes_sent += static_cast(write_result); + } + } +}; +} // namespace details +} // namespace spdlog diff --git a/third_party/spdlog/include/spdlog/details/thread_pool-inl.h b/third_party/spdlog/include/spdlog/details/thread_pool-inl.h index 43220f43..df65b029 100644 --- a/third_party/spdlog/include/spdlog/details/thread_pool-inl.h +++ b/third_party/spdlog/include/spdlog/details/thread_pool-inl.h @@ -18,8 +18,8 @@ SPDLOG_INLINE thread_pool::thread_pool(size_t q_max_items, size_t threads_n, std { if (threads_n == 0 || threads_n > 1000) { - SPDLOG_THROW(spdlog_ex("spdlog::thread_pool(): invalid threads_n param (valid " - "range is 1-1000)")); + throw_spdlog_ex("spdlog::thread_pool(): invalid threads_n param (valid " + "range is 1-1000)"); } for (size_t i = 0; i < threads_n; i++) { @@ -113,7 +113,7 @@ bool SPDLOG_INLINE thread_pool::process_next_msg_() } default: { - assert(false && "Unexpected async_msg_type"); + assert(false); } } diff --git a/third_party/spdlog/include/spdlog/details/thread_pool.h b/third_party/spdlog/include/spdlog/details/thread_pool.h index 12078044..733949ba 100644 --- a/third_party/spdlog/include/spdlog/details/thread_pool.h +++ b/third_party/spdlog/include/spdlog/details/thread_pool.h @@ -79,7 +79,7 @@ struct async_msg : log_msg_buffer {} }; -class thread_pool +class SPDLOG_API thread_pool { public: using item_type = async_msg; diff --git a/third_party/spdlog/include/spdlog/details/windows_include.h b/third_party/spdlog/include/spdlog/details/windows_include.h new file mode 100644 index 00000000..6a2f14f9 --- /dev/null +++ b/third_party/spdlog/include/spdlog/details/windows_include.h @@ -0,0 +1,11 @@ +#pragma once + +#ifndef NOMINMAX +#define NOMINMAX // prevent windows redefining min/max +#endif + +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif + +#include diff --git a/third_party/spdlog/include/spdlog/fmt/bin_to_hex.h b/third_party/spdlog/include/spdlog/fmt/bin_to_hex.h index de126061..e974cf51 100644 --- a/third_party/spdlog/include/spdlog/fmt/bin_to_hex.h +++ b/third_party/spdlog/include/spdlog/fmt/bin_to_hex.h @@ -5,6 +5,8 @@ #pragma once +#include + // // Support for logging binary data as hex // format flags: @@ -12,6 +14,7 @@ // {:s} - don't separate each byte with space. // {:p} - don't print the position on each line start. // {:n} - don't split the output to lines. +// {:a} - show ASCII if :n is not set // // Examples: @@ -20,17 +23,19 @@ // logger->info("Some buffer {}", spdlog::to_hex(v)); // char buf[128]; // logger->info("Some buffer {:X}", spdlog::to_hex(std::begin(buf), std::end(buf))); +// logger->info("Some buffer {:X}", spdlog::to_hex(std::begin(buf), std::end(buf), 16)); namespace spdlog { namespace details { template -class bytes_range +class dump_info { public: - bytes_range(It range_begin, It range_end) + dump_info(It range_begin, It range_end, size_t size_per_line) : begin_(range_begin) , end_(range_end) + , size_per_line_(size_per_line) {} It begin() const @@ -41,26 +46,31 @@ public: { return end_; } + size_t size_per_line() const + { + return size_per_line_; + } private: It begin_, end_; + size_t size_per_line_; }; } // namespace details -// create a bytes_range that wraps the given container +// create a dump_info that wraps the given container template -inline details::bytes_range to_hex(const Container &container) +inline details::dump_info to_hex(const Container &container, size_t size_per_line = 32) { static_assert(sizeof(typename Container::value_type) == 1, "sizeof(Container::value_type) != 1"); using Iter = typename Container::const_iterator; - return details::bytes_range(std::begin(container), std::end(container)); + return details::dump_info(std::begin(container), std::end(container), size_per_line); } -// create bytes_range from ranges +// create dump_info from ranges template -inline details::bytes_range to_hex(const It range_begin, const It range_end) +inline details::dump_info to_hex(const It range_begin, const It range_end, size_t size_per_line = 32) { - return details::bytes_range(range_begin, range_end); + return details::dump_info(range_begin, range_end, size_per_line); } } // namespace spdlog @@ -68,15 +78,14 @@ inline details::bytes_range to_hex(const It range_begin, const It range_end) namespace fmt { template -struct formatter> +struct formatter> { - const std::size_t line_size = 100; const char delimiter = ' '; - bool put_newlines = true; bool put_delimiters = true; bool use_uppercase = false; bool put_positions = true; // position on start of each line + bool show_ascii = false; // parse the format string flags template @@ -98,6 +107,13 @@ struct formatter> break; case 'n': put_newlines = false; + show_ascii = false; + break; + case 'a': + if (put_newlines) + { + show_ascii = true; + } break; } @@ -108,53 +124,83 @@ struct formatter> // format the given bytes range as hex template - auto format(const spdlog::details::bytes_range &the_range, FormatContext &ctx) -> decltype(ctx.out()) + auto format(const spdlog::details::dump_info &the_range, FormatContext &ctx) -> decltype(ctx.out()) { SPDLOG_CONSTEXPR const char *hex_upper = "0123456789ABCDEF"; SPDLOG_CONSTEXPR const char *hex_lower = "0123456789abcdef"; const char *hex_chars = use_uppercase ? hex_upper : hex_lower; - std::size_t pos = 0; - std::size_t column = line_size; #if FMT_VERSION < 60000 auto inserter = ctx.begin(); #else auto inserter = ctx.out(); #endif - for (auto &item : the_range) + int size_per_line = static_cast(the_range.size_per_line()); + auto start_of_line = the_range.begin(); + for (auto i = the_range.begin(); i != the_range.end(); i++) { - auto ch = static_cast(item); - pos++; + auto ch = static_cast(*i); - if (put_newlines && column >= line_size) + if (put_newlines && (i == the_range.begin() || i - start_of_line >= size_per_line)) { - column = put_newline(inserter, pos); + if (show_ascii && i != the_range.begin()) + { + *inserter++ = delimiter; + *inserter++ = delimiter; + for (auto j = start_of_line; j < i; j++) + { + auto pc = static_cast(*j); + *inserter++ = std::isprint(pc) ? static_cast(*j) : '.'; + } + } + + put_newline(inserter, static_cast(i - the_range.begin())); // put first byte without delimiter in front of it *inserter++ = hex_chars[(ch >> 4) & 0x0f]; *inserter++ = hex_chars[ch & 0x0f]; - column += 2; + start_of_line = i; continue; } if (put_delimiters) { *inserter++ = delimiter; - ++column; } *inserter++ = hex_chars[(ch >> 4) & 0x0f]; *inserter++ = hex_chars[ch & 0x0f]; - column += 2; + } + if (show_ascii) // add ascii to last line + { + if (the_range.end() - the_range.begin() > size_per_line) + { + auto blank_num = size_per_line - (the_range.end() - start_of_line); + while (blank_num-- > 0) + { + *inserter++ = delimiter; + *inserter++ = delimiter; + if (put_delimiters) + { + *inserter++ = delimiter; + } + } + } + *inserter++ = delimiter; + *inserter++ = delimiter; + for (auto j = start_of_line; j != the_range.end(); j++) + { + auto pc = static_cast(*j); + *inserter++ = std::isprint(pc) ? static_cast(*j) : '.'; + } } return inserter; } // put newline(and position header) - // return the next column template - std::size_t put_newline(It inserter, std::size_t pos) + void put_newline(It inserter, std::size_t pos) { #ifdef _WIN32 *inserter++ = '\r'; @@ -163,12 +209,7 @@ struct formatter> if (put_positions) { - fmt::format_to(inserter, "{:<04X}: ", pos - 1); - return 7; - } - else - { - return 1; + fmt::format_to(inserter, "{:<04X}: ", pos); } } }; diff --git a/third_party/spdlog/include/spdlog/fmt/bundled/chrono.h b/third_party/spdlog/include/spdlog/fmt/bundled/chrono.h index 9abe7c4f..ca4ed30a 100644 --- a/third_party/spdlog/include/spdlog/fmt/bundled/chrono.h +++ b/third_party/spdlog/include/spdlog/fmt/bundled/chrono.h @@ -696,7 +696,7 @@ inline int to_nonnegative_int(T value, int upper) { template ::value)> inline T mod(T x, int y) { - return x % y; + return x % static_cast(y); } template ::value)> inline T mod(T x, int y) { @@ -793,7 +793,10 @@ struct chrono_formatter { explicit chrono_formatter(FormatContext& ctx, OutputIt o, std::chrono::duration d) - : context(ctx), out(o), val(d.count()), negative(false) { + : context(ctx), + out(o), + val(static_cast(d.count())), + negative(false) { if (d.count() < 0) { val = 0 - val; negative = true; @@ -1023,8 +1026,8 @@ struct formatter, Char> { void on_error(const char* msg) { FMT_THROW(format_error(msg)); } void on_fill(Char fill) { f.specs.fill[0] = fill; } void on_align(align_t align) { f.specs.align = align; } - void on_width(unsigned width) { f.specs.width = width; } - void on_precision(unsigned _precision) { f.precision = _precision; } + void on_width(int width) { f.specs.width = width; } + void on_precision(int _precision) { f.precision = _precision; } void end_precision() {} template void on_dynamic_width(Id arg_id) { diff --git a/third_party/spdlog/include/spdlog/fmt/bundled/compile.h b/third_party/spdlog/include/spdlog/fmt/bundled/compile.h index f65f5a74..5829f623 100644 --- a/third_party/spdlog/include/spdlog/fmt/bundled/compile.h +++ b/third_party/spdlog/include/spdlog/fmt/bundled/compile.h @@ -26,11 +26,11 @@ template struct format_part { kind part_kind; union value { - unsigned arg_index; + int arg_index; basic_string_view str; replacement repl; - FMT_CONSTEXPR value(unsigned index = 0) : arg_index(index) {} + FMT_CONSTEXPR value(int index = 0) : arg_index(index) {} FMT_CONSTEXPR value(basic_string_view s) : str(s) {} FMT_CONSTEXPR value(replacement r) : repl(r) {} } val; @@ -40,7 +40,7 @@ template struct format_part { FMT_CONSTEXPR format_part(kind k = kind::arg_index, value v = {}) : part_kind(k), val(v) {} - static FMT_CONSTEXPR format_part make_arg_index(unsigned index) { + static FMT_CONSTEXPR format_part make_arg_index(int index) { return format_part(kind::arg_index, index); } static FMT_CONSTEXPR format_part make_arg_name(basic_string_view name) { @@ -62,7 +62,7 @@ template struct part_counter { } FMT_CONSTEXPR void on_arg_id() { ++num_parts; } - FMT_CONSTEXPR void on_arg_id(unsigned) { ++num_parts; } + FMT_CONSTEXPR void on_arg_id(int) { ++num_parts; } FMT_CONSTEXPR void on_arg_id(basic_string_view) { ++num_parts; } FMT_CONSTEXPR void on_replacement_field(const Char*) {} @@ -119,7 +119,7 @@ class format_string_compiler : public error_handler { part_ = part::make_arg_index(parse_context_.next_arg_id()); } - FMT_CONSTEXPR void on_arg_id(unsigned id) { + FMT_CONSTEXPR void on_arg_id(int id) { parse_context_.check_arg_id(id); part_ = part::make_arg_index(id); } @@ -512,8 +512,6 @@ template ::value)> std::basic_string format(const CompiledFormat& cf, const Args&... args) { basic_memory_buffer buffer; - using range = buffer_range; - using context = buffer_context; cf.format(std::back_inserter(buffer), args...); return to_string(buffer); } diff --git a/third_party/spdlog/include/spdlog/fmt/bundled/core.h b/third_party/spdlog/include/spdlog/fmt/bundled/core.h index 13d74ba8..9fd8df28 100644 --- a/third_party/spdlog/include/spdlog/fmt/bundled/core.h +++ b/third_party/spdlog/include/spdlog/fmt/bundled/core.h @@ -15,7 +15,7 @@ #include // The fmt library version in the form major * 10000 + minor * 100 + patch. -#define FMT_VERSION 60101 +#define FMT_VERSION 60102 #ifdef __has_feature # define FMT_HAS_FEATURE(x) __has_feature(x) @@ -878,7 +878,7 @@ template struct arg_mapper { FMT_ENABLE_IF( std::is_constructible, T>::value && !std::is_constructible, T>::value && - !is_string::value)> + !is_string::value && !has_formatter::value)> FMT_CONSTEXPR basic_string_view map(const T& val) { return std_string_view(val); } @@ -911,12 +911,14 @@ template struct arg_mapper { map(static_cast::type>(val))) { return map(static_cast::type>(val)); } - template ::value && !is_char::value && - !std::is_constructible, - T>::value && - (has_formatter::value || - has_fallback_formatter::value))> + template < + typename T, + FMT_ENABLE_IF( + !is_string::value && !is_char::value && + !std::is_constructible, T>::value && + (has_formatter::value || + (has_fallback_formatter::value && + !std::is_constructible, T>::value)))> FMT_CONSTEXPR const T& map(const T& val) { return val; } @@ -1283,7 +1285,7 @@ template class basic_format_args { */ template basic_format_args(const format_arg_store& store) - : types_(static_cast(store.types)) { + : types_(store.types) { set_data(store.data_); } diff --git a/third_party/spdlog/include/spdlog/fmt/bundled/format.h b/third_party/spdlog/include/spdlog/fmt/bundled/format.h index 600b0eba..01f41f5c 100644 --- a/third_party/spdlog/include/spdlog/fmt/bundled/format.h +++ b/third_party/spdlog/include/spdlog/fmt/bundled/format.h @@ -69,7 +69,8 @@ # define FMT_HAS_BUILTIN(x) 0 #endif -#if FMT_HAS_CPP_ATTRIBUTE(fallthrough) >= 201603 && __cplusplus >= 201703 +#if FMT_HAS_CPP_ATTRIBUTE(fallthrough) && \ + (__cplusplus >= 201703 || FMT_GCC_VERSION != 0) # define FMT_FALLTHROUGH [[fallthrough]] #else # define FMT_FALLTHROUGH @@ -801,60 +802,6 @@ template <> int count_digits<4>(internal::fallback_uintptr n); # define FMT_ALWAYS_INLINE #endif -// Computes g = floor(log10(n)) and calls h.on(n); -template FMT_ALWAYS_INLINE char* lg(uint32_t n, Handler h) { - return n < 100 ? n < 10 ? h.template on<0>(n) : h.template on<1>(n) - : n < 1000000 - ? n < 10000 ? n < 1000 ? h.template on<2>(n) - : h.template on<3>(n) - : n < 100000 ? h.template on<4>(n) - : h.template on<5>(n) - : n < 100000000 ? n < 10000000 ? h.template on<6>(n) - : h.template on<7>(n) - : n < 1000000000 ? h.template on<8>(n) - : h.template on<9>(n); -} - -// An lg handler that formats a decimal number. -// Usage: lg(n, decimal_formatter(buffer)); -class decimal_formatter { - private: - char* buffer_; - - void write_pair(unsigned N, uint32_t index) { - std::memcpy(buffer_ + N, data::digits + index * 2, 2); - } - - public: - explicit decimal_formatter(char* buf) : buffer_(buf) {} - - template char* on(uint32_t u) { - if (N == 0) { - *buffer_ = static_cast(u) + '0'; - } else if (N == 1) { - write_pair(0, u); - } else { - // The idea of using 4.32 fixed-point numbers is based on - // https://github.com/jeaiii/itoa - unsigned n = N - 1; - unsigned a = n / 5 * n * 53 / 16; - uint64_t t = - ((1ULL << (32 + a)) / data::zero_or_powers_of_10_32[n] + 1 - n / 9); - t = ((t * u) >> a) + n / 5 * 4; - write_pair(0, t >> 32); - for (unsigned i = 2; i < N; i += 2) { - t = 100ULL * static_cast(t); - write_pair(i, t >> 32); - } - if (N % 2 == 0) { - buffer_[N] = - static_cast((10ULL * static_cast(t)) >> 32) + '0'; - } - } - return buffer_ += N + 1; - } -}; - #ifdef FMT_BUILTIN_CLZ // Optional version of count_digits for better performance on 32-bit platforms. inline int count_digits(uint32_t n) { @@ -2620,7 +2567,7 @@ class format_string_checker { public: explicit FMT_CONSTEXPR format_string_checker( basic_string_view format_str, ErrorHandler eh) - : arg_id_(max_value()), + : arg_id_(-1), context_(format_str, eh), parse_funcs_{&parse_format_specs...} {} @@ -2661,7 +2608,7 @@ class format_string_checker { // Format specifier parsing function. using parse_func = const Char* (*)(parse_context_type&); - unsigned arg_id_; + int arg_id_; parse_context_type context_; parse_func parse_funcs_[num_args > 0 ? num_args : 1]; }; diff --git a/third_party/spdlog/include/spdlog/fmt/bundled/printf.h b/third_party/spdlog/include/spdlog/fmt/bundled/printf.h index cdbb65e6..a2fa945d 100644 --- a/third_party/spdlog/include/spdlog/fmt/bundled/printf.h +++ b/third_party/spdlog/include/spdlog/fmt/bundled/printf.h @@ -333,12 +333,12 @@ template class basic_printf_context { static void parse_flags(format_specs& specs, const Char*& it, const Char* end); - // Returns the argument with specified index or, if arg_index is equal - // to the maximum unsigned value, the next argument. - format_arg get_arg(unsigned arg_index = internal::max_value()); + // Returns the argument with specified index or, if arg_index is -1, the next + // argument. + format_arg get_arg(int arg_index = -1); // Parses argument index, flags and width and returns the argument index. - unsigned parse_header(const Char*& it, const Char* end, format_specs& specs); + int parse_header(const Char*& it, const Char* end, format_specs& specs); public: /** @@ -355,7 +355,7 @@ template class basic_printf_context { OutputIt out() { return out_; } void advance_to(OutputIt it) { out_ = it; } - format_arg arg(unsigned id) const { return args_.get(id); } + format_arg arg(int id) const { return args_.get(id); } basic_format_parse_context& parse_context() { return parse_ctx_; } @@ -397,8 +397,8 @@ void basic_printf_context::parse_flags(format_specs& specs, template typename basic_printf_context::format_arg -basic_printf_context::get_arg(unsigned arg_index) { - if (arg_index == internal::max_value()) +basic_printf_context::get_arg(int arg_index) { + if (arg_index < 0) arg_index = parse_ctx_.next_arg_id(); else parse_ctx_.check_arg_id(--arg_index); @@ -406,15 +406,15 @@ basic_printf_context::get_arg(unsigned arg_index) { } template -unsigned basic_printf_context::parse_header( +int basic_printf_context::parse_header( const Char*& it, const Char* end, format_specs& specs) { - unsigned arg_index = internal::max_value(); + int arg_index = -1; char_type c = *it; if (c >= '0' && c <= '9') { // Parse an argument index (if followed by '$') or a width possibly // preceded with '0' flag(s). internal::error_handler eh; - unsigned value = parse_nonnegative_int(it, end, eh); + int value = parse_nonnegative_int(it, end, eh); if (it != end && *it == '$') { // value is an argument index ++it; arg_index = value; @@ -436,8 +436,8 @@ unsigned basic_printf_context::parse_header( specs.width = parse_nonnegative_int(it, end, eh); } else if (*it == '*') { ++it; - specs.width = visit_format_arg( - internal::printf_width_handler(specs), get_arg()); + specs.width = static_cast(visit_format_arg( + internal::printf_width_handler(specs), get_arg())); } } return arg_index; @@ -464,7 +464,7 @@ OutputIt basic_printf_context::format() { specs.align = align::right; // Parse argument index, flags and width. - unsigned arg_index = parse_header(it, end, specs); + int arg_index = parse_header(it, end, specs); if (arg_index == 0) on_error("argument index out of range"); // Parse precision. @@ -473,11 +473,11 @@ OutputIt basic_printf_context::format() { c = it != end ? *it : 0; if ('0' <= c && c <= '9') { internal::error_handler eh; - specs.precision = static_cast(parse_nonnegative_int(it, end, eh)); + specs.precision = parse_nonnegative_int(it, end, eh); } else if (c == '*') { ++it; specs.precision = - visit_format_arg(internal::printf_precision_handler(), get_arg()); + static_cast(visit_format_arg(internal::printf_precision_handler(), get_arg())); } else { specs.precision = 0; } diff --git a/third_party/spdlog/include/spdlog/fmt/fmt.h b/third_party/spdlog/include/spdlog/fmt/fmt.h index a3762ba9..b853fd5e 100644 --- a/third_party/spdlog/include/spdlog/fmt/fmt.h +++ b/third_party/spdlog/include/spdlog/fmt/fmt.h @@ -10,30 +10,16 @@ // By default spdlog include its own copy. // -#if defined(__GNUC__) || defined(__clang__) -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wimplicit-fallthrough" -#pragma GCC diagnostic ignored "-Wsign-conversion" -#endif // __GNUC__ || __clang__ - - #if !defined(SPDLOG_FMT_EXTERNAL) -#ifdef SPDLOG_HEADER_ONLY -#ifndef FMT_HEADER_ONLY +#if !defined(SPDLOG_COMPILED_LIB) && !defined(FMT_HEADER_ONLY) #define FMT_HEADER_ONLY #endif -#endif #ifndef FMT_USE_WINDOWS_H #define FMT_USE_WINDOWS_H 0 #endif -#include "bundled/core.h" -#include "bundled/format.h" +#include +#include #else // SPDLOG_FMT_EXTERNAL is defined - use external fmtlib #include #include -#endif - -// pop warnings supressions -#if defined(__GNUC__) || defined(__clang__) -#pragma GCC diagnostic pop -#endif +#endif \ No newline at end of file diff --git a/third_party/spdlog/include/spdlog/fmt/ostr.h b/third_party/spdlog/include/spdlog/fmt/ostr.h index 9902898f..f82eb679 100644 --- a/third_party/spdlog/include/spdlog/fmt/ostr.h +++ b/third_party/spdlog/include/spdlog/fmt/ostr.h @@ -7,12 +7,14 @@ // // include bundled or external copy of fmtlib's ostream support // + #if !defined(SPDLOG_FMT_EXTERNAL) +#ifdef SPDLOG_HEADER_ONLY #ifndef FMT_HEADER_ONLY #define FMT_HEADER_ONLY #endif -#include "bundled/ostream.h" -#include "fmt.h" +#endif +#include #else #include #endif diff --git a/third_party/spdlog/include/spdlog/fwd.h b/third_party/spdlog/include/spdlog/fwd.h new file mode 100644 index 00000000..cc05ddd4 --- /dev/null +++ b/third_party/spdlog/include/spdlog/fwd.h @@ -0,0 +1,14 @@ +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) + +#pragma once + +namespace spdlog { +class logger; +class formatter; + +namespace sinks { +class sink; +} + +} // namespace spdlog diff --git a/third_party/spdlog/include/spdlog/logger-inl.h b/third_party/spdlog/include/spdlog/logger-inl.h index 95a485f1..69d6a1de 100644 --- a/third_party/spdlog/include/spdlog/logger-inl.h +++ b/third_party/spdlog/include/spdlog/logger-inl.h @@ -9,7 +9,7 @@ #include #include -#include +#include #include @@ -89,6 +89,7 @@ SPDLOG_INLINE void logger::set_formatter(std::unique_ptr f) { // last element - we can be move it. (*it)->set_formatter(std::move(f)); + break; // to prevent clang-tidy warning } else { diff --git a/third_party/spdlog/include/spdlog/logger.h b/third_party/spdlog/include/spdlog/logger.h index 43f39600..aeb38564 100644 --- a/third_party/spdlog/include/spdlog/logger.h +++ b/third_party/spdlog/include/spdlog/logger.h @@ -39,7 +39,7 @@ namespace spdlog { -class logger +class SPDLOG_API logger { public: // Empty logger @@ -143,6 +143,11 @@ public: // T can be statically converted to string_view template::value, T>::type * = nullptr> void log(source_loc loc, level::level_enum lvl, const T &msg) + { + log(loc, lvl, string_view_t{msg}); + } + + void log(source_loc loc, level::level_enum lvl, string_view_t msg) { bool log_enabled = should_log(lvl); bool traceback_enabled = tracer_.enabled(); diff --git a/third_party/spdlog/include/spdlog/details/pattern_formatter-inl.h b/third_party/spdlog/include/spdlog/pattern_formatter-inl.h similarity index 96% rename from third_party/spdlog/include/spdlog/details/pattern_formatter-inl.h rename to third_party/spdlog/include/spdlog/pattern_formatter-inl.h index 6fdc78a9..6bb319c8 100644 --- a/third_party/spdlog/include/spdlog/details/pattern_formatter-inl.h +++ b/third_party/spdlog/include/spdlog/pattern_formatter-inl.h @@ -4,7 +4,7 @@ #pragma once #ifndef SPDLOG_HEADER_ONLY -#include +#include #endif #include @@ -90,7 +90,7 @@ struct null_scoped_padder }; template -class name_formatter : public flag_formatter +class name_formatter final : public flag_formatter { public: explicit name_formatter(padding_info padinfo) @@ -106,7 +106,7 @@ public: // log level appender template -class level_formatter : public flag_formatter +class level_formatter final : public flag_formatter { public: explicit level_formatter(padding_info padinfo) @@ -123,7 +123,7 @@ public: // short log level appender template -class short_level_formatter : public flag_formatter +class short_level_formatter final : public flag_formatter { public: explicit short_level_formatter(padding_info padinfo) @@ -156,7 +156,7 @@ static int to12h(const tm &t) static std::array days{{"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"}}; template -class a_formatter : public flag_formatter +class a_formatter final : public flag_formatter { public: explicit a_formatter(padding_info padinfo) @@ -194,7 +194,7 @@ public: static const std::array months{{"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sept", "Oct", "Nov", "Dec"}}; template -class b_formatter : public flag_formatter +class b_formatter final : public flag_formatter { public: explicit b_formatter(padding_info padinfo) @@ -214,7 +214,7 @@ static const std::array full_months{ {"January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"}}; template -class B_formatter : public flag_formatter +class B_formatter final : public flag_formatter { public: explicit B_formatter(padding_info padinfo) @@ -933,16 +933,15 @@ public: dest.push_back(']'); dest.push_back(' '); -#ifndef SPDLOG_NO_NAME + // append logger name if exists if (msg.logger_name.size() > 0) { dest.push_back('['); - // fmt_helper::append_str(*msg.logger_name, dest); fmt_helper::append_string_view(msg.logger_name, dest); dest.push_back(']'); dest.push_back(' '); } -#endif + dest.push_back('['); // wrap the level name with color msg.color_range_start = dest.size(); @@ -974,11 +973,13 @@ private: } // namespace details -SPDLOG_INLINE pattern_formatter::pattern_formatter(std::string pattern, pattern_time_type time_type, std::string eol) +SPDLOG_INLINE pattern_formatter::pattern_formatter( + std::string pattern, pattern_time_type time_type, std::string eol, custom_flags custom_user_flags) : pattern_(std::move(pattern)) , eol_(std::move(eol)) , pattern_time_type_(time_type) , last_log_secs_(0) + , custom_handlers_(std::move(custom_user_flags)) { std::memset(&cached_tm_, 0, sizeof(cached_tm_)); compile_pattern_(pattern_); @@ -997,7 +998,12 @@ SPDLOG_INLINE pattern_formatter::pattern_formatter(pattern_time_type time_type, SPDLOG_INLINE std::unique_ptr pattern_formatter::clone() const { - return details::make_unique(pattern_, pattern_time_type_, eol_); + custom_flags cloned_custom_formatters; + for (auto &it : custom_handlers_) + { + cloned_custom_formatters[it.first] = it.second->clone(); + } + return details::make_unique(pattern_, pattern_time_type_, eol_, std::move(cloned_custom_formatters)); } SPDLOG_INLINE void pattern_formatter::format(const details::log_msg &msg, memory_buf_t &dest) @@ -1017,6 +1023,12 @@ SPDLOG_INLINE void pattern_formatter::format(const details::log_msg &msg, memory details::fmt_helper::append_string_view(eol_, dest); } +SPDLOG_INLINE void pattern_formatter::set_pattern(std::string pattern) +{ + pattern_ = std::move(pattern); + compile_pattern_(pattern_); +} + SPDLOG_INLINE std::tm pattern_formatter::get_time_(const details::log_msg &msg) { if (pattern_time_type_ == pattern_time_type::local) @@ -1029,9 +1041,19 @@ SPDLOG_INLINE std::tm pattern_formatter::get_time_(const details::log_msg &msg) template SPDLOG_INLINE void pattern_formatter::handle_flag_(char flag, details::padding_info padding) { + // process custom flags + auto it = custom_handlers_.find(flag); + if (it != custom_handlers_.end()) + { + auto custom_handler = it->second->clone(); + custom_handler->set_padding_info(padding); + formatters_.push_back(std::move(custom_handler)); + return; + } + + // process built-in flags switch (flag) { - case ('+'): // default formatter formatters_.push_back(details::make_unique(padding)); break; diff --git a/third_party/spdlog/include/spdlog/details/pattern_formatter.h b/third_party/spdlog/include/spdlog/pattern_formatter.h similarity index 67% rename from third_party/spdlog/include/spdlog/details/pattern_formatter.h rename to third_party/spdlog/include/spdlog/pattern_formatter.h index fa134ada..ecea6bcf 100644 --- a/third_party/spdlog/include/spdlog/details/pattern_formatter.h +++ b/third_party/spdlog/include/spdlog/pattern_formatter.h @@ -14,6 +14,7 @@ #include #include +#include namespace spdlog { namespace details { @@ -40,13 +41,13 @@ struct padding_info { return enabled_; } - const size_t width_ = 0; - const pad_side side_ = left; + size_t width_ = 0; + pad_side side_ = left; bool truncate_ = false; bool enabled_ = false; }; -class flag_formatter +class SPDLOG_API flag_formatter { public: explicit flag_formatter(padding_info padinfo) @@ -62,11 +63,24 @@ protected: } // namespace details -class pattern_formatter final : public formatter +class SPDLOG_API custom_flag_formatter : public details::flag_formatter { public: - explicit pattern_formatter( - std::string pattern, pattern_time_type time_type = pattern_time_type::local, std::string eol = spdlog::details::os::default_eol); + virtual std::unique_ptr clone() const = 0; + + void set_padding_info(details::padding_info padding) + { + flag_formatter::padinfo_ = padding; + } +}; + +class SPDLOG_API pattern_formatter final : public formatter +{ +public: + using custom_flags = std::unordered_map>; + + explicit pattern_formatter(std::string pattern, pattern_time_type time_type = pattern_time_type::local, + std::string eol = spdlog::details::os::default_eol, custom_flags custom_user_flags = {}); // use default pattern is not given explicit pattern_formatter(pattern_time_type time_type = pattern_time_type::local, std::string eol = spdlog::details::os::default_eol); @@ -77,6 +91,14 @@ public: std::unique_ptr clone() const override; void format(const details::log_msg &msg, memory_buf_t &dest) override; + template + pattern_formatter &add_flag(char flag, const Args &... args) + { + custom_handlers_[flag] = details::make_unique(args...); + return *this; + } + void set_pattern(std::string pattern); + private: std::string pattern_; std::string eol_; @@ -84,6 +106,7 @@ private: std::tm cached_tm_; std::chrono::seconds last_log_secs_; std::vector> formatters_; + custom_flags custom_handlers_; std::tm get_time_(const details::log_msg &msg); template @@ -92,7 +115,7 @@ private: // Extract given pad spec (e.g. %8X) // Advance the given it pass the end of the padding spec found (if any) // Return padding. - details::padding_info handle_padspec_(std::string::const_iterator &it, std::string::const_iterator end); + static details::padding_info handle_padspec_(std::string::const_iterator &it, std::string::const_iterator end); void compile_pattern_(const std::string &pattern); }; diff --git a/third_party/spdlog/include/spdlog/sinks/android_sink.h b/third_party/spdlog/include/spdlog/sinks/android_sink.h index bdbe542b..9686adff 100644 --- a/third_party/spdlog/include/spdlog/sinks/android_sink.h +++ b/third_party/spdlog/include/spdlog/sinks/android_sink.h @@ -64,7 +64,7 @@ protected: if (ret < 0) { - SPDLOG_THROW(spdlog_ex("__android_log_write() failed", ret)); + throw_spdlog_ex("__android_log_write() failed", ret); } } diff --git a/third_party/spdlog/include/spdlog/sinks/ansicolor_sink-inl.h b/third_party/spdlog/include/spdlog/sinks/ansicolor_sink-inl.h index 8480b06d..288aeced 100644 --- a/third_party/spdlog/include/spdlog/sinks/ansicolor_sink-inl.h +++ b/third_party/spdlog/include/spdlog/sinks/ansicolor_sink-inl.h @@ -7,7 +7,7 @@ #include #endif -#include +#include #include namespace spdlog { @@ -43,7 +43,8 @@ SPDLOG_INLINE void ansicolor_sink::log(const details::log_msg &msg // Wrap the originally formatted message in color codes. // If color is not supported in the terminal, log as is instead. std::lock_guard lock(mutex_); - + msg.color_range_start = 0; + msg.color_range_end = 0; memory_buf_t formatted; formatter_->format(msg, formatted); if (should_do_colors_ && msg.color_range_end > msg.color_range_start) @@ -111,7 +112,7 @@ SPDLOG_INLINE void ansicolor_sink::set_color_mode(color_mode mode) template SPDLOG_INLINE void ansicolor_sink::print_ccode_(const string_view_t &color_code) { - fwrite(color_code.data(), sizeof(string_view_t::char_type), color_code.size(), target_file_); + fwrite(color_code.data(), sizeof(char), color_code.size(), target_file_); } template diff --git a/third_party/spdlog/include/spdlog/sinks/ansicolor_sink.h b/third_party/spdlog/include/spdlog/sinks/ansicolor_sink.h index 16433019..90b590e6 100644 --- a/third_party/spdlog/include/spdlog/sinks/ansicolor_sink.h +++ b/third_party/spdlog/include/spdlog/sinks/ansicolor_sink.h @@ -9,7 +9,7 @@ #include #include #include -#include +#include namespace spdlog { namespace sinks { @@ -30,7 +30,11 @@ public: ~ansicolor_sink() override = default; ansicolor_sink(const ansicolor_sink &other) = delete; + ansicolor_sink(ansicolor_sink &&other) = delete; + ansicolor_sink &operator=(const ansicolor_sink &other) = delete; + ansicolor_sink &operator=(ansicolor_sink &&other) = delete; + void set_color(level::level_enum color_level, string_view_t color); void set_color_mode(color_mode mode); bool should_color(); @@ -80,7 +84,7 @@ private: mutex_t &mutex_; bool should_do_colors_; std::unique_ptr formatter_; - std::unordered_map colors_; + std::array colors_; void print_ccode_(const string_view_t &color_code); void print_range_(const memory_buf_t &formatted, size_t start, size_t end); }; diff --git a/third_party/spdlog/include/spdlog/sinks/base_sink-inl.h b/third_party/spdlog/include/spdlog/sinks/base_sink-inl.h index 2883c058..b15fb0e6 100644 --- a/third_party/spdlog/include/spdlog/sinks/base_sink-inl.h +++ b/third_party/spdlog/include/spdlog/sinks/base_sink-inl.h @@ -8,7 +8,7 @@ #endif #include -#include +#include #include diff --git a/third_party/spdlog/include/spdlog/sinks/base_sink.h b/third_party/spdlog/include/spdlog/sinks/base_sink.h index bc832763..bf5072f8 100644 --- a/third_party/spdlog/include/spdlog/sinks/base_sink.h +++ b/third_party/spdlog/include/spdlog/sinks/base_sink.h @@ -21,8 +21,14 @@ class base_sink : public sink public: base_sink(); explicit base_sink(std::unique_ptr formatter); + ~base_sink() override = default; + base_sink(const base_sink &) = delete; + base_sink(base_sink &&) = delete; + base_sink &operator=(const base_sink &) = delete; + base_sink &operator=(base_sink &&) = delete; + void log(const details::log_msg &msg) final; void flush() final; void set_pattern(const std::string &pattern) final; diff --git a/third_party/spdlog/include/spdlog/sinks/daily_file_sink.h b/third_party/spdlog/include/spdlog/sinks/daily_file_sink.h index 40a37a71..a3843af7 100644 --- a/third_party/spdlog/include/spdlog/sinks/daily_file_sink.h +++ b/third_party/spdlog/include/spdlog/sinks/daily_file_sink.h @@ -56,7 +56,7 @@ public: { if (rotation_hour < 0 || rotation_hour > 23 || rotation_minute < 0 || rotation_minute > 59) { - SPDLOG_THROW(spdlog_ex("daily_file_sink: Invalid rotation time in ctor")); + throw_spdlog_ex("daily_file_sink: Invalid rotation time in ctor"); } auto now = log_clock::now(); @@ -66,13 +66,13 @@ public: if (max_files_ > 0) { - filenames_q_ = details::circular_q(static_cast(max_files_)); - filenames_q_.push_back(std::move(filename)); + init_filenames_q_(); } } - const filename_t &filename() const + filename_t filename() { + std::lock_guard lock(base_sink::mutex_); return file_helper_.filename(); } @@ -104,6 +104,29 @@ protected: } private: + void init_filenames_q_() + { + using details::os::path_exists; + + filenames_q_ = details::circular_q(static_cast(max_files_)); + std::vector filenames; + auto now = log_clock::now(); + while (filenames.size() < max_files_) + { + auto filename = FileNameCalc::calc_filename(base_filename_, now_tm(now)); + if (!path_exists(filename)) + { + break; + } + filenames.emplace_back(filename); + now -= std::chrono::hours(24); + } + for (auto iter = filenames.rbegin(); iter != filenames.rend(); ++iter) + { + filenames_q_.push_back(std::move(*iter)); + } + } + tm now_tm(log_clock::time_point tp) { time_t tnow = log_clock::to_time_t(tp); @@ -141,7 +164,7 @@ private: if (!ok) { filenames_q_.push_back(std::move(current_file)); - SPDLOG_THROW(spdlog_ex("Failed removing daily file " + filename_to_str(old_filename), errno)); + throw_spdlog_ex("Failed removing daily file " + filename_to_str(old_filename), errno); } } filenames_q_.push_back(std::move(current_file)); @@ -167,15 +190,15 @@ using daily_file_sink_st = daily_file_sink; // template inline std::shared_ptr daily_logger_mt( - const std::string &logger_name, const filename_t &filename, int hour = 0, int minute = 0, bool truncate = false) + const std::string &logger_name, const filename_t &filename, int hour = 0, int minute = 0, bool truncate = false, uint16_t max_files = 0) { - return Factory::template create(logger_name, filename, hour, minute, truncate); + return Factory::template create(logger_name, filename, hour, minute, truncate, max_files); } template inline std::shared_ptr daily_logger_st( - const std::string &logger_name, const filename_t &filename, int hour = 0, int minute = 0, bool truncate = false) + const std::string &logger_name, const filename_t &filename, int hour = 0, int minute = 0, bool truncate = false, uint16_t max_files = 0) { - return Factory::template create(logger_name, filename, hour, minute, truncate); + return Factory::template create(logger_name, filename, hour, minute, truncate, max_files); } } // namespace spdlog diff --git a/third_party/spdlog/include/spdlog/sinks/dist_sink.h b/third_party/spdlog/include/spdlog/sinks/dist_sink.h index ae98fee4..8fccb4ee 100644 --- a/third_party/spdlog/include/spdlog/sinks/dist_sink.h +++ b/third_party/spdlog/include/spdlog/sinks/dist_sink.h @@ -6,7 +6,7 @@ #include "base_sink.h" #include #include -#include +#include #include #include diff --git a/third_party/spdlog/include/spdlog/sinks/msvc_sink.h b/third_party/spdlog/include/spdlog/sinks/msvc_sink.h index 6db10bc9..f6c25acb 100644 --- a/third_party/spdlog/include/spdlog/sinks/msvc_sink.h +++ b/third_party/spdlog/include/spdlog/sinks/msvc_sink.h @@ -8,6 +8,7 @@ #include #include +#include #include #include diff --git a/third_party/spdlog/include/spdlog/sinks/rotating_file_sink-inl.h b/third_party/spdlog/include/spdlog/sinks/rotating_file_sink-inl.h index bd2d175d..d715ebf3 100644 --- a/third_party/spdlog/include/spdlog/sinks/rotating_file_sink-inl.h +++ b/third_party/spdlog/include/spdlog/sinks/rotating_file_sink-inl.h @@ -54,8 +54,9 @@ SPDLOG_INLINE filename_t rotating_file_sink::calc_filename(const filename } template -SPDLOG_INLINE const filename_t &rotating_file_sink::filename() const +SPDLOG_INLINE filename_t rotating_file_sink::filename() { + std::lock_guard lock(base_sink::mutex_); return file_helper_.filename(); } @@ -99,18 +100,17 @@ SPDLOG_INLINE void rotating_file_sink::rotate_() } filename_t target = calc_filename(base_filename_, i); - if (!rename_file(src, target)) + if (!rename_file_(src, target)) { // if failed try again after a small delay. // this is a workaround to a windows issue, where very high rotation // rates can cause the rename to fail with permission denied (because of antivirus?). details::os::sleep_for_millis(100); - if (!rename_file(src, target)) + if (!rename_file_(src, target)) { file_helper_.reopen(true); // truncate the log file anyway to prevent it to grow beyond its limit! current_size_ = 0; - SPDLOG_THROW( - spdlog_ex("rotating_file_sink: failed renaming " + filename_to_str(src) + " to " + filename_to_str(target), errno)); + throw_spdlog_ex("rotating_file_sink: failed renaming " + filename_to_str(src) + " to " + filename_to_str(target), errno); } } } @@ -120,7 +120,7 @@ SPDLOG_INLINE void rotating_file_sink::rotate_() // delete the target if exists, and rename the src file to target // return true on success, false otherwise. template -SPDLOG_INLINE bool rotating_file_sink::rename_file(const filename_t &src_filename, const filename_t &target_filename) +SPDLOG_INLINE bool rotating_file_sink::rename_file_(const filename_t &src_filename, const filename_t &target_filename) { // try to delete the target file in case it already exists. (void)details::os::remove(target_filename); diff --git a/third_party/spdlog/include/spdlog/sinks/rotating_file_sink.h b/third_party/spdlog/include/spdlog/sinks/rotating_file_sink.h index 5be8583a..e1e85a7d 100644 --- a/third_party/spdlog/include/spdlog/sinks/rotating_file_sink.h +++ b/third_party/spdlog/include/spdlog/sinks/rotating_file_sink.h @@ -24,7 +24,7 @@ class rotating_file_sink final : public base_sink public: rotating_file_sink(filename_t base_filename, std::size_t max_size, std::size_t max_files, bool rotate_on_open = false); static filename_t calc_filename(const filename_t &filename, std::size_t index); - const filename_t &filename() const; + filename_t filename(); protected: void sink_it_(const details::log_msg &msg) override; @@ -40,7 +40,7 @@ private: // delete the target if exists, and rename the src file to target // return true on success, false otherwise. - bool rename_file(const filename_t &src_filename, const filename_t &target_filename); + bool rename_file_(const filename_t &src_filename, const filename_t &target_filename); filename_t base_filename_; std::size_t max_size_; @@ -75,4 +75,4 @@ inline std::shared_ptr rotating_logger_st( #ifdef SPDLOG_HEADER_ONLY #include "rotating_file_sink-inl.h" -#endif \ No newline at end of file +#endif diff --git a/third_party/spdlog/include/spdlog/sinks/sink.h b/third_party/spdlog/include/spdlog/sinks/sink.h index b2ca4db1..be99744d 100644 --- a/third_party/spdlog/include/spdlog/sinks/sink.h +++ b/third_party/spdlog/include/spdlog/sinks/sink.h @@ -9,7 +9,7 @@ namespace spdlog { namespace sinks { -class sink +class SPDLOG_API sink { public: virtual ~sink() = default; diff --git a/third_party/spdlog/include/spdlog/sinks/stdout_sinks-inl.h b/third_party/spdlog/include/spdlog/sinks/stdout_sinks-inl.h index adbcb632..20f2114f 100644 --- a/third_party/spdlog/include/spdlog/sinks/stdout_sinks-inl.h +++ b/third_party/spdlog/include/spdlog/sinks/stdout_sinks-inl.h @@ -8,7 +8,7 @@ #endif #include -#include +#include #include namespace spdlog { diff --git a/third_party/spdlog/include/spdlog/sinks/stdout_sinks.h b/third_party/spdlog/include/spdlog/sinks/stdout_sinks.h index 1cc47bd0..b962e1e2 100644 --- a/third_party/spdlog/include/spdlog/sinks/stdout_sinks.h +++ b/third_party/spdlog/include/spdlog/sinks/stdout_sinks.h @@ -19,8 +19,12 @@ public: using mutex_t = typename ConsoleMutex::mutex_t; explicit stdout_sink_base(FILE *file); ~stdout_sink_base() override = default; + stdout_sink_base(const stdout_sink_base &other) = delete; + stdout_sink_base(stdout_sink_base &&other) = delete; + stdout_sink_base &operator=(const stdout_sink_base &other) = delete; + stdout_sink_base &operator=(stdout_sink_base &&other) = delete; void log(const details::log_msg &msg) override; void flush() override; diff --git a/third_party/spdlog/include/spdlog/sinks/systemd_sink.h b/third_party/spdlog/include/spdlog/sinks/systemd_sink.h index d90edb22..d23824b8 100644 --- a/third_party/spdlog/include/spdlog/sinks/systemd_sink.h +++ b/third_party/spdlog/include/spdlog/sinks/systemd_sink.h @@ -72,7 +72,7 @@ protected: if (err) { - SPDLOG_THROW(spdlog_ex("Failed writing to systemd", errno)); + throw_spdlog_ex("Failed writing to systemd", errno); } } diff --git a/third_party/spdlog/include/spdlog/sinks/tcp_sink.h b/third_party/spdlog/include/spdlog/sinks/tcp_sink.h new file mode 100644 index 00000000..9dd9e51d --- /dev/null +++ b/third_party/spdlog/include/spdlog/sinks/tcp_sink.h @@ -0,0 +1,81 @@ +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) + +#pragma once + +#include +#include +#include +#ifdef _WIN32 +#include +#else +#include +#endif + +#include +#include +#include +#include + +#pragma once + +// Simple tcp client sink +// Connects to remote address and send the formatted log. +// Will attempt to reconnect if connection drops. +// If more complicated behaviour is needed (i.e get responses), you can inherit it and override the sink_it_ method. + +namespace spdlog { +namespace sinks { + +struct tcp_sink_config +{ + std::string server_host; + int server_port; + bool lazy_connect = false; // if true connect on first log call instead of on construction + + tcp_sink_config(std::string host, int port) + : server_host{std::move(host)} + , server_port{port} + {} +}; + +template +class tcp_sink : public spdlog::sinks::base_sink +{ +public: + // connect to tcp host/port or throw if failed + // host can be hostname or ip address + + explicit tcp_sink(tcp_sink_config sink_config) + : config_{std::move(sink_config)} + { + if (!config_.lazy_connect) + { + this->client_.connect(config_.server_host, config_.server_port); + } + } + + ~tcp_sink() override = default; + +protected: + void sink_it_(const spdlog::details::log_msg &msg) override + { + spdlog::memory_buf_t formatted; + spdlog::sinks::base_sink::formatter_->format(msg, formatted); + if (!client_.is_connected()) + { + client_.connect(config_.server_host, config_.server_port); + } + client_.send(formatted.data(), formatted.size()); + } + + void flush_() override {} + tcp_sink_config config_; + details::tcp_client client_; +}; + +using tcp_sink_mt = tcp_sink; +using tcp_sink_st = tcp_sink; + +} // namespace sinks +} // namespace spdlog diff --git a/third_party/spdlog/include/spdlog/sinks/win_eventlog_sink.h b/third_party/spdlog/include/spdlog/sinks/win_eventlog_sink.h new file mode 100644 index 00000000..384fa9eb --- /dev/null +++ b/third_party/spdlog/include/spdlog/sinks/win_eventlog_sink.h @@ -0,0 +1,266 @@ +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) + +// Writing to Windows Event Log requires the registry entries below to be present, with the following modifications: +// 1. should be replaced with your log name (e.g. your application name) +// 2. should be replaced with the specific source name and the key should be duplicated for +// each source used in the application +// +// Since typically modifications of this kind require elevation, it's better to do it as a part of setup procedure. +// The snippet below uses mscoree.dll as the message file as it exists on most of the Windows systems anyway and +// happens to contain the needed resource. +// +// You can also specify a custom message file if needed. +// Please refer to Event Log functions descriptions in MSDN for more details on custom message files. + +/*--------------------------------------------------------------------------------------- + +Windows Registry Editor Version 5.00 + +[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\EventLog\] + +[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\EventLog\\] +"TypesSupported"=dword:00000007 +"EventMessageFile"=hex(2):25,00,73,00,79,00,73,00,74,00,65,00,6d,00,72,00,6f,\ + 00,6f,00,74,00,25,00,5c,00,53,00,79,00,73,00,74,00,65,00,6d,00,33,00,32,00,\ + 5c,00,6d,00,73,00,63,00,6f,00,72,00,65,00,65,00,2e,00,64,00,6c,00,6c,00,00,\ + 00 + +-----------------------------------------------------------------------------------------*/ + +#pragma once + +#include +#include + +#include +#include + +#include +#include +#include + +namespace spdlog { +namespace sinks { + +namespace win_eventlog { + +namespace internal { + +/** Windows error */ +struct win32_error : public spdlog_ex +{ + /** Formats an error report line: "user-message: error-code (system message)" */ + static std::string format(std::string const &user_message, DWORD error_code = GetLastError()) + { + std::string system_message; + + LPSTR format_message_result{}; + auto format_message_succeeded = + ::FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, nullptr, + error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&format_message_result, 0, nullptr); + + if (format_message_succeeded && format_message_result) + { + system_message = fmt::format(" ({})", format_message_result); + } + + if (format_message_result) + { + LocalFree((HLOCAL)format_message_result); + } + + return fmt::format("{}: {}{}", user_message, error_code, system_message); + } + + explicit win32_error(std::string const &func_name, DWORD error = GetLastError()) + : spdlog_ex(format(func_name, error)) + {} +}; + +/** Wrapper for security identifiers (SID) on Windows */ +struct sid_t +{ + std::vector buffer_; + +public: + sid_t() {} + + /** creates a wrapped SID copy */ + static sid_t duplicate_sid(PSID psid) + { + if (!::IsValidSid(psid)) + { + throw_spdlog_ex("sid_t::sid_t(): invalid SID received"); + } + + auto const sid_length{::GetLengthSid(psid)}; + + sid_t result; + result.buffer_.resize(sid_length); + if (!::CopySid(sid_length, (PSID)result.as_sid(), psid)) + { + SPDLOG_THROW(win32_error("CopySid")); + } + + return result; + } + + /** Retrieves pointer to the internal buffer contents as SID* */ + SID *as_sid() const + { + return buffer_.empty() ? nullptr : (SID *)buffer_.data(); + } + + /** Get SID for the current user */ + static sid_t get_current_user_sid() + { + /* create and init RAII holder for process token */ + struct process_token_t + { + HANDLE token_handle_ = INVALID_HANDLE_VALUE; + explicit process_token_t(HANDLE process) + { + if (!::OpenProcessToken(process, TOKEN_QUERY, &token_handle_)) + { + SPDLOG_THROW(win32_error("OpenProcessToken")); + } + } + + ~process_token_t() + { + ::CloseHandle(token_handle_); + } + + } current_process_token(::GetCurrentProcess()); // GetCurrentProcess returns pseudohandle, no leak here! + + // Get the required size, this is expected to fail with ERROR_INSUFFICIENT_BUFFER and return the token size + DWORD tusize = 0; + if (::GetTokenInformation(current_process_token.token_handle_, TokenUser, NULL, 0, &tusize)) + { + SPDLOG_THROW(win32_error("GetTokenInformation should fail")); + } + + // get user token + std::vector buffer(static_cast(tusize)); + if (!::GetTokenInformation(current_process_token.token_handle_, TokenUser, (LPVOID)buffer.data(), tusize, &tusize)) + { + SPDLOG_THROW(win32_error("GetTokenInformation")); + } + + // create a wrapper of the SID data as stored in the user token + return sid_t::duplicate_sid(((TOKEN_USER *)buffer.data())->User.Sid); + } +}; + +struct eventlog +{ + static WORD get_event_type(details::log_msg const &msg) + { + switch (msg.level) + { + case level::trace: + case level::debug: + return EVENTLOG_SUCCESS; + + case level::info: + return EVENTLOG_INFORMATION_TYPE; + + case level::warn: + return EVENTLOG_WARNING_TYPE; + + case level::err: + case level::critical: + case level::off: + return EVENTLOG_ERROR_TYPE; + + default: + return EVENTLOG_INFORMATION_TYPE; + } + } + + static WORD get_event_category(details::log_msg const &msg) + { + return (WORD)msg.level; + } +}; + +} // namespace internal + +/* + * Windows Event Log sink + */ +template +class win_eventlog_sink : public base_sink +{ +private: + HANDLE hEventLog_{NULL}; + internal::sid_t current_user_sid_; + std::string source_; + WORD event_id_; + + HANDLE event_log_handle() + { + if (!hEventLog_) + { + hEventLog_ = ::RegisterEventSource(nullptr, source_.c_str()); + if (!hEventLog_ || hEventLog_ == (HANDLE)ERROR_ACCESS_DENIED) + { + SPDLOG_THROW(internal::win32_error("RegisterEventSource")); + } + } + + return hEventLog_; + } + +protected: + void sink_it_(const details::log_msg &msg) override + { + using namespace internal; + + memory_buf_t formatted; + base_sink::formatter_->format(msg, formatted); + formatted.push_back('\0'); + LPCSTR lp_str = static_cast(formatted.data()); + + auto succeeded = ::ReportEvent(event_log_handle(), eventlog::get_event_type(msg), eventlog::get_event_category(msg), event_id_, + current_user_sid_.as_sid(), 1, 0, &lp_str, nullptr); + + if (!succeeded) + { + SPDLOG_THROW(win32_error("ReportEvent")); + } + } + + void flush_() override {} + +public: + win_eventlog_sink(std::string const &source, WORD event_id = 1000 /* according to mscoree.dll */) + : source_(source) + , event_id_(event_id) + { + try + { + current_user_sid_ = internal::sid_t::get_current_user_sid(); + } + catch (...) + { + // get_current_user_sid() is unlikely to fail and if it does, we can still proceed without + // current_user_sid but in the event log the record will have no user name + } + } + + ~win_eventlog_sink() + { + if (hEventLog_) + DeregisterEventSource(hEventLog_); + } +}; + +} // namespace win_eventlog + +using win_eventlog_sink_mt = win_eventlog::win_eventlog_sink; +using win_eventlog_sink_st = win_eventlog::win_eventlog_sink; + +} // namespace sinks +} // namespace spdlog diff --git a/third_party/spdlog/include/spdlog/sinks/wincolor_sink-inl.h b/third_party/spdlog/include/spdlog/sinks/wincolor_sink-inl.h index 6ce9cac3..71e3a8ce 100644 --- a/third_party/spdlog/include/spdlog/sinks/wincolor_sink-inl.h +++ b/third_party/spdlog/include/spdlog/sinks/wincolor_sink-inl.h @@ -8,7 +8,7 @@ #endif #include -#include +#include namespace spdlog { namespace sinks { @@ -52,6 +52,8 @@ template void SPDLOG_INLINE wincolor_sink::log(const details::log_msg &msg) { std::lock_guard lock(mutex_); + msg.color_range_start = 0; + msg.color_range_end = 0; memory_buf_t formatted; formatter_->format(msg, formatted); if (!in_console_) @@ -59,7 +61,6 @@ void SPDLOG_INLINE wincolor_sink::log(const details::log_msg &msg) write_to_file_(formatted); return; } - if (should_do_colors_ && msg.color_range_end > msg.color_range_start) { // before color range @@ -157,7 +158,7 @@ void SPDLOG_INLINE wincolor_sink::write_to_file_(const memory_buf_ bool ok = ::WriteFile(out_handle_, formatted.data() + total_written, size - total_written, &bytes_written, nullptr) != 0; if (!ok || bytes_written == 0) { - SPDLOG_THROW(spdlog_ex("wincolor_sink: write_to_file_ failed. GetLastError(): " + std::to_string(::GetLastError()))); + throw_spdlog_ex("wincolor_sink: write_to_file_ failed. GetLastError(): " + std::to_string(::GetLastError())); } total_written += bytes_written; } while (total_written < size); diff --git a/third_party/spdlog/include/spdlog/sinks/wincolor_sink.h b/third_party/spdlog/include/spdlog/sinks/wincolor_sink.h index 743db5c6..8d4d08fd 100644 --- a/third_party/spdlog/include/spdlog/sinks/wincolor_sink.h +++ b/third_party/spdlog/include/spdlog/sinks/wincolor_sink.h @@ -11,7 +11,9 @@ #include #include #include -#include +#include + +#include #include namespace spdlog { @@ -52,7 +54,7 @@ protected: bool in_console_; bool should_do_colors_; std::unique_ptr formatter_; - std::unordered_map colors_; + std::array colors_; // set foreground color and return the orig console attributes (for resetting later) WORD set_foreground_color_(WORD attribs); diff --git a/third_party/spdlog/include/spdlog/spdlog-inl.h b/third_party/spdlog/include/spdlog/spdlog-inl.h index 43aa49ef..02e818a4 100644 --- a/third_party/spdlog/include/spdlog/spdlog-inl.h +++ b/third_party/spdlog/include/spdlog/spdlog-inl.h @@ -8,7 +8,7 @@ #endif #include -#include +#include namespace spdlog { diff --git a/third_party/spdlog/include/spdlog/spdlog.h b/third_party/spdlog/include/spdlog/spdlog.h index facb0b3f..55de6676 100644 --- a/third_party/spdlog/include/spdlog/spdlog.h +++ b/third_party/spdlog/include/spdlog/spdlog.h @@ -39,68 +39,66 @@ inline std::shared_ptr create(std::string logger_name, SinkArgs // Initialize and register a logger, // formatter and flush level will be set according the global settings. // -// NOTE: -// Use this function when creating loggers manually. +// Useful for initializing manually created loggers with the global settings. // // Example: -// auto console_sink = std::make_shared(); -// auto console_logger = std::make_shared("console_logger", console_sink); -// spdlog::initialize_logger(console_logger); -void initialize_logger(std::shared_ptr logger); +// auto mylogger = std::make_shared("mylogger", ...); +// spdlog::initialize_logger(mylogger); +SPDLOG_API void initialize_logger(std::shared_ptr logger); // Return an existing logger or nullptr if a logger with such name doesn't // exist. // example: spdlog::get("my_logger")->info("hello {}", "world"); -std::shared_ptr get(const std::string &name); +SPDLOG_API std::shared_ptr get(const std::string &name); // Set global formatter. Each sink in each logger will get a clone of this object -void set_formatter(std::unique_ptr formatter); +SPDLOG_API void set_formatter(std::unique_ptr formatter); // Set global format string. // example: spdlog::set_pattern("%Y-%m-%d %H:%M:%S.%e %l : %v"); -void set_pattern(std::string pattern, pattern_time_type time_type = pattern_time_type::local); +SPDLOG_API void set_pattern(std::string pattern, pattern_time_type time_type = pattern_time_type::local); // enable global backtrace support -void enable_backtrace(size_t n_messages); +SPDLOG_API void enable_backtrace(size_t n_messages); // disable global backtrace support -void disable_backtrace(); +SPDLOG_API void disable_backtrace(); // call dump backtrace on default logger -void dump_backtrace(); +SPDLOG_API void dump_backtrace(); // Set global logging level -void set_level(level::level_enum log_level); +SPDLOG_API void set_level(level::level_enum log_level); // Set global flush level -void flush_on(level::level_enum log_level); +SPDLOG_API void flush_on(level::level_enum log_level); // Start/Restart a periodic flusher thread // Warning: Use only if all your loggers are thread safe! -void flush_every(std::chrono::seconds interval); +SPDLOG_API void flush_every(std::chrono::seconds interval); // Set global error handler -void set_error_handler(void (*handler)(const std::string &msg)); +SPDLOG_API void set_error_handler(void (*handler)(const std::string &msg)); // Register the given logger with the given name -void register_logger(std::shared_ptr logger); +SPDLOG_API void register_logger(std::shared_ptr logger); // Apply a user defined function on all registered loggers // Example: // spdlog::apply_all([&](std::shared_ptr l) {l->flush();}); -void apply_all(const std::function)> &fun); +SPDLOG_API void apply_all(const std::function)> &fun); // Drop the reference to the given logger -void drop(const std::string &name); +SPDLOG_API void drop(const std::string &name); // Drop all references from the registry -void drop_all(); +SPDLOG_API void drop_all(); // stop any running threads started by spdlog and clean registry loggers -void shutdown(); +SPDLOG_API void shutdown(); // Automatic registration of loggers when using spdlog::create() or spdlog::create_async -void set_automatic_registration(bool automatic_registration); +SPDLOG_API void set_automatic_registration(bool automatic_registration); // API for using default logger (stdout_color_mt), // e.g: spdlog::info("Message {}", 1); @@ -117,11 +115,11 @@ void set_automatic_registration(bool automatic_registration); // set_default_logger() *should not* be used concurrently with the default API. // e.g do not call set_default_logger() from one thread while calling spdlog::info() from another. -std::shared_ptr default_logger(); +SPDLOG_API std::shared_ptr default_logger(); -spdlog::logger *default_logger_raw(); +SPDLOG_API spdlog::logger *default_logger_raw(); -void set_default_logger(std::shared_ptr default_logger); +SPDLOG_API void set_default_logger(std::shared_ptr default_logger); template inline void log(source_loc source, level::level_enum lvl, string_view_t fmt, const Args &... args) diff --git a/third_party/spdlog/include/spdlog/tweakme.h b/third_party/spdlog/include/spdlog/tweakme.h index b67043e0..244bc3b3 100644 --- a/third_party/spdlog/include/spdlog/tweakme.h +++ b/third_party/spdlog/include/spdlog/tweakme.h @@ -24,7 +24,7 @@ // This will prevent spdlog from querying the thread id on each log call. // // WARNING: If the log pattern contains thread id (i.e, %t) while this flag is -// on, the result is undefined. +// on, zero will be logged as thread id. // // #define SPDLOG_NO_THREAD_ID /////////////////////////////////////////////////////////////////////////////// @@ -38,13 +38,6 @@ // #define SPDLOG_NO_TLS /////////////////////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////////// -// Uncomment if logger name logging is not needed. -// This will prevent spdlog from copying the logger name on each log call. -// -// #define SPDLOG_NO_NAME -/////////////////////////////////////////////////////////////////////////////// - /////////////////////////////////////////////////////////////////////////////// // Uncomment to avoid spdlog's usage of atomic log levels // Use only if your code never modifies a logger's log levels concurrently by diff --git a/third_party/spdlog/include/spdlog/version.h b/third_party/spdlog/include/spdlog/version.h index 5f2a68b2..f6d8224e 100644 --- a/third_party/spdlog/include/spdlog/version.h +++ b/third_party/spdlog/include/spdlog/version.h @@ -4,7 +4,7 @@ #pragma once #define SPDLOG_VER_MAJOR 1 -#define SPDLOG_VER_MINOR 5 +#define SPDLOG_VER_MINOR 6 #define SPDLOG_VER_PATCH 0 #define SPDLOG_VERSION (SPDLOG_VER_MAJOR * 10000 + SPDLOG_VER_MINOR * 100 + SPDLOG_VER_PATCH) diff --git a/third_party/spdlog/logos/jetbrains-variant-4.svg b/third_party/spdlog/logos/jetbrains-variant-4.svg new file mode 100644 index 00000000..e02b5595 --- /dev/null +++ b/third_party/spdlog/logos/jetbrains-variant-4.svg @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/third_party/spdlog/meson.build b/third_party/spdlog/meson.build index 1ab1e0a7..fae42bfc 100644 --- a/third_party/spdlog/meson.build +++ b/third_party/spdlog/meson.build @@ -23,7 +23,7 @@ if get_option('external_fmt') if not meson.version().version_compare('>=0.49.0') warning('Finding fmt can fail with meson versions before 0.49.0') endif - dep_list += dependency('fmt') + dep_list += dependency('fmt', fallback : ['fmt', 'fmt_dep']) compile_args += '-DSPDLOG_FMT_EXTERNAL' endif @@ -82,7 +82,8 @@ spdlog_srcs = files([ 'src/color_sinks.cpp', 'src/file_sinks.cpp', 'src/spdlog.cpp', - 'src/stdout_sinks.cpp' + 'src/stdout_sinks.cpp', + 'src/cfg.cpp' ]) if not get_option('external_fmt') @@ -148,7 +149,7 @@ endif # --- Conditionally add subdirs --- # ------------------------------------- -if get_option('enable_tests') or get_option('enable_tests-ho') +if get_option('enable_tests') or get_option('enable_tests_ho') subdir('tests') endif diff --git a/third_party/spdlog/scripts/clang_tidy.sh b/third_party/spdlog/scripts/clang_tidy.sh deleted file mode 100755 index b62bfaf1..00000000 --- a/third_party/spdlog/scripts/clang_tidy.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/bash - -cd "$(dirname "$0")" - -clang-tidy ../example/example.cpp -- -I ../include diff --git a/third_party/spdlog/scripts/format.sh b/third_party/spdlog/scripts/format.sh index ef52a5f1..d1c36007 100755 --- a/third_party/spdlog/scripts/format.sh +++ b/third_party/spdlog/scripts/format.sh @@ -1,12 +1,12 @@ #!/bin/bash -cd "$(dirname "$0")" - +cd "$(dirname "$0")"/.. +pwd echo -n "Running dos2unix " -find .. -name "*\.h" -o -name "*\.cpp"|grep -v bundled|xargs -I {} sh -c "dos2unix '{}' 2>/dev/null; echo -n '.'" +find . -name "*\.h" -o -name "*\.cpp"|grep -v bundled|xargs -I {} sh -c "dos2unix '{}' 2>/dev/null; echo -n '.'" echo echo -n "Running clang-format " -find .. -name "*\.h" -o -name "*\.cpp"|grep -v bundled|xargs -I {} sh -c "clang-format -i {}; echo -n '.'" +find . -name "*\.h" -o -name "*\.cpp"|grep -v bundled|xargs -I {} sh -c "clang-format -i {}; echo -n '.'" echo diff --git a/third_party/spdlog/src/async.cpp b/third_party/spdlog/src/async.cpp index f9557a84..d7ee8274 100644 --- a/third_party/spdlog/src/async.cpp +++ b/third_party/spdlog/src/async.cpp @@ -5,8 +5,9 @@ #error Please define SPDLOG_COMPILED_LIB to compile this file. #endif -#include "spdlog/async.h" -#include "spdlog/async_logger-inl.h" -#include "spdlog/details/periodic_worker-inl.h" -#include "spdlog/details/thread_pool-inl.h" -template class spdlog::details::mpmc_blocking_queue; \ No newline at end of file +#include +#include +#include +#include + +template class SPDLOG_API spdlog::details::mpmc_blocking_queue; \ No newline at end of file diff --git a/third_party/spdlog/src/cfg.cpp b/third_party/spdlog/src/cfg.cpp new file mode 100644 index 00000000..d3fe47f3 --- /dev/null +++ b/third_party/spdlog/src/cfg.cpp @@ -0,0 +1,8 @@ +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) + +#ifndef SPDLOG_COMPILED_LIB +#error Please define SPDLOG_COMPILED_LIB to compile this file. +#endif + +#include \ No newline at end of file diff --git a/third_party/spdlog/src/color_sinks.cpp b/third_party/spdlog/src/color_sinks.cpp index 3a335a77..e5de1854 100644 --- a/third_party/spdlog/src/color_sinks.cpp +++ b/third_party/spdlog/src/color_sinks.cpp @@ -7,19 +7,19 @@ #include -#include "spdlog/details/null_mutex.h" -#include "spdlog/async.h" +#include +#include // // color sinks // #ifdef _WIN32 -#include "spdlog/sinks/wincolor_sink-inl.h" -template class spdlog::sinks::wincolor_sink; -template class spdlog::sinks::wincolor_sink; -template class spdlog::sinks::wincolor_stdout_sink; -template class spdlog::sinks::wincolor_stdout_sink; -template class spdlog::sinks::wincolor_stderr_sink; -template class spdlog::sinks::wincolor_stderr_sink; +#include +template class SPDLOG_API spdlog::sinks::wincolor_sink; +template class SPDLOG_API spdlog::sinks::wincolor_sink; +template class SPDLOG_API spdlog::sinks::wincolor_stdout_sink; +template class SPDLOG_API spdlog::sinks::wincolor_stdout_sink; +template class SPDLOG_API spdlog::sinks::wincolor_stderr_sink; +template class SPDLOG_API spdlog::sinks::wincolor_stderr_sink; #else #include "spdlog/sinks/ansicolor_sink-inl.h" template class spdlog::sinks::ansicolor_sink; @@ -32,16 +32,20 @@ template class spdlog::sinks::ansicolor_stderr_sink spdlog::stdout_color_mt( +template SPDLOG_API std::shared_ptr spdlog::stdout_color_mt( const std::string &logger_name, color_mode mode); -template std::shared_ptr spdlog::stdout_color_st( +template SPDLOG_API std::shared_ptr spdlog::stdout_color_st( const std::string &logger_name, color_mode mode); -template std::shared_ptr spdlog::stderr_color_mt( +template SPDLOG_API std::shared_ptr spdlog::stderr_color_mt( const std::string &logger_name, color_mode mode); -template std::shared_ptr spdlog::stderr_color_st( +template SPDLOG_API std::shared_ptr spdlog::stderr_color_st( const std::string &logger_name, color_mode mode); -template std::shared_ptr spdlog::stdout_color_mt(const std::string &logger_name, color_mode mode); -template std::shared_ptr spdlog::stdout_color_st(const std::string &logger_name, color_mode mode); -template std::shared_ptr spdlog::stderr_color_mt(const std::string &logger_name, color_mode mode); -template std::shared_ptr spdlog::stderr_color_st(const std::string &logger_name, color_mode mode); +template SPDLOG_API std::shared_ptr spdlog::stdout_color_mt( + const std::string &logger_name, color_mode mode); +template SPDLOG_API std::shared_ptr spdlog::stdout_color_st( + const std::string &logger_name, color_mode mode); +template SPDLOG_API std::shared_ptr spdlog::stderr_color_mt( + const std::string &logger_name, color_mode mode); +template SPDLOG_API std::shared_ptr spdlog::stderr_color_st( + const std::string &logger_name, color_mode mode); diff --git a/third_party/spdlog/src/file_sinks.cpp b/third_party/spdlog/src/file_sinks.cpp index bc23f8d5..5fd7e98a 100644 --- a/third_party/spdlog/src/file_sinks.cpp +++ b/third_party/spdlog/src/file_sinks.cpp @@ -5,14 +5,16 @@ #error Please define SPDLOG_COMPILED_LIB to compile this file. #endif +#include +#include +#include +#include + #include -#include "spdlog/details/null_mutex.h" -#include "spdlog/details/file_helper-inl.h" -#include "spdlog/sinks/basic_file_sink-inl.h" -template class spdlog::sinks::basic_file_sink; -template class spdlog::sinks::basic_file_sink; +template class SPDLOG_API spdlog::sinks::basic_file_sink; +template class SPDLOG_API spdlog::sinks::basic_file_sink; -#include "spdlog/sinks/rotating_file_sink-inl.h" -template class spdlog::sinks::rotating_file_sink; -template class spdlog::sinks::rotating_file_sink; \ No newline at end of file +#include +template class SPDLOG_API spdlog::sinks::rotating_file_sink; +template class SPDLOG_API spdlog::sinks::rotating_file_sink; \ No newline at end of file diff --git a/third_party/spdlog/src/fmt.cpp b/third_party/spdlog/src/fmt.cpp index 431b2a57..c196ab1b 100644 --- a/third_party/spdlog/src/fmt.cpp +++ b/third_party/spdlog/src/fmt.cpp @@ -6,32 +6,153 @@ // Copyright (c) 2012 - 2016, Victor Zverovich // All rights reserved. -#if defined(__GNUC__) || defined(__clang__) -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wimplicit-fallthrough" -#pragma GCC diagnostic ignored "-Wsign-conversion" -#endif - #if !defined(SPDLOG_FMT_EXTERNAL) -#include "spdlog/fmt/bundled/format-inl.h" - - -// pop warnings supressions -#if defined(__GNUC__) || defined(__clang__) -#pragma GCC diagnostic pop -#endif - +#include FMT_BEGIN_NAMESPACE +namespace internal { + +template +int format_float(char *buf, std::size_t size, const char *format, int precision, T value) +{ +#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION + if (precision > 100000) + throw std::runtime_error("fuzz mode - avoid large allocation inside snprintf"); +#endif + // Suppress the warning about nonliteral format string. + auto snprintf_ptr = FMT_SNPRINTF; + return precision < 0 ? snprintf_ptr(buf, size, format, value) : snprintf_ptr(buf, size, format, precision, value); +} +struct sprintf_specs +{ + int precision; + char type; + bool alt : 1; + + template + constexpr sprintf_specs(basic_format_specs specs) + : precision(specs.precision) + , type(specs.type) + , alt(specs.alt) + {} + + constexpr bool has_precision() const + { + return precision >= 0; + } +}; + +// This is deprecated and is kept only to preserve ABI compatibility. +template +char *sprintf_format(Double value, internal::buffer &buf, sprintf_specs specs) +{ + // Buffer capacity must be non-zero, otherwise MSVC's vsnprintf_s will fail. + FMT_ASSERT(buf.capacity() != 0, "empty buffer"); + + // Build format string. + enum + { + max_format_size = 10 + }; // longest format: %#-*.*Lg + char format[max_format_size]; + char *format_ptr = format; + *format_ptr++ = '%'; + if (specs.alt || !specs.type) + *format_ptr++ = '#'; + if (specs.precision >= 0) + { + *format_ptr++ = '.'; + *format_ptr++ = '*'; + } + if (std::is_same::value) + *format_ptr++ = 'L'; + + char type = specs.type; + + if (type == '%') + type = 'f'; + else if (type == 0 || type == 'n') + type = 'g'; +#if FMT_MSC_VER + if (type == 'F') + { + // MSVC's printf doesn't support 'F'. + type = 'f'; + } +#endif + *format_ptr++ = type; + *format_ptr = '\0'; + + // Format using snprintf. + char *start = nullptr; + char *decimal_point_pos = nullptr; + for (;;) + { + std::size_t buffer_size = buf.capacity(); + start = &buf[0]; + int result = format_float(start, buffer_size, format, specs.precision, value); + if (result >= 0) + { + unsigned n = internal::to_unsigned(result); + if (n < buf.capacity()) + { + // Find the decimal point. + auto p = buf.data(), end = p + n; + if (*p == '+' || *p == '-') + ++p; + if (specs.type != 'a' && specs.type != 'A') + { + while (p < end && *p >= '0' && *p <= '9') + ++p; + if (p < end && *p != 'e' && *p != 'E') + { + decimal_point_pos = p; + if (!specs.type) + { + // Keep only one trailing zero after the decimal point. + ++p; + if (*p == '0') + ++p; + while (p != end && *p >= '1' && *p <= '9') + ++p; + char *where = p; + while (p != end && *p == '0') + ++p; + if (p == end || *p < '0' || *p > '9') + { + if (p != end) + std::memmove(where, p, to_unsigned(end - p)); + n -= static_cast(p - where); + } + } + } + } + buf.resize(n); + break; // The buffer is large enough - continue with formatting. + } + buf.reserve(n + 1); + } + else + { + // If result is negative we ask to increase the capacity by at least 1, + // but as std::vector, the buffer grows exponentially. + buf.reserve(buf.capacity() + 1); + } + } + return decimal_point_pos; +} +} // namespace internal + +template FMT_API char *internal::sprintf_format(double, internal::buffer &, sprintf_specs); +template FMT_API char *internal::sprintf_format(long double, internal::buffer &, sprintf_specs); + template struct FMT_API internal::basic_data; // Workaround a bug in MSVC2013 that prevents instantiation of format_float. -int (*instantiate_format_float)(double, int, internal::float_specs, - internal::buffer&) = -internal::format_float; +int (*instantiate_format_float)(double, int, internal::float_specs, internal::buffer &) = internal::format_float; #ifndef FMT_STATIC_THOUSANDS_SEPARATOR -template FMT_API internal::locale_ref::locale_ref(const std::locale& loc); +template FMT_API internal::locale_ref::locale_ref(const std::locale &loc); template FMT_API std::locale internal::locale_ref::get() const; #endif @@ -41,28 +162,18 @@ template FMT_API std::string internal::grouping_impl(locale_ref); template FMT_API char internal::thousands_sep_impl(locale_ref); template FMT_API char internal::decimal_point_impl(locale_ref); -template FMT_API void internal::buffer::append(const char*, const char*); +template FMT_API void internal::buffer::append(const char *, const char *); -template FMT_API void internal::arg_map::init( - const basic_format_args& args); +template FMT_API void internal::arg_map::init(const basic_format_args &args); -template FMT_API std::string internal::vformat( - string_view, basic_format_args); +template FMT_API std::string internal::vformat(string_view, basic_format_args); -template FMT_API format_context::iterator internal::vformat_to( - internal::buffer&, string_view, basic_format_args); +template FMT_API format_context::iterator internal::vformat_to(internal::buffer &, string_view, basic_format_args); -template FMT_API int internal::snprintf_float(double, int, - internal::float_specs, - internal::buffer&); -template FMT_API int internal::snprintf_float(long double, int, - internal::float_specs, - internal::buffer&); -template FMT_API int internal::format_float(double, int, internal::float_specs, - internal::buffer&); -template FMT_API int internal::format_float(long double, int, - internal::float_specs, - internal::buffer&); +template FMT_API int internal::snprintf_float(double, int, internal::float_specs, internal::buffer &); +template FMT_API int internal::snprintf_float(long double, int, internal::float_specs, internal::buffer &); +template FMT_API int internal::format_float(double, int, internal::float_specs, internal::buffer &); +template FMT_API int internal::format_float(long double, int, internal::float_specs, internal::buffer &); // Explicit instantiations for wchar_t. @@ -70,11 +181,9 @@ template FMT_API std::string internal::grouping_impl(locale_ref); template FMT_API wchar_t internal::thousands_sep_impl(locale_ref); template FMT_API wchar_t internal::decimal_point_impl(locale_ref); -template FMT_API void internal::buffer::append(const wchar_t*, - const wchar_t*); +template FMT_API void internal::buffer::append(const wchar_t *, const wchar_t *); -template FMT_API std::wstring internal::vformat( - wstring_view, basic_format_args); +template FMT_API std::wstring internal::vformat(wstring_view, basic_format_args); FMT_END_NAMESPACE #endif diff --git a/third_party/spdlog/src/spdlog.cpp b/third_party/spdlog/src/spdlog.cpp index ec183c95..c0904e6c 100644 --- a/third_party/spdlog/src/spdlog.cpp +++ b/third_party/spdlog/src/spdlog.cpp @@ -5,22 +5,22 @@ #error Please define SPDLOG_COMPILED_LIB to compile this file. #endif -#include "spdlog/spdlog-inl.h" -#include "spdlog/common-inl.h" -#include "spdlog/details/backtracer-inl.h" -#include "spdlog/details/registry-inl.h" -#include "spdlog/details/os-inl.h" -#include "spdlog/details/pattern_formatter-inl.h" -#include "spdlog/details/log_msg-inl.h" -#include "spdlog/details/log_msg_buffer-inl.h" -#include "spdlog/logger-inl.h" -#include "spdlog/sinks/sink-inl.h" -#include "spdlog/sinks/base_sink-inl.h" -#include "spdlog/details/null_mutex.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include // template instantiate logger constructor with sinks init list -template spdlog::logger::logger(std::string name, sinks_init_list::iterator begin, sinks_init_list::iterator end); -template class spdlog::sinks::base_sink; -template class spdlog::sinks::base_sink; \ No newline at end of file +template SPDLOG_API spdlog::logger::logger(std::string name, sinks_init_list::iterator begin, sinks_init_list::iterator end); +template class SPDLOG_API spdlog::sinks::base_sink; +template class SPDLOG_API spdlog::sinks::base_sink; \ No newline at end of file diff --git a/third_party/spdlog/src/stdout_sinks.cpp b/third_party/spdlog/src/stdout_sinks.cpp index 36d6699e..9e86e061 100644 --- a/third_party/spdlog/src/stdout_sinks.cpp +++ b/third_party/spdlog/src/stdout_sinks.cpp @@ -7,23 +7,23 @@ #include -#include "spdlog/details/null_mutex.h" -#include "spdlog/async.h" -#include "spdlog/sinks/stdout_sinks-inl.h" +#include +#include +#include -template class spdlog::sinks::stdout_sink_base; -template class spdlog::sinks::stdout_sink_base; -template class spdlog::sinks::stdout_sink; -template class spdlog::sinks::stdout_sink; -template class spdlog::sinks::stderr_sink; -template class spdlog::sinks::stderr_sink; +template class SPDLOG_API spdlog::sinks::stdout_sink_base; +template class SPDLOG_API spdlog::sinks::stdout_sink_base; +template class SPDLOG_API spdlog::sinks::stdout_sink; +template class SPDLOG_API spdlog::sinks::stdout_sink; +template class SPDLOG_API spdlog::sinks::stderr_sink; +template class SPDLOG_API spdlog::sinks::stderr_sink; -template std::shared_ptr spdlog::stdout_logger_mt(const std::string &logger_name); -template std::shared_ptr spdlog::stdout_logger_st(const std::string &logger_name); -template std::shared_ptr spdlog::stderr_logger_mt(const std::string &logger_name); -template std::shared_ptr spdlog::stderr_logger_st(const std::string &logger_name); +template SPDLOG_API std::shared_ptr spdlog::stdout_logger_mt(const std::string &logger_name); +template SPDLOG_API std::shared_ptr spdlog::stdout_logger_st(const std::string &logger_name); +template SPDLOG_API std::shared_ptr spdlog::stderr_logger_mt(const std::string &logger_name); +template SPDLOG_API std::shared_ptr spdlog::stderr_logger_st(const std::string &logger_name); -template std::shared_ptr spdlog::stdout_logger_mt(const std::string &logger_name); -template std::shared_ptr spdlog::stdout_logger_st(const std::string &logger_name); -template std::shared_ptr spdlog::stderr_logger_mt(const std::string &logger_name); -template std::shared_ptr spdlog::stderr_logger_st(const std::string &logger_name); \ No newline at end of file +template SPDLOG_API std::shared_ptr spdlog::stdout_logger_mt(const std::string &logger_name); +template SPDLOG_API std::shared_ptr spdlog::stdout_logger_st(const std::string &logger_name); +template SPDLOG_API std::shared_ptr spdlog::stderr_logger_mt(const std::string &logger_name); +template SPDLOG_API std::shared_ptr spdlog::stderr_logger_st(const std::string &logger_name); \ No newline at end of file diff --git a/third_party/spdlog/tests/CMakeLists.txt b/third_party/spdlog/tests/CMakeLists.txt index 3184e9b6..1964ae25 100644 --- a/third_party/spdlog/tests/CMakeLists.txt +++ b/third_party/spdlog/tests/CMakeLists.txt @@ -1,5 +1,12 @@ +cmake_minimum_required(VERSION 3.2) + project(spdlog_utests CXX) +if(NOT TARGET spdlog) + # Stand-alone build + find_package(spdlog REQUIRED) +endif() + include(../cmake/utils.cmake) find_package(PkgConfig) @@ -12,6 +19,7 @@ set(SPDLOG_UTESTS_SOURCES test_file_logging.cpp test_daily_logger.cpp test_misc.cpp + test_eventlog.cpp test_pattern_formatter.cpp test_async.cpp test_registry.cpp @@ -23,7 +31,8 @@ set(SPDLOG_UTESTS_SOURCES test_fmt_helper.cpp test_stdout_api.cpp test_backtrace.cpp - test_create_dir.cpp) + test_create_dir.cpp + test_cfg.cpp) if(NOT SPDLOG_NO_EXCEPTIONS) list(APPEND SPDLOG_UTESTS_SOURCES test_errors.cpp) @@ -47,6 +56,7 @@ function(spdlog_prepare_test test_target spdlog_lib) spdlog_enable_sanitizer(${test_target}) endif() add_test(NAME ${test_target} COMMAND ${test_target}) + set_tests_properties(${test_target} PROPERTIES RUN_SERIAL ON) endfunction() # The compiled library tests diff --git a/third_party/spdlog/tests/includes.h b/third_party/spdlog/tests/includes.h index 2fd30370..7285873a 100644 --- a/third_party/spdlog/tests/includes.h +++ b/third_party/spdlog/tests/includes.h @@ -11,6 +11,7 @@ #include #include #include +#include #define SPDLOG_ACTIVE_LEVEL SPDLOG_LEVEL_DEBUG @@ -22,4 +23,4 @@ #include "spdlog/sinks/ostream_sink.h" #include "spdlog/sinks/rotating_file_sink.h" #include "spdlog/sinks/stdout_color_sinks.h" -#include "spdlog/details/pattern_formatter.h" \ No newline at end of file +#include "spdlog/pattern_formatter.h" \ No newline at end of file diff --git a/third_party/spdlog/tests/meson.build b/third_party/spdlog/tests/meson.build index 24feb0a6..d59e702c 100644 --- a/third_party/spdlog/tests/meson.build +++ b/third_party/spdlog/tests/meson.build @@ -14,7 +14,8 @@ test_sources = files([ 'test_fmt_helper.cpp', 'test_stdout_api.cpp', 'test_backtrace.cpp', - 'test_create_dir.cpp' + 'test_create_dir.cpp', + 'test_cfg.cpp', ]) if not get_option('no_exceptions') diff --git a/third_party/spdlog/tests/test_async.cpp b/third_party/spdlog/tests/test_async.cpp index 166ac21e..92b9587d 100644 --- a/third_party/spdlog/tests/test_async.cpp +++ b/third_party/spdlog/tests/test_async.cpp @@ -5,14 +5,13 @@ TEST_CASE("basic async test ", "[async]") { - using namespace spdlog; - auto test_sink = std::make_shared(); + auto test_sink = std::make_shared(); size_t overrun_counter = 0; size_t queue_size = 128; size_t messages = 256; { - auto tp = std::make_shared(queue_size, 1); - auto logger = std::make_shared("as", test_sink, tp, async_overflow_policy::block); + auto tp = std::make_shared(queue_size, 1); + auto logger = std::make_shared("as", test_sink, tp, spdlog::async_overflow_policy::block); for (size_t i = 0; i < messages; i++) { logger->info("Hello message #{}", i); @@ -27,14 +26,13 @@ TEST_CASE("basic async test ", "[async]") TEST_CASE("discard policy ", "[async]") { - using namespace spdlog; - auto test_sink = std::make_shared(); + auto test_sink = std::make_shared(); test_sink->set_delay(std::chrono::milliseconds(1)); size_t queue_size = 4; size_t messages = 1024; - auto tp = std::make_shared(queue_size, 1); - auto logger = std::make_shared("as", test_sink, tp, async_overflow_policy::overrun_oldest); + auto tp = std::make_shared(queue_size, 1); + auto logger = std::make_shared("as", test_sink, tp, spdlog::async_overflow_policy::overrun_oldest); for (size_t i = 0; i < messages; i++) { logger->info("Hello message"); @@ -45,13 +43,12 @@ TEST_CASE("discard policy ", "[async]") TEST_CASE("discard policy using factory ", "[async]") { - using namespace spdlog; size_t queue_size = 4; size_t messages = 1024; spdlog::init_thread_pool(queue_size, 1); - auto logger = spdlog::create_async_nb("as2"); - auto test_sink = std::static_pointer_cast(logger->sinks()[0]); + auto logger = spdlog::create_async_nb("as2"); + auto test_sink = std::static_pointer_cast(logger->sinks()[0]); test_sink->set_delay(std::chrono::milliseconds(1)); for (size_t i = 0; i < messages; i++) @@ -65,13 +62,12 @@ TEST_CASE("discard policy using factory ", "[async]") TEST_CASE("flush", "[async]") { - using namespace spdlog; - auto test_sink = std::make_shared(); + auto test_sink = std::make_shared(); size_t queue_size = 256; size_t messages = 256; { - auto tp = std::make_shared(queue_size, 1); - auto logger = std::make_shared("as", test_sink, tp, async_overflow_policy::block); + auto tp = std::make_shared(queue_size, 1); + auto logger = std::make_shared("as", test_sink, tp, spdlog::async_overflow_policy::block); for (size_t i = 0; i < messages; i++) { logger->info("Hello message #{}", i); @@ -86,11 +82,9 @@ TEST_CASE("flush", "[async]") TEST_CASE("async periodic flush", "[async]") { - using namespace spdlog; - auto logger = spdlog::create_async("as"); - - auto test_sink = std::static_pointer_cast(logger->sinks()[0]); + auto logger = spdlog::create_async("as"); + auto test_sink = std::static_pointer_cast(logger->sinks()[0]); spdlog::flush_every(std::chrono::seconds(1)); std::this_thread::sleep_for(std::chrono::milliseconds(1100)); @@ -101,13 +95,12 @@ TEST_CASE("async periodic flush", "[async]") TEST_CASE("tp->wait_empty() ", "[async]") { - using namespace spdlog; - auto test_sink = std::make_shared(); + auto test_sink = std::make_shared(); test_sink->set_delay(std::chrono::milliseconds(5)); size_t messages = 100; - auto tp = std::make_shared(messages, 2); - auto logger = std::make_shared("as", test_sink, tp, async_overflow_policy::block); + auto tp = std::make_shared(messages, 2); + auto logger = std::make_shared("as", test_sink, tp, spdlog::async_overflow_policy::block); for (size_t i = 0; i < messages; i++) { logger->info("Hello message #{}", i); @@ -121,14 +114,13 @@ TEST_CASE("tp->wait_empty() ", "[async]") TEST_CASE("multi threads", "[async]") { - using namespace spdlog; - auto test_sink = std::make_shared(); + auto test_sink = std::make_shared(); size_t queue_size = 128; size_t messages = 256; size_t n_threads = 10; { - auto tp = std::make_shared(queue_size, 1); - auto logger = std::make_shared("as", test_sink, tp, async_overflow_policy::block); + auto tp = std::make_shared(queue_size, 1); + auto logger = std::make_shared("as", test_sink, tp, spdlog::async_overflow_policy::block); std::vector threads; for (size_t i = 0; i < n_threads; i++) @@ -169,9 +161,10 @@ TEST_CASE("to_file", "[async]") } } - REQUIRE(count_lines(filename) == messages); + require_message_count(filename, messages); auto contents = file_contents(filename); - REQUIRE(ends_with(contents, std::string("Hello message #1023\n"))); + using spdlog::details::os::default_eol; + REQUIRE(ends_with(contents, fmt::format("Hello message #1023{}", default_eol))); } TEST_CASE("to_file multi-workers", "[async]") @@ -191,5 +184,5 @@ TEST_CASE("to_file multi-workers", "[async]") } } - REQUIRE(count_lines(filename) == messages); + require_message_count(filename, messages); } diff --git a/third_party/spdlog/tests/test_cfg.cpp b/third_party/spdlog/tests/test_cfg.cpp new file mode 100644 index 00000000..436036d3 --- /dev/null +++ b/third_party/spdlog/tests/test_cfg.cpp @@ -0,0 +1,93 @@ +#include "includes.h" +#include "test_sink.h" + +#include +#include + +using spdlog::cfg::load_argv_levels; +using spdlog::cfg::load_env_levels; +using spdlog::sinks::test_sink_st; + +TEST_CASE("env", "[cfg]") +{ + spdlog::drop("l1"); + auto l1 = spdlog::create("l1"); +#ifdef CATCH_PLATFORM_WINDOWS + _putenv_s("SPDLOG_LEVEL", "l1=warn"); +#else + setenv("SPDLOG_LEVEL", "l1=warn", 1); +#endif + load_env_levels(); + REQUIRE(l1->level() == spdlog::level::warn); + spdlog::set_default_logger(spdlog::create("cfg-default")); + REQUIRE(spdlog::default_logger()->level() == spdlog::level::info); +} + +TEST_CASE("argv1", "[cfg]") +{ + spdlog::drop("l1"); + const char *argv[] = {"ignore", "SPDLOG_LEVEL=l1=warn"}; + load_argv_levels(2, argv); + auto l1 = spdlog::create("l1"); + REQUIRE(l1->level() == spdlog::level::warn); + REQUIRE(spdlog::default_logger()->level() == spdlog::level::info); +} + +TEST_CASE("argv2", "[cfg]") +{ + spdlog::drop("l1"); + const char *argv[] = {"ignore", "SPDLOG_LEVEL=l1=warn,trace"}; + load_argv_levels(2, argv); + auto l1 = spdlog::create("l1"); + REQUIRE(l1->level() == spdlog::level::warn); + REQUIRE(spdlog::default_logger()->level() == spdlog::level::trace); + spdlog::set_level(spdlog::level::info); +} + +TEST_CASE("argv3", "[cfg]") +{ + spdlog::drop("l1"); + const char *argv[] = {"ignore", "SPDLOG_LEVEL="}; + load_argv_levels(2, argv); + auto l1 = spdlog::create("l1"); + REQUIRE(l1->level() == spdlog::level::info); + REQUIRE(spdlog::default_logger()->level() == spdlog::level::info); +} + +TEST_CASE("argv4", "[cfg]") +{ + spdlog::drop("l1"); + const char *argv[] = {"ignore", "SPDLOG_LEVEL=junk"}; + load_argv_levels(2, argv); + auto l1 = spdlog::create("l1"); + REQUIRE(l1->level() == spdlog::level::info); +} + +TEST_CASE("argv5", "[cfg]") +{ + spdlog::drop("l1"); + const char *argv[] = {"ignore", "ignore", "SPDLOG_LEVEL=l1=warn,trace"}; + load_argv_levels(3, argv); + auto l1 = spdlog::create("l1"); + REQUIRE(l1->level() == spdlog::level::warn); + REQUIRE(spdlog::default_logger()->level() == spdlog::level::trace); + spdlog::set_level(spdlog::level::info); +} + +TEST_CASE("argv6", "[cfg]") +{ + spdlog::set_level(spdlog::level::err); + const char *argv[] = {""}; + load_argv_levels(1, argv); + REQUIRE(spdlog::default_logger()->level() == spdlog::level::err); + spdlog::set_level(spdlog::level::info); +} + +TEST_CASE("argv7", "[cfg]") +{ + spdlog::set_level(spdlog::level::err); + const char *argv[] = {""}; + load_argv_levels(0, argv); + REQUIRE(spdlog::default_logger()->level() == spdlog::level::err); + spdlog::set_level(spdlog::level::info); +} diff --git a/third_party/spdlog/tests/test_daily_logger.cpp b/third_party/spdlog/tests/test_daily_logger.cpp index cf2002a3..a3e70e68 100644 --- a/third_party/spdlog/tests/test_daily_logger.cpp +++ b/third_party/spdlog/tests/test_daily_logger.cpp @@ -24,7 +24,7 @@ TEST_CASE("daily_logger with dateonly calculator", "[daily_logger]") logger->flush(); auto filename = fmt::to_string(w); - REQUIRE(count_lines(filename) == 10); + require_message_count(filename, 10); } struct custom_daily_file_name_calculator @@ -55,12 +55,10 @@ TEST_CASE("daily_logger with custom calculator", "[daily_logger]") logger->info("Test message {}", i); } - logger-> - - flush(); + logger->flush(); auto filename = fmt::to_string(w); - REQUIRE(count_lines(filename) == 10); + require_message_count(filename, 10); } /* @@ -115,7 +113,6 @@ static void test_rotate(int days_to_run, uint16_t max_days, uint16_t expected_n_ using spdlog::log_clock; using spdlog::details::log_msg; using spdlog::sinks::daily_file_sink_st; - using namespace spdlog::details; prepare_logdir(); diff --git a/third_party/spdlog/tests/test_dup_filter.cpp b/third_party/spdlog/tests/test_dup_filter.cpp index 47541e0f..795278a0 100644 --- a/third_party/spdlog/tests/test_dup_filter.cpp +++ b/third_party/spdlog/tests/test_dup_filter.cpp @@ -2,11 +2,11 @@ #include "spdlog/sinks/dup_filter_sink.h" #include "test_sink.h" -using namespace spdlog; -using namespace spdlog::sinks; - TEST_CASE("dup_filter_test1", "[dup_filter_sink]") { + using spdlog::sinks::dup_filter_sink_st; + using spdlog::sinks::test_sink_mt; + dup_filter_sink_st dup_sink{std::chrono::seconds{5}}; auto test_sink = std::make_shared(); dup_sink.add_sink(test_sink); @@ -21,6 +21,9 @@ TEST_CASE("dup_filter_test1", "[dup_filter_sink]") TEST_CASE("dup_filter_test2", "[dup_filter_sink]") { + using spdlog::sinks::dup_filter_sink_st; + using spdlog::sinks::test_sink_mt; + dup_filter_sink_st dup_sink{std::chrono::seconds{0}}; auto test_sink = std::make_shared(); dup_sink.add_sink(test_sink); @@ -36,6 +39,9 @@ TEST_CASE("dup_filter_test2", "[dup_filter_sink]") TEST_CASE("dup_filter_test3", "[dup_filter_sink]") { + using spdlog::sinks::dup_filter_sink_st; + using spdlog::sinks::test_sink_mt; + dup_filter_sink_st dup_sink{std::chrono::seconds{1}}; auto test_sink = std::make_shared(); dup_sink.add_sink(test_sink); @@ -51,6 +57,9 @@ TEST_CASE("dup_filter_test3", "[dup_filter_sink]") TEST_CASE("dup_filter_test4", "[dup_filter_sink]") { + using spdlog::sinks::dup_filter_sink_mt; + using spdlog::sinks::test_sink_mt; + dup_filter_sink_mt dup_sink{std::chrono::milliseconds{10}}; auto test_sink = std::make_shared(); dup_sink.add_sink(test_sink); @@ -63,6 +72,9 @@ TEST_CASE("dup_filter_test4", "[dup_filter_sink]") TEST_CASE("dup_filter_test5", "[dup_filter_sink]") { + using spdlog::sinks::dup_filter_sink_mt; + using spdlog::sinks::test_sink_mt; + dup_filter_sink_mt dup_sink{std::chrono::seconds{5}}; auto test_sink = std::make_shared(); dup_sink.add_sink(test_sink); diff --git a/third_party/spdlog/tests/test_errors.cpp b/third_party/spdlog/tests/test_errors.cpp index 4fc40594..d6db535e 100644 --- a/third_party/spdlog/tests/test_errors.cpp +++ b/third_party/spdlog/tests/test_errors.cpp @@ -7,10 +7,6 @@ class failing_sink : public spdlog::sinks::base_sink { -public: - failing_sink() = default; - ~failing_sink() final = default; - protected: void sink_it_(const spdlog::details::log_msg &) final { @@ -34,7 +30,8 @@ TEST_CASE("default_error_handler", "[errors]]") logger->info("Test message {}", 2); logger->flush(); - REQUIRE(file_contents(filename) == std::string("Test message 2\n")); + using spdlog::details::os::default_eol; + REQUIRE(file_contents(filename) == fmt::format("Test message 2{}", default_eol)); REQUIRE(count_lines(filename) == 1); } @@ -51,7 +48,7 @@ TEST_CASE("custom_error_handler", "[errors]]") REQUIRE_THROWS_AS(logger->info("Bad format msg {} {}", "xxx"), custom_ex); logger->info("Good message #2"); - REQUIRE(count_lines(filename) == 2); + require_message_count(filename, 2); } TEST_CASE("default_error_handler2", "[errors]]") @@ -93,7 +90,7 @@ TEST_CASE("async_error_handler", "[errors]]") spdlog::drop("logger"); // force logger to drain the queue and shutdown } spdlog::init_thread_pool(128, 1); - REQUIRE(count_lines(filename) == 2); + require_message_count(filename, 2); REQUIRE(file_contents("test_logs/custom_err.txt") == err_msg); } diff --git a/third_party/spdlog/tests/test_eventlog.cpp b/third_party/spdlog/tests/test_eventlog.cpp new file mode 100644 index 00000000..ea6b7942 --- /dev/null +++ b/third_party/spdlog/tests/test_eventlog.cpp @@ -0,0 +1,71 @@ +#if _WIN32 + +#include "includes.h" +#include "test_sink.h" + +#include "spdlog/sinks/win_eventlog_sink.h" + +static const LPCSTR TEST_SOURCE = "spdlog_test"; + +static void test_single_print(std::function do_log, std::string const &expected_contents, WORD expected_ev_type) +{ + using namespace std::chrono; + do_log(expected_contents); + const auto expected_time_generated = duration_cast(system_clock::now().time_since_epoch()).count(); + + struct handle_t + { + HANDLE handle_; + + ~handle_t() + { + if (handle_) + { + REQUIRE(CloseEventLog(handle_)); + } + } + } event_log{::OpenEventLog(nullptr, TEST_SOURCE)}; + + REQUIRE(event_log.handle_); + + DWORD read_bytes{}, size_needed{}; + auto ok = + ::ReadEventLog(event_log.handle_, EVENTLOG_SEQUENTIAL_READ | EVENTLOG_BACKWARDS_READ, 0, &read_bytes, 0, &read_bytes, &size_needed); + REQUIRE(!ok); + REQUIRE(::GetLastError() == ERROR_INSUFFICIENT_BUFFER); + + std::vector record_buffer(size_needed); + PEVENTLOGRECORD record = (PEVENTLOGRECORD)record_buffer.data(); + + ok = ::ReadEventLog( + event_log.handle_, EVENTLOG_SEQUENTIAL_READ | EVENTLOG_BACKWARDS_READ, 0, record, size_needed, &read_bytes, &size_needed); + REQUIRE(ok); + + REQUIRE(record->NumStrings == 1); + REQUIRE(record->EventType == expected_ev_type); + REQUIRE((expected_time_generated - record->TimeGenerated) <= 3u); + + std::string message_in_log(((char *)record + record->StringOffset)); + REQUIRE(message_in_log == expected_contents + spdlog::details::os::default_eol); +} + +TEST_CASE("eventlog", "[eventlog]") +{ + using namespace spdlog; + + auto test_sink = std::make_shared(TEST_SOURCE); + + spdlog::logger test_logger("eventlog", test_sink); + test_logger.set_level(level::trace); + + test_sink->set_pattern("%v"); + + test_single_print([&test_logger](std::string const &msg) { test_logger.trace(msg); }, "my trace message", EVENTLOG_SUCCESS); + test_single_print([&test_logger](std::string const &msg) { test_logger.debug(msg); }, "my debug message", EVENTLOG_SUCCESS); + test_single_print([&test_logger](std::string const &msg) { test_logger.info(msg); }, "my info message", EVENTLOG_INFORMATION_TYPE); + test_single_print([&test_logger](std::string const &msg) { test_logger.warn(msg); }, "my warn message", EVENTLOG_WARNING_TYPE); + test_single_print([&test_logger](std::string const &msg) { test_logger.error(msg); }, "my error message", EVENTLOG_ERROR_TYPE); + test_single_print([&test_logger](std::string const &msg) { test_logger.critical(msg); }, "my critical message", EVENTLOG_ERROR_TYPE); +} + +#endif //_WIN32 diff --git a/third_party/spdlog/tests/test_file_helper.cpp b/third_party/spdlog/tests/test_file_helper.cpp index 3a3545fe..061f125f 100644 --- a/third_party/spdlog/tests/test_file_helper.cpp +++ b/third_party/spdlog/tests/test_file_helper.cpp @@ -4,9 +4,6 @@ #include "includes.h" using spdlog::details::file_helper; -using spdlog::details::log_msg; - -static const std::string target_filename = "test_logs/file_helper_test.txt"; static void write_with_helper(file_helper &helper, size_t howmany) { @@ -21,6 +18,7 @@ TEST_CASE("file_helper_filename", "[file_helper::filename()]]") prepare_logdir(); file_helper helper; + std::string target_filename = "test_logs/file_helper_test.txt"; helper.open(target_filename); REQUIRE(helper.filename() == target_filename); } @@ -28,6 +26,7 @@ TEST_CASE("file_helper_filename", "[file_helper::filename()]]") TEST_CASE("file_helper_size", "[file_helper::size()]]") { prepare_logdir(); + std::string target_filename = "test_logs/file_helper_test.txt"; size_t expected_size = 123; { file_helper helper; @@ -41,6 +40,7 @@ TEST_CASE("file_helper_size", "[file_helper::size()]]") TEST_CASE("file_helper_reopen", "[file_helper::reopen()]]") { prepare_logdir(); + std::string target_filename = "test_logs/file_helper_test.txt"; file_helper helper; helper.open(target_filename); write_with_helper(helper, 12); @@ -52,6 +52,7 @@ TEST_CASE("file_helper_reopen", "[file_helper::reopen()]]") TEST_CASE("file_helper_reopen2", "[file_helper::reopen(false)]]") { prepare_logdir(); + std::string target_filename = "test_logs/file_helper_test.txt"; size_t expected_size = 14; file_helper helper; helper.open(target_filename); @@ -71,7 +72,8 @@ static void test_split_ext(const char *fname, const char *expect_base, const cha std::replace(filename.begin(), filename.end(), '/', '\\'); std::replace(expected_base.begin(), expected_base.end(), '/', '\\'); #endif - spdlog::filename_t basename, ext; + spdlog::filename_t basename; + spdlog::filename_t ext; std::tie(basename, ext) = file_helper::split_by_extension(filename); REQUIRE(basename == expected_base); REQUIRE(ext == expected_ext); diff --git a/third_party/spdlog/tests/test_file_logging.cpp b/third_party/spdlog/tests/test_file_logging.cpp index a8f9b2bb..394b4bb2 100644 --- a/third_party/spdlog/tests/test_file_logging.cpp +++ b/third_party/spdlog/tests/test_file_logging.cpp @@ -15,8 +15,9 @@ TEST_CASE("simple_file_logger", "[simple_logger]]") logger->info("Test message {}", 2); logger->flush(); - REQUIRE(file_contents(filename) == std::string("Test message 1\nTest message 2\n")); - REQUIRE(count_lines(filename) == 2); + require_message_count(filename, 2); + using spdlog::details::os::default_eol; + REQUIRE(file_contents(filename) == fmt::format("Test message 1{}Test message 2{}", default_eol, default_eol)); } TEST_CASE("flush_on", "[flush_on]]") @@ -34,8 +35,10 @@ TEST_CASE("flush_on", "[flush_on]]") logger->info("Test message {}", 1); logger->info("Test message {}", 2); - REQUIRE(file_contents(filename) == std::string("Should not be flushed\nTest message 1\nTest message 2\n")); - REQUIRE(count_lines(filename) == 3); + require_message_count(filename, 3); + using spdlog::details::os::default_eol; + REQUIRE(file_contents(filename) == + fmt::format("Should not be flushed{}Test message 1{}Test message 2{}", default_eol, default_eol, default_eol)); } TEST_CASE("rotating_file_logger1", "[rotating_logger]]") @@ -51,8 +54,7 @@ TEST_CASE("rotating_file_logger1", "[rotating_logger]]") } logger->flush(); - auto filename = basename; - REQUIRE(count_lines(filename) == 10); + require_message_count(basename, 10); } TEST_CASE("rotating_file_logger2", "[rotating_logger]]") @@ -80,8 +82,9 @@ TEST_CASE("rotating_file_logger2", "[rotating_logger]]") } logger->flush(); - auto filename = basename; - REQUIRE(count_lines(filename) == 10); + + require_message_count(basename, 10); + for (int i = 0; i < 1000; i++) { @@ -89,7 +92,7 @@ TEST_CASE("rotating_file_logger2", "[rotating_logger]]") } logger->flush(); - REQUIRE(get_filesize(filename) <= max_size); + REQUIRE(get_filesize(basename) <= max_size); auto filename1 = basename + ".1"; REQUIRE(get_filesize(filename1) <= max_size); } diff --git a/third_party/spdlog/tests/test_fmt_helper.cpp b/third_party/spdlog/tests/test_fmt_helper.cpp index 0e10f4de..3ef18abe 100644 --- a/third_party/spdlog/tests/test_fmt_helper.cpp +++ b/third_party/spdlog/tests/test_fmt_helper.cpp @@ -36,7 +36,10 @@ TEST_CASE("pad2", "[fmt_helper]") { test_pad2(0, "00"); test_pad2(3, "03"); + test_pad2(10, "10"); test_pad2(23, "23"); + test_pad2(99, "99"); + test_pad2(100, "100"); test_pad2(123, "123"); test_pad2(1234, "1234"); test_pad2(-5, "-5"); @@ -46,8 +49,13 @@ TEST_CASE("pad3", "[fmt_helper]") { test_pad3(0, "000"); test_pad3(3, "003"); + test_pad3(10, "010"); test_pad3(23, "023"); + test_pad3(99, "099"); + test_pad3(100, "100"); test_pad3(123, "123"); + test_pad3(999, "999"); + test_pad3(1000, "1000"); test_pad3(1234, "1234"); } diff --git a/third_party/spdlog/tests/test_macros.cpp b/third_party/spdlog/tests/test_macros.cpp index 4c621bb3..37f5c892 100644 --- a/third_party/spdlog/tests/test_macros.cpp +++ b/third_party/spdlog/tests/test_macros.cpp @@ -22,7 +22,8 @@ TEST_CASE("debug and trace w/o format string", "[macros]]") SPDLOG_LOGGER_DEBUG(logger, "Test message 2"); logger->flush(); - REQUIRE(ends_with(file_contents(filename), "Test message 2\n")); + using spdlog::details::os::default_eol; + REQUIRE(ends_with(file_contents(filename), fmt::format("Test message 2{}", default_eol))); REQUIRE(count_lines(filename) == 1); spdlog::set_default_logger(logger); @@ -31,8 +32,8 @@ TEST_CASE("debug and trace w/o format string", "[macros]]") SPDLOG_DEBUG("Test message {}", 4); logger->flush(); - REQUIRE(ends_with(file_contents(filename), "Test message 4\n")); - REQUIRE(count_lines(filename) == 2); + require_message_count(filename, 2); + REQUIRE(ends_with(file_contents(filename), fmt::format("Test message 4{}", default_eol))); } TEST_CASE("disable param evaluation", "[macros]") diff --git a/third_party/spdlog/tests/test_misc.cpp b/third_party/spdlog/tests/test_misc.cpp index 576005a4..1d67e879 100644 --- a/third_party/spdlog/tests/test_misc.cpp +++ b/third_party/spdlog/tests/test_misc.cpp @@ -21,11 +21,11 @@ TEST_CASE("basic_logging ", "[basic_logging]") { // const char REQUIRE(log_info("Hello") == "Hello"); - REQUIRE(log_info("") == ""); + REQUIRE(log_info("").empty()); // std::string REQUIRE(log_info(std::string("Hello")) == "Hello"); - REQUIRE(log_info(std::string()) == std::string()); + REQUIRE(log_info(std::string()).empty()); // Numbers REQUIRE(log_info(5) == "5"); @@ -37,8 +37,8 @@ TEST_CASE("basic_logging ", "[basic_logging]") TEST_CASE("log_levels", "[log_levels]") { - REQUIRE(log_info("Hello", spdlog::level::err) == ""); - REQUIRE(log_info("Hello", spdlog::level::critical) == ""); + REQUIRE(log_info("Hello", spdlog::level::err).empty()); + REQUIRE(log_info("Hello", spdlog::level::critical).empty()); REQUIRE(log_info("Hello", spdlog::level::info) == "Hello"); REQUIRE(log_info("Hello", spdlog::level::debug) == "Hello"); REQUIRE(log_info("Hello", spdlog::level::trace) == "Hello"); @@ -72,6 +72,7 @@ TEST_CASE("to_level_enum", "[convert_to_level_enum]") REQUIRE(spdlog::level::from_str("debug") == spdlog::level::debug); REQUIRE(spdlog::level::from_str("info") == spdlog::level::info); REQUIRE(spdlog::level::from_str("warning") == spdlog::level::warn); + REQUIRE(spdlog::level::from_str("warn") == spdlog::level::warn); REQUIRE(spdlog::level::from_str("error") == spdlog::level::err); REQUIRE(spdlog::level::from_str("critical") == spdlog::level::critical); REQUIRE(spdlog::level::from_str("off") == spdlog::level::off); @@ -80,11 +81,9 @@ TEST_CASE("to_level_enum", "[convert_to_level_enum]") TEST_CASE("periodic flush", "[periodic_flush]") { - using namespace spdlog; - - auto logger = spdlog::create("periodic_flush"); - - auto test_sink = std::static_pointer_cast(logger->sinks()[0]); + using spdlog::sinks::test_sink_mt; + auto logger = spdlog::create("periodic_flush"); + auto test_sink = std::static_pointer_cast(logger->sinks()[0]); spdlog::flush_every(std::chrono::seconds(1)); std::this_thread::sleep_for(std::chrono::milliseconds(1250)); @@ -95,8 +94,8 @@ TEST_CASE("periodic flush", "[periodic_flush]") TEST_CASE("clone-logger", "[clone]") { - using namespace spdlog; - auto test_sink = std::make_shared(); + using spdlog::sinks::test_sink_mt; + auto test_sink = std::make_shared(); auto logger = std::make_shared("orig", test_sink); logger->set_pattern("%v"); auto cloned = logger->clone("clone"); @@ -117,10 +116,9 @@ TEST_CASE("clone-logger", "[clone]") TEST_CASE("clone async", "[clone]") { - using namespace spdlog; - + using spdlog::sinks::test_sink_st; spdlog::init_thread_pool(4, 1); - auto test_sink = std::make_shared(); + auto test_sink = std::make_shared(); auto logger = std::make_shared("orig", test_sink, spdlog::thread_pool()); logger->set_pattern("%v"); auto cloned = logger->clone("clone"); @@ -181,6 +179,57 @@ TEST_CASE("to_hex_no_delimiter", "[to_hex]") REQUIRE(ends_with(output, "0000: 090A0B0CFFFF" + std::string(spdlog::details::os::default_eol))); } +TEST_CASE("to_hex_show_ascii", "[to_hex]") +{ + std::ostringstream oss; + auto oss_sink = std::make_shared(oss); + spdlog::logger oss_logger("oss", oss_sink); + + std::vector v{9, 0xa, 0xb, 0x41, 0xc, 0x4b, 0xff, 0xff}; + oss_logger.info("{:Xsa}", spdlog::to_hex(v, 8)); + + REQUIRE(ends_with(oss.str(), "0000: 090A0B410C4BFFFF ...A.K.." + std::string(spdlog::details::os::default_eol))); +} + +TEST_CASE("to_hex_different_size_per_line", "[to_hex]") +{ + std::ostringstream oss; + auto oss_sink = std::make_shared(oss); + spdlog::logger oss_logger("oss", oss_sink); + + std::vector v{9, 0xa, 0xb, 0x41, 0xc, 0x4b, 0xff, 0xff}; + + oss_logger.info("{:Xsa}", spdlog::to_hex(v, 10)); + REQUIRE(ends_with(oss.str(), "0000: 090A0B410C4BFFFF ...A.K.." + std::string(spdlog::details::os::default_eol))); + + oss_logger.info("{:Xs}", spdlog::to_hex(v, 10)); + REQUIRE(ends_with(oss.str(), "0000: 090A0B410C4BFFFF" + std::string(spdlog::details::os::default_eol))); + + oss_logger.info("{:Xsa}", spdlog::to_hex(v, 6)); + REQUIRE(ends_with(oss.str(), "0000: 090A0B410C4B ...A.K" + std::string(spdlog::details::os::default_eol) + "0006: FFFF .." + + std::string(spdlog::details::os::default_eol))); + + oss_logger.info("{:Xs}", spdlog::to_hex(v, 6)); + REQUIRE(ends_with(oss.str(), "0000: 090A0B410C4B" + std::string(spdlog::details::os::default_eol) + "0006: FFFF" + + std::string(spdlog::details::os::default_eol))); +} + +TEST_CASE("to_hex_no_ascii", "[to_hex]") +{ + std::ostringstream oss; + auto oss_sink = std::make_shared(oss); + spdlog::logger oss_logger("oss", oss_sink); + + std::vector v{9, 0xa, 0xb, 0x41, 0xc, 0x4b, 0xff, 0xff}; + oss_logger.info("{:Xs}", spdlog::to_hex(v, 8)); + + REQUIRE(ends_with(oss.str(), "0000: 090A0B410C4BFFFF" + std::string(spdlog::details::os::default_eol))); + + oss_logger.info("{:Xsna}", spdlog::to_hex(v, 8)); + + REQUIRE(ends_with(oss.str(), "090A0B410C4BFFFF" + std::string(spdlog::details::os::default_eol))); +} + TEST_CASE("default logger API", "[default logger]") { std::ostringstream oss; diff --git a/third_party/spdlog/tests/test_mpmc_q.cpp b/third_party/spdlog/tests/test_mpmc_q.cpp index 888240fd..5b0e41d9 100644 --- a/third_party/spdlog/tests/test_mpmc_q.cpp +++ b/third_party/spdlog/tests/test_mpmc_q.cpp @@ -1,6 +1,5 @@ #include "includes.h" -using namespace std::chrono; using std::chrono::milliseconds; using test_clock = std::chrono::high_resolution_clock; @@ -13,7 +12,7 @@ TEST_CASE("dequeue-empty-nowait", "[mpmc_blocking_q]") size_t q_size = 100; milliseconds tolerance_wait(10); spdlog::details::mpmc_blocking_queue q(q_size); - int popped_item; + int popped_item = 0; auto start = test_clock::now(); auto rv = q.dequeue_for(popped_item, milliseconds::zero()); @@ -32,7 +31,7 @@ TEST_CASE("dequeue-empty-wait", "[mpmc_blocking_q]") milliseconds tolerance_wait(250); spdlog::details::mpmc_blocking_queue q(q_size); - int popped_item; + int popped_item = 0; auto start = test_clock::now(); auto rv = q.dequeue_for(popped_item, wait_ms); auto delta_ms = millis_from(start); @@ -69,7 +68,7 @@ TEST_CASE("bad_queue", "[mpmc_blocking_q]") spdlog::details::mpmc_blocking_queue q(q_size); q.enqueue_nowait(1); REQUIRE(q.overrun_counter() == 1); - int i; + int i = 0; REQUIRE(q.dequeue_for(i, milliseconds(0)) == false); } @@ -77,7 +76,7 @@ TEST_CASE("empty_queue", "[mpmc_blocking_q]") { size_t q_size = 10; spdlog::details::mpmc_blocking_queue q(q_size); - int i; + int i = 0; REQUIRE(q.dequeue_for(i, milliseconds(10)) == false); } @@ -87,7 +86,7 @@ TEST_CASE("full_queue", "[mpmc_blocking_q]") spdlog::details::mpmc_blocking_queue q(q_size); for (int i = 0; i < static_cast(q_size); i++) { - q.enqueue(std::move(i)); + q.enqueue(i + 0); // i+0 to force rvalue and avoid tidy warnings on the same time if we std::move(i) instead } q.enqueue_nowait(123456); diff --git a/third_party/spdlog/tests/test_pattern_formatter.cpp b/third_party/spdlog/tests/test_pattern_formatter.cpp index d9647f9b..848398fd 100644 --- a/third_party/spdlog/tests/test_pattern_formatter.cpp +++ b/third_party/spdlog/tests/test_pattern_formatter.cpp @@ -27,7 +27,7 @@ TEST_CASE("custom eol", "[pattern_formatter]") TEST_CASE("empty format", "[pattern_formatter]") { - REQUIRE(log_to_str("Some message", "", spdlog::pattern_time_type::local, "") == ""); + REQUIRE(log_to_str("Some message", "", spdlog::pattern_time_type::local, "").empty()); } TEST_CASE("empty format2", "[pattern_formatter]") @@ -305,14 +305,61 @@ TEST_CASE("clone-formatter-2", "[pattern_formatter]") REQUIRE(fmt::to_string(formatted_1) == fmt::to_string(formatted_2)); } +class custom_test_flag : public spdlog::custom_flag_formatter +{ +public: + explicit custom_test_flag(std::string txt) + : some_txt{std::move(txt)} + {} + + void format(const spdlog::details::log_msg &, const std::tm &, spdlog::memory_buf_t &dest) override + { + if (some_txt == "throw_me") + { + throw spdlog::spdlog_ex("custom_flag_exception_test"); + } + some_txt = std::string(padinfo_.width_, ' ') + some_txt; + dest.append(some_txt.data(), some_txt.data() + some_txt.size()); + } + spdlog::details::padding_info get_padding_info() + { + return padinfo_; + } + + std::string some_txt; + + std::unique_ptr clone() const override + { + return spdlog::details::make_unique(some_txt); + } +}; +// test clone with custom flag formatters +TEST_CASE("clone-custom_formatter", "[pattern_formatter]") +{ + auto formatter_1 = std::make_shared(); + formatter_1->add_flag('t', "custom_output").set_pattern("[%n] [%t] %v"); + auto formatter_2 = formatter_1->clone(); + std::string logger_name = "logger-name"; + spdlog::details::log_msg msg(logger_name, spdlog::level::info, "some message"); + + memory_buf_t formatted_1; + memory_buf_t formatted_2; + formatter_1->format(msg, formatted_1); + formatter_2->format(msg, formatted_2); + + auto expected = fmt::format("[logger-name] [custom_output] some message{}", spdlog::details::os::default_eol); + REQUIRE(fmt::to_string(formatted_1) == expected); + REQUIRE(fmt::to_string(formatted_2) == expected); +} + // // Test source location formatting // #ifdef _WIN32 -static const char *test_path = "\\a\\b\\myfile.cpp"; +static const char *const test_path = "\\a\\b\\myfile.cpp"; #else -static const char *test_path = "/a/b//myfile.cpp"; +static const char *const test_path = "/a/b//myfile.cpp"; #endif TEST_CASE("short filename formatter-1", "[pattern_formatter]") @@ -358,3 +405,39 @@ TEST_CASE("full filename formatter", "[pattern_formatter]") formatter.format(msg, formatted); REQUIRE(fmt::to_string(formatted) == test_path); } + +TEST_CASE("custom flags", "[pattern_formatter]") +{ + auto formatter = std::make_shared(); + formatter->add_flag('t', "custom1").add_flag('u', "custom2").set_pattern("[%n] [%t] [%u] %v"); + + memory_buf_t formatted; + + spdlog::details::log_msg msg(spdlog::source_loc{}, "logger-name", spdlog::level::info, "some message"); + formatter->format(msg, formatted); + auto expected = fmt::format("[logger-name] [custom1] [custom2] some message{}", spdlog::details::os::default_eol); + REQUIRE(fmt::to_string(formatted) == expected); +} + +TEST_CASE("custom flags-padding", "[pattern_formatter]") +{ + auto formatter = std::make_shared(); + formatter->add_flag('t', "custom1").add_flag('u', "custom2").set_pattern("[%n] [%t] [%5u] %v"); + + memory_buf_t formatted; + + spdlog::details::log_msg msg(spdlog::source_loc{}, "logger-name", spdlog::level::info, "some message"); + formatter->format(msg, formatted); + auto expected = fmt::format("[logger-name] [custom1] [ custom2] some message{}", spdlog::details::os::default_eol); + REQUIRE(fmt::to_string(formatted) == expected); +} + +TEST_CASE("custom flags-exception", "[pattern_formatter]") +{ + auto formatter = std::make_shared(); + formatter->add_flag('t', "throw_me").add_flag('u', "custom2").set_pattern("[%n] [%t] [%u] %v"); + + memory_buf_t formatted; + spdlog::details::log_msg msg(spdlog::source_loc{}, "logger-name", spdlog::level::info, "some message"); + CHECK_THROWS_AS(formatter->format(msg, formatted), spdlog::spdlog_ex); +} diff --git a/third_party/spdlog/tests/test_registry.cpp b/third_party/spdlog/tests/test_registry.cpp index c1a8a308..cd8bab84 100644 --- a/third_party/spdlog/tests/test_registry.cpp +++ b/third_party/spdlog/tests/test_registry.cpp @@ -1,7 +1,7 @@ #include "includes.h" -static const char *tested_logger_name = "null_logger"; -static const char *tested_logger_name2 = "null_logger2"; +static const char *const tested_logger_name = "null_logger"; +static const char *const tested_logger_name2 = "null_logger2"; #ifndef SPDLOG_NO_EXCEPTIONS TEST_CASE("register_drop", "[registry]") diff --git a/third_party/spdlog/tests/utils.cpp b/third_party/spdlog/tests/utils.cpp index 255a4fec..6b5b9103 100644 --- a/third_party/spdlog/tests/utils.cpp +++ b/third_party/spdlog/tests/utils.cpp @@ -21,7 +21,7 @@ void prepare_logdir() std::string file_contents(const std::string &filename) { - std::ifstream ifs(filename); + std::ifstream ifs(filename, std::ios_base::binary); if (!ifs) { throw std::runtime_error("Failed open file "); @@ -44,6 +44,18 @@ std::size_t count_lines(const std::string &filename) return counter; } +void require_message_count(const std::string &filename, const std::size_t messages) +{ + if (strlen(spdlog::details::os::default_eol) == 0) + { + REQUIRE(count_lines(filename) == 1); + } + else + { + REQUIRE(count_lines(filename) == messages); + } +} + std::size_t get_filesize(const std::string &filename) { std::ifstream ifs(filename, std::ifstream::ate | std::ifstream::binary); @@ -101,7 +113,7 @@ std::size_t count_files(const std::string &folder) throw std::runtime_error("Failed open folder " + folder); } - struct dirent *ep; + struct dirent *ep = nullptr; while ((ep = readdir(dp)) != nullptr) { if (ep->d_name[0] != '.') diff --git a/third_party/spdlog/tests/utils.h b/third_party/spdlog/tests/utils.h index de553a9c..53c09b46 100644 --- a/third_party/spdlog/tests/utils.h +++ b/third_party/spdlog/tests/utils.h @@ -3,8 +3,6 @@ #include #include -std::size_t count_lines(const std::string &filename); - std::size_t count_files(const std::string &folder); void prepare_logdir(); @@ -13,6 +11,8 @@ std::string file_contents(const std::string &filename); std::size_t count_lines(const std::string &filename); +void require_message_count(const std::string &filename, const std::size_t messages); + std::size_t get_filesize(const std::string &filename); bool ends_with(std::string const &value, std::string const &ending); \ No newline at end of file