(third_party deps) fix #177, update bundled spdlog to 1.6.0

This commit is contained in:
Benjamin Sergeant 2020-04-11 13:31:39 -07:00
parent 2eb5c9480e
commit f1c106728b
109 changed files with 2792 additions and 689 deletions

View File

@ -5,7 +5,7 @@ include(FindPackageHandleStandardArgs)
find_path(JSONCPP_INCLUDE_DIRS json/json.h) find_path(JSONCPP_INCLUDE_DIRS json/json.h)
find_library(JSONCPP_LIBRARY jsoncpp) find_library(JSONCPP_LIBRARY jsoncpp)
find_package_handle_standard_args(JSONCPP find_package_handle_standard_args(JsonCpp
FOUND_VAR FOUND_VAR
JSONCPP_FOUND JSONCPP_FOUND
REQUIRED_VARS REQUIRED_VARS

View File

@ -1,6 +1,10 @@
# Changelog # Changelog
All changes to this project will be documented in this file. 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 ## [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. (windows) when using OpenSSL, the system store is used to populate the cacert. No need to ship a cacert.pem file with your app.

View File

@ -6,4 +6,4 @@
#pragma once #pragma once
#define IX_WEBSOCKET_VERSION "9.2.1" #define IX_WEBSOCKET_VERSION "9.2.2"

View File

@ -1,19 +1,32 @@
Checks: '\ Checks: 'cppcoreguidelines-*,
cppcoreguidelines-*,\ performance-*,
performance-*,\ modernize-*,
-performance-unnecessary-value-param,\ google-*,
modernize-*,\ misc-*,
-modernize-use-trailing-return-type,\ cert-*,
google-*,\ readability-*,
-google-runtime-references,\ clang-analyzer-*,
misc-*,\ -performance-unnecessary-value-param,
-misc-non-private-member-variables-in-classes,\ -modernize-use-trailing-return-type,
cert-*,\ -google-runtime-references,
readability-*,\ -misc-non-private-member-variables-in-classes,
clang-analyzer-*' -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: '' 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 AnalyzeTemporaryDtors: false
FormatStyle: none FormatStyle: none

View File

@ -97,6 +97,7 @@ script:
-DCMAKE_CXX_STANDARD=$CPP \ -DCMAKE_CXX_STANDARD=$CPP \
-DSPDLOG_BUILD_EXAMPLE=ON \ -DSPDLOG_BUILD_EXAMPLE=ON \
-DSPDLOG_BUILD_EXAMPLE_HO=ON \ -DSPDLOG_BUILD_EXAMPLE_HO=ON \
-DSPDLOG_ENABLE_WARNINGS=ON \
-DSPDLOG_BUILD_BENCH=OFF \ -DSPDLOG_BUILD_BENCH=OFF \
-DSPDLOG_BUILD_TESTS=ON \ -DSPDLOG_BUILD_TESTS=ON \
-DSPDLOG_BUILD_TESTS_HO=OFf \ -DSPDLOG_BUILD_TESTS_HO=OFf \

View File

@ -3,15 +3,27 @@
cmake_minimum_required(VERSION 3.2) 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 # Start spdlog project
#--------------------------------------------------------------------------------------- #---------------------------------------------------------------------------------------
include(GNUInstallDirs)
include(cmake/utils.cmake) include(cmake/utils.cmake)
include(cmake/ide.cmake) include(cmake/ide.cmake)
spdlog_extract_version() spdlog_extract_version()
project(spdlog VERSION ${SPDLOG_VERSION} LANGUAGES CXX)
message(STATUS "Build spdlog: ${SPDLOG_VERSION}")
include(GNUInstallDirs)
#--------------------------------------------------------------------------------------- #---------------------------------------------------------------------------------------
# Set default build to release # Set default build to release
#--------------------------------------------------------------------------------------- #---------------------------------------------------------------------------------------
@ -19,16 +31,22 @@ if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE "Release" CACHE STRING "Choose Release or Debug" FORCE) set(CMAKE_BUILD_TYPE "Release" CACHE STRING "Choose Release or Debug" FORCE)
endif() endif()
project(spdlog VERSION ${SPDLOG_VERSION} LANGUAGES CXX)
message(STATUS "Build spdlog: ${SPDLOG_VERSION}")
#--------------------------------------------------------------------------------------- #---------------------------------------------------------------------------------------
# Compiler config # Compiler config
#--------------------------------------------------------------------------------------- #---------------------------------------------------------------------------------------
if (NOT CMAKE_CXX_STANDARD)
set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_STANDARD_REQUIRED ON)
endif()
set(CMAKE_CXX_EXTENSIONS OFF) 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 # Set SPDLOG_MASTER_PROJECT to ON if we are building spdlog
#--------------------------------------------------------------------------------------- #---------------------------------------------------------------------------------------
@ -42,16 +60,17 @@ if (NOT DEFINED SPDLOG_MASTER_PROJECT)
endif () endif ()
# build shared option # build shared option
if(NOT WIN32)
option(SPDLOG_BUILD_SHARED "Build shared library" OFF) option(SPDLOG_BUILD_SHARED "Build shared library" OFF)
endif()
# precompiled headers option
option(SPDLOG_ENABLE_PCH "Build static or shared library using precompiled header to speed up compilation time" OFF)
# example options # example options
option(SPDLOG_BUILD_EXAMPLE "Build example" ${SPDLOG_MASTER_PROJECT}) option(SPDLOG_BUILD_EXAMPLE "Build example" ${SPDLOG_MASTER_PROJECT})
option(SPDLOG_BUILD_EXAMPLE_HO "Build header only example" OFF) option(SPDLOG_BUILD_EXAMPLE_HO "Build header only example" OFF)
# testing options # 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) option(SPDLOG_BUILD_TESTS_HO "Build tests using the header only version" OFF)
# bench options # bench options
@ -60,6 +79,9 @@ option(SPDLOG_BUILD_BENCH "Build benchmarks (Requires https://github.com/google/
# sanitizer options # sanitizer options
option(SPDLOG_SANITIZE_ADDRESS "Enable address sanitizer in tests" OFF) option(SPDLOG_SANITIZE_ADDRESS "Enable address sanitizer in tests" OFF)
# warning options
option(SPDLOG_BUILD_WARNINGS "Enable compiler warnings" OFF)
# install options # install options
option(SPDLOG_INSTALL "Generate the install target" ${SPDLOG_MASTER_PROJECT}) option(SPDLOG_INSTALL "Generate the install target" ${SPDLOG_MASTER_PROJECT})
option(SPDLOG_FMT_EXTERNAL "Use external fmt library instead of bundled" OFF) 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_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) 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) find_package(Threads REQUIRED)
message(STATUS "Build type: " ${CMAKE_BUILD_TYPE}) message(STATUS "Build type: " ${CMAKE_BUILD_TYPE})
#--------------------------------------------------------------------------------------- #---------------------------------------------------------------------------------------
@ -94,18 +127,27 @@ set(SPDLOG_SRCS
src/stdout_sinks.cpp src/stdout_sinks.cpp
src/color_sinks.cpp src/color_sinks.cpp
src/file_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) if(NOT SPDLOG_FMT_EXTERNAL AND NOT SPDLOG_FMT_EXTERNAL_HO)
list(APPEND SPDLOG_SRCS src/fmt.cpp) list(APPEND SPDLOG_SRCS src/fmt.cpp)
endif() endif()
if (SPDLOG_BUILD_SHARED) if(WIN32 AND SPDLOG_BUILD_SHARED)
if(WIN32) list(APPEND SPDLOG_SRCS ${CMAKE_CURRENT_BINARY_DIR}/version.rc)
message(FATAL_ERROR "spdlog shared lib is not yet supported under windows")
endif() endif()
if (SPDLOG_BUILD_SHARED)
add_library(spdlog SHARED ${SPDLOG_SRCS} ${SPDLOG_ALL_HEADERS}) 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() else()
add_library(spdlog STATIC ${SPDLOG_SRCS} ${SPDLOG_ALL_HEADERS}) add_library(spdlog STATIC ${SPDLOG_SRCS} ${SPDLOG_ALL_HEADERS})
endif() 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 VERSION ${SPDLOG_VERSION} SOVERSION ${SPDLOG_VERSION_MAJOR})
set_target_properties(spdlog PROPERTIES DEBUG_POSTFIX d) 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 # Header only version
#--------------------------------------------------------------------------------------- #---------------------------------------------------------------------------------------
@ -209,8 +256,12 @@ endif()
# Build binaries # Build binaries
#--------------------------------------------------------------------------------------- #---------------------------------------------------------------------------------------
if(SPDLOG_BUILD_EXAMPLE OR SPDLOG_BUILD_EXAMPLE_HO) if(SPDLOG_BUILD_EXAMPLE OR SPDLOG_BUILD_EXAMPLE_HO)
message(STATUS "Generating examples") message(STATUS "Generating example(s)")
add_subdirectory(example) add_subdirectory(example)
spdlog_enable_warnings(example)
if(SPDLOG_BUILD_EXAMPLE_HO)
spdlog_enable_warnings(example_header_only)
endif()
endif() endif()
if(SPDLOG_BUILD_TESTS OR SPDLOG_BUILD_TESTS_HO) if(SPDLOG_BUILD_TESTS OR SPDLOG_BUILD_TESTS_HO)
@ -241,7 +292,10 @@ if (SPDLOG_INSTALL)
# Include files # Include files
#--------------------------------------------------------------------------------------- #---------------------------------------------------------------------------------------
install(DIRECTORY include/ DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}" PATTERN "fmt/bundled" EXCLUDE) 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) if(NOT SPDLOG_FMT_EXTERNAL AND NOT SPDLOG_FMT_EXTERNAL_HO)
install(DIRECTORY include/${PROJECT_NAME}/fmt/bundled/ install(DIRECTORY include/${PROJECT_NAME}/fmt/bundled/
@ -277,6 +331,5 @@ if (SPDLOG_INSTALL)
# Support creation of installable packages # Support creation of installable packages
#--------------------------------------------------------------------------------------- #---------------------------------------------------------------------------------------
include(cmake/spdlogCPack.cmake) include(cmake/spdlogCPack.cmake)
endif () endif ()

View File

@ -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 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE. 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

View File

@ -1,8 +1,6 @@
# spdlog # 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 ## Install
#### Header only version #### Header only version
@ -25,20 +23,22 @@ $ cmake .. && make -j
## Package managers: ## Package managers:
* Homebrew: `brew install spdlog` * Homebrew: `brew install spdlog`
* MacPorts: `sudo port install spdlog`
* FreeBSD: `cd /usr/ports/devel/spdlog/ && make install clean` * FreeBSD: `cd /usr/ports/devel/spdlog/ && make install clean`
* Fedora: `yum install spdlog` * Fedora: `yum install spdlog`
* Gentoo: `emerge dev-libs/spdlog` * Gentoo: `emerge dev-libs/spdlog`
* Arch Linux: `yaourt -S spdlog-git` * Arch Linux: `pacman -S spdlog`
* vcpkg: `vcpkg install 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 ## Features
* Very fast (see [benchmarks](#benchmarks) below). * 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. * 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. * **New!** [Backtrace](#backtrace-support) support - store debug messages in a ring buffer and display later on demand.
* Fast asynchronous mode (optional) * Asynchronous mode (optional)
* [Custom](https://github.com/gabime/spdlog/wiki/3.-Custom-formatting) formatting. * [Custom](https://github.com/gabime/spdlog/wiki/3.-Custom-formatting) formatting.
* Multi/Single threaded loggers. * Multi/Single threaded loggers.
* Various log targets: * Various log targets:
@ -48,7 +48,8 @@ $ cmake .. && make -j
* syslog. * syslog.
* Windows debugger (```OutputDebugString(..)```) * Windows debugger (```OutputDebugString(..)```)
* Easily extendable with custom log targets (just implement a single function in the [sink](include/spdlog/sinks/sink.h) interface). * 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 ## Usage samples
@ -77,15 +78,30 @@ int main()
// Compile time log levels // Compile time log levels
// define SPDLOG_ACTIVE_LEVEL to desired level // 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"); SPDLOG_DEBUG("Some debug message");
// Set the default logger to file logger // Set the default logger to file logger
auto file_logger = spdlog::basic_logger_mt("basic_logger", "logs/basic.txt"); auto file_logger = spdlog::basic_logger_mt("basic_logger", "logs/basic.txt");
spdlog::set_default_logger(file_logger); 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++ ```c++
#include "spdlog/spdlog.h" #include "spdlog/spdlog.h"
#include "spdlog/sinks/stdout_color_sinks.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 #### Periodic flush
```c++ ```c++
// periodically flush all *registered* loggers every 3 seconds: // 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)); 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 <my_formatter_flag> 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<custom_flag_formatter> clone() const override
{
return spdlog::details::make_unique<my_formatter_flag>();
}
};
void custom_flags_example()
{
auto formatter = std::make_unique<spdlog::pattern_formatter>();
formatter->add_flag<my_formatter_flag>('*').set_pattern("[%n] [%*] [%^%l%$] %v");
spdlog::set_formatter(std::move(formatter));
}
```
--- ---
#### Custom error handler #### Custom error handler
```c++ ```c++
@ -277,6 +324,8 @@ void err_handler_example()
} }
``` ```
--- ---
#### syslog #### syslog
```c++ ```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] daily_st Elapsed: 0.42 secs 2,393,298/sec
[info] null_st Elapsed: 0.04 secs 27,446,957/sec [info] null_st Elapsed: 0.04 secs 27,446,957/sec
[info] ************************************************************** [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] **************************************************************
[info] basic_mt Elapsed: 0.60 secs 1,659,613/sec [info] basic_mt Elapsed: 0.60 secs 1,659,613/sec
[info] rotating_mt Elapsed: 0.62 secs 1,612,493/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] Threads : 10
[info] Queue : 8,192 slots [info] Queue : 8,192 slots
[info] Queue memory : 8,192 x 272 = 2,176 KB [info] Queue memory : 8,192 x 272 = 2,176 KB
[info] Total iters : 3
[info] ------------------------------------------------- [info] -------------------------------------------------
[info] [info]
[info] ********************************* [info] *********************************

View File

@ -30,7 +30,7 @@ build_script:
set PATH=%PATH%:C:\Program Files\Git\usr\bin 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% cmake --build . --config %BUILD_TYPE%

View File

@ -19,19 +19,15 @@
#include <string> #include <string>
#include <thread> #include <thread>
using namespace std;
using namespace std::chrono;
using namespace spdlog;
using namespace spdlog::sinks;
using namespace utils;
void bench(int howmany, std::shared_ptr<spdlog::logger> log); void bench(int howmany, std::shared_ptr<spdlog::logger> log);
void bench_mt(int howmany, std::shared_ptr<spdlog::logger> log, int thread_count); void bench_mt(int howmany, std::shared_ptr<spdlog::logger> log, int thread_count);
void bench_default_api(int howmany, std::shared_ptr<spdlog::logger> log);
void bench_c_string(int howmany, std::shared_ptr<spdlog::logger> log);
static size_t file_size = 30 * 1024 * 1024; // void bench_default_api(int howmany, std::shared_ptr<spdlog::logger> log);
static size_t rotating_files = 5; // void bench_c_string(int howmany, std::shared_ptr<spdlog::logger> 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) void bench_threaded_logging(int threads, int iters)
{ {
@ -116,9 +112,18 @@ int main(int argc, char *argv[])
{ {
if (argc > 1) if (argc > 1)
iters = atoi(argv[1]); {
iters = std::stoi(argv[1]);
}
if (argc > 2) 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_single_threaded(iters);
bench_threaded_logging(1, iters); bench_threaded_logging(1, iters);
@ -134,7 +139,10 @@ int main(int argc, char *argv[])
void bench(int howmany, std::shared_ptr<spdlog::logger> log) void bench(int howmany, std::shared_ptr<spdlog::logger> log)
{ {
using std::chrono::duration;
using std::chrono::duration_cast;
using std::chrono::high_resolution_clock; using std::chrono::high_resolution_clock;
auto start = high_resolution_clock::now(); auto start = high_resolution_clock::now();
for (auto i = 0; i < howmany; ++i) for (auto i = 0; i < howmany; ++i)
{ {
@ -150,17 +158,21 @@ void bench(int howmany, std::shared_ptr<spdlog::logger> log)
void bench_mt(int howmany, std::shared_ptr<spdlog::logger> log, int thread_count) void bench_mt(int howmany, std::shared_ptr<spdlog::logger> log, int thread_count)
{ {
using std::chrono::duration;
using std::chrono::duration_cast;
using std::chrono::high_resolution_clock; using std::chrono::high_resolution_clock;
vector<thread> threads;
std::vector<std::thread> threads;
threads.reserve(thread_count);
auto start = high_resolution_clock::now(); auto start = high_resolution_clock::now();
for (int t = 0; t < thread_count; ++t) 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++) for (int j = 0; j < howmany / thread_count; j++)
{ {
log->info("Hello logger: msg number {}", j); log->info("Hello logger: msg number {}", j);
} }
})); });
} }
for (auto &t : threads) for (auto &t : threads)
@ -174,9 +186,13 @@ void bench_mt(int howmany, std::shared_ptr<spdlog::logger> log, int thread_count
spdlog::drop(log->name()); spdlog::drop(log->name());
} }
/*
void bench_default_api(int howmany, std::shared_ptr<spdlog::logger> log) void bench_default_api(int howmany, std::shared_ptr<spdlog::logger> log)
{ {
using std::chrono::high_resolution_clock; using std::chrono::high_resolution_clock;
using std::chrono::duration;
using std::chrono::duration_cast;
auto orig_default = spdlog::default_logger(); auto orig_default = spdlog::default_logger();
spdlog::set_default_logger(log); spdlog::set_default_logger(log);
auto start = high_resolution_clock::now(); auto start = high_resolution_clock::now();
@ -194,18 +210,22 @@ void bench_default_api(int howmany, std::shared_ptr<spdlog::logger> log)
void bench_c_string(int howmany, std::shared_ptr<spdlog::logger> log) void bench_c_string(int howmany, std::shared_ptr<spdlog::logger> 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 " 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 " "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 " "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 " "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."; "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(); auto orig_default = spdlog::default_logger();
spdlog::set_default_logger(log); spdlog::set_default_logger(log);
auto start = high_resolution_clock::now(); auto start = high_resolution_clock::now();
for (auto i = 0; i < howmany; ++i) 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; auto delta = high_resolution_clock::now() - start;
@ -214,3 +234,5 @@ void bench_c_string(int howmany, std::shared_ptr<spdlog::logger> log)
spdlog::set_default_logger(std::move(orig_default)); 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)); spdlog::info("{:<30} Elapsed: {:0.2f} secs {:>16n}/sec", log->name(), delta_d, int(howmany / delta_d));
} }
*/

View File

@ -6,7 +6,7 @@
#include "benchmark/benchmark.h" #include "benchmark/benchmark.h"
#include "spdlog/spdlog.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) void bench_formatter(benchmark::State &state, std::string pattern)
{ {

View File

@ -51,11 +51,21 @@ void bench_disabled_macro(benchmark::State &state, std::shared_ptr<spdlog::logge
} }
} }
#ifdef __linux__
void bench_dev_null()
{
auto dev_null_st = spdlog::basic_logger_st("/dev/null_st", "/dev/null");
benchmark::RegisterBenchmark("/dev/null_st", bench_logger, std::move(dev_null_st))->UseRealTime();
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[]) 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_mt;
using spdlog::sinks::null_sink_st; using spdlog::sinks::null_sink_st;
@ -63,6 +73,8 @@ int main(int argc, char *argv[])
size_t rotating_files = 5; size_t rotating_files = 5;
int n_threads = benchmark::CPUInfo::Get().num_cpus; int n_threads = benchmark::CPUInfo::Get().num_cpus;
auto full_bench = argc > 1 && std::string(argv[1]) == "full";
// disabled loggers // disabled loggers
auto disabled_logger = std::make_shared<spdlog::logger>("bench", std::make_shared<null_sink_mt>()); auto disabled_logger = std::make_shared<spdlog::logger>("bench", std::make_shared<null_sink_mt>());
disabled_logger->set_level(spdlog::level::off); disabled_logger->set_level(spdlog::level::off);
@ -81,6 +93,12 @@ int main(int argc, char *argv[])
tracing_null_logger_st->enable_backtrace(64); tracing_null_logger_st->enable_backtrace(64);
benchmark::RegisterBenchmark("null_sink_st/backtrace", bench_logger, tracing_null_logger_st); benchmark::RegisterBenchmark("null_sink_st/backtrace", bench_logger, tracing_null_logger_st);
#ifdef __linux
bench_dev_null();
#endif // __linux__
if (full_bench)
{
// basic_st // basic_st
auto basic_st = spdlog::basic_logger_st("basic_st", "latency_logs/basic_st.log", true); 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(); benchmark::RegisterBenchmark("basic_st", bench_logger, std::move(basic_st))->UseRealTime();
@ -129,6 +147,7 @@ int main(int argc, char *argv[])
auto daily_mt = spdlog::daily_logger_mt("daily_mt", "latency_logs/daily_mt.log"); 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(); benchmark::RegisterBenchmark("daily_mt", bench_logger, std::move(daily_mt))->Threads(n_threads)->UseRealTime();
spdlog::drop("daily_mt"); spdlog::drop("daily_mt");
}
// async // async
auto queue_size = 1024 * 1024 * 3; auto queue_size = 1024 * 1024 * 3;

258
third_party/spdlog/cmake/pch.h.in vendored Normal file
View File

@ -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 <cctype>
// 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 <cstdio>
// details/os-inl.h
// fmt/bundled/posix.h
#include <cstdlib>
// details/os-inl.h
// details/pattern_formatter-inl.h
// fmt/bundled/core.h
// fmt/bundled/format-inl.h
#include <cstring>
// 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 <ctime>
// fmt/bundled/format-inl.h
#include <climits>
// fmt/bundled/format-inl.h
#include <cwchar>
// fmt/bundled/format-inl.h
// fmt/bundled/format.h
#include <cmath>
// fmt/bundled/format-inl.h
#include <cstdarg>
// details/file_helper-inl.h
// fmt/bundled/format.h
// fmt/bundled/posix.h
// sinks/rotating_file_sink-inl.h
#include <cerrno>
// details/circular_q.h
// details/thread_pool-inl.h
// fmt/bundled/format-inl.h
#include <cassert>
// 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 <string>
// cfg/helpers-inl.h
// fmt/bundled/chrono.h
#include <sstream>
// fmt/bundled/ostream.h
// sinks/ostream_sink.h
#include <ostream>
// cfg/log_levels.h
// details/registry-inl.h
// details/registry.h
#include <unordered_map>
// 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 <vector>
// 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 <array>
// details/file_helper-inl.h
// details/file_helper.h
// sinks/rotating_file_sink-inl.h
#include <tuple>
// details/os-inl.h
// fmt/bundled/format.h
// fmt/bundled/printf.h
#include <limits>
// common.h
// details/backtracer.h
// details/null_mutex.h
#include <atomic>
// common.h
// details/backtracer.h
// details/null_mutex.h
#include <locale>
// common.h
#include <initializer_list>
// common.h
#include <exception>
// common.h
// details/fmt_helper.h
// fmt/bundled/core.h
// fmt/bundled/ranges.h
#include <type_traits>
// cfg/helpers-inl.h
// details/null_mutex.h
// details/pattern_formatter-inl.h
#include <utility>
// 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 <memory>
// 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 <functional>
// details/mpmc_blocking_q.h
// details/periodic_worker.h
#include <condition_variable>
// details/os-inl.h
// fmt/bundled/format.h
// fmt/bundled/printf.h
// sinks/dist_sink.h
#include <algorithm>
// 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 <chrono>
// 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 <thread>
// 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 <mutex>
// spdlog
#include <spdlog/common.h>

View File

@ -1,7 +1,4 @@
set(CPACK_GENERATOR set(CPACK_GENERATOR "TGZ;ZIP" CACHE STRING "Semicolon separated list of generators")
TGZ
ZIP
)
set(CPACK_INCLUDE_TOPLEVEL_DIRECTORY 0) set(CPACK_INCLUDE_TOPLEVEL_DIRECTORY 0)
set(CPACK_INSTALL_CMAKE_PROJECTS set(CPACK_INSTALL_CMAKE_PROJECTS
@ -22,11 +19,32 @@ set(CPACK_PACKAGE_VERSION ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PR
if (PROJECT_VERSION_TWEAK) if (PROJECT_VERSION_TWEAK)
set(CPACK_PACKAGE_VERSION ${CPACK_PACKAGE_VERSION}.${PROJECT_VERSION_TWEAK}) set(CPACK_PACKAGE_VERSION ${CPACK_PACKAGE_VERSION}.${PROJECT_VERSION_TWEAK})
endif () 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_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_URL ${CPACK_PROJECT_URL})
set(CPACK_RPM_PACKAGE_DESCRIPTION "Very fast, header-only/compiled, C++ logging library.") 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) include(CPack)

View File

@ -20,19 +20,28 @@ function(spdlog_extract_version)
set(ver_patch ${CMAKE_MATCH_1}) set(ver_patch ${CMAKE_MATCH_1})
set(SPDLOG_VERSION_MAJOR ${ver_major} PARENT_SCOPE) 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) set (SPDLOG_VERSION "${ver_major}.${ver_minor}.${ver_patch}" PARENT_SCOPE)
endfunction() endfunction()
# Turn on warnings on the given target # Turn on warnings on the given target
function(spdlog_enable_warnings target_name) function(spdlog_enable_warnings target_name)
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 target_compile_options(${target_name} PRIVATE
$<$<OR:$<CXX_COMPILER_ID:Clang>,$<CXX_COMPILER_ID:AppleClang>,$<CXX_COMPILER_ID:GNU>>: $<$<OR:$<CXX_COMPILER_ID:Clang>,$<CXX_COMPILER_ID:AppleClang>,$<CXX_COMPILER_ID:GNU>>:
-Wall -Wextra -Wconversion -pedantic -Wfatal-errors> -Wall -Wextra -Wconversion -pedantic -Wfatal-errors>
$<$<CXX_COMPILER_ID:MSVC>:/W4>) $<$<CXX_COMPILER_ID:MSVC>:${MSVC_OPTIONS}>)
if(MSVC_VERSION GREATER_EQUAL 1910) #Allow non fatal security wanrnings for msvc 2015
target_compile_options(${target_name} PRIVATE /WX)
endif() endif()
endfunction() endfunction()

42
third_party/spdlog/cmake/version.rc.in vendored Normal file
View File

@ -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

View File

@ -1,7 +1,7 @@
# Copyright(c) 2019 spdlog authors # Copyright(c) 2019 spdlog authors
# Distributed under the MIT License (http://opensource.org/licenses/MIT) # 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) project(spdlog_examples CXX)
if(NOT TARGET spdlog) if(NOT TARGET spdlog)
@ -13,7 +13,6 @@ endif()
# Example of using pre-compiled library # Example of using pre-compiled library
#--------------------------------------------------------------------------------------- #---------------------------------------------------------------------------------------
add_executable(example example.cpp) add_executable(example example.cpp)
spdlog_enable_warnings(example)
target_link_libraries(example PRIVATE spdlog::spdlog) target_link_libraries(example PRIVATE spdlog::spdlog)
#--------------------------------------------------------------------------------------- #---------------------------------------------------------------------------------------
@ -21,7 +20,6 @@ target_link_libraries(example PRIVATE spdlog::spdlog)
#--------------------------------------------------------------------------------------- #---------------------------------------------------------------------------------------
if(SPDLOG_BUILD_EXAMPLE_HO) if(SPDLOG_BUILD_EXAMPLE_HO)
add_executable(example_header_only example.cpp) add_executable(example_header_only example.cpp)
spdlog_enable_warnings(example_header_only)
target_link_libraries(example_header_only PRIVATE spdlog::spdlog_header_only) target_link_libraries(example_header_only PRIVATE spdlog::spdlog_header_only)
endif() endif()

View File

@ -6,6 +6,7 @@
#include <cstdio> #include <cstdio>
void load_levels_example();
void stdout_logger_example(); void stdout_logger_example();
void basic_example(); void basic_example();
void rotating_example(); void rotating_example();
@ -17,12 +18,18 @@ void multi_sink_example();
void user_defined_example(); void user_defined_example();
void err_handler_example(); void err_handler_example();
void syslog_example(); void syslog_example();
void custom_flags_example();
#include "spdlog/spdlog.h" #include "spdlog/spdlog.h"
#include "spdlog/cfg/env.h" // for loading levels from the environment variable
int main(int, char *[]) 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::info("Welcome to spdlog version {}.{}.{} !", SPDLOG_VER_MAJOR, SPDLOG_VER_MINOR, SPDLOG_VER_PATCH);
spdlog::warn("Easy padding in numbers like {:08d}", 12); 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::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); spdlog::info("Support for floats {:03.2f}", 1.23456);
@ -64,6 +71,7 @@ int main(int, char *[])
user_defined_example(); user_defined_example();
err_handler_example(); err_handler_example();
trace_example(); trace_example();
custom_flags_example();
// Flush all *registered* loggers using a worker thread every 3 seconds. // Flush all *registered* loggers using a worker thread every 3 seconds.
// note: registered loggers *must* be thread safe for this to work correctly! // 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); 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" #include "spdlog/async.h"
void async_example() void async_example()
{ {
@ -154,6 +174,8 @@ void binary_example()
// logger->info("uppercase: {:X}", spdlog::to_hex(buf)); // logger->info("uppercase: {:X}", spdlog::to_hex(buf));
// logger->info("uppercase, no delimiters: {:Xs}", 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("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. // Compile time log levels.
@ -230,5 +252,31 @@ void android_example()
auto android_logger = spdlog::android_logger_mt("android", tag); auto android_logger = spdlog::android_logger_mt("android", tag);
android_logger->critical("Use \"adb shell logcat\" to view this message."); android_logger->critical("Use \"adb shell logcat\" to view this message.");
} }
#endif #endif
// Log patterns can contain custom flags.
// this will add custom flag '%*' which will be bound to a <my_formatter_flag> 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<custom_flag_formatter> clone() const override
{
return spdlog::details::make_unique<my_formatter_flag>();
}
};
void custom_flags_example()
{
using spdlog::details::make_unique; // for pre c++14
auto formatter = make_unique<spdlog::pattern_formatter>();
formatter->add_flag<my_formatter_flag>('*').set_pattern("[%n] [%*] [%^%l%$] %v");
spdlog::set_formatter(std::move(formatter));
}

View File

@ -32,7 +32,7 @@ SPDLOG_INLINE void spdlog::async_logger::sink_it_(const details::log_msg &msg)
} }
else 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 else
{ {
SPDLOG_THROW(spdlog_ex("async flush: thread pool doesn't exist anymore")); throw_spdlog_ex("async flush: thread pool doesn't exist anymore");
} }
} }

View File

@ -30,7 +30,7 @@ namespace details {
class thread_pool; class thread_pool;
} }
class async_logger final : public std::enable_shared_from_this<async_logger>, public logger class SPDLOG_API async_logger final : public std::enable_shared_from_this<async_logger>, public logger
{ {
friend class details::thread_pool; friend class details::thread_pool;

View File

@ -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 <spdlog/cfg/helpers.h>
#include <spdlog/details/registry.h>
//
// 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<const char **>(argv));
}
} // namespace cfg
} // namespace spdlog

View File

@ -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 <spdlog/cfg/helpers.h>
#include <spdlog/details/registry.h>
#include <spdlog/details/os.h>
//
// 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

View File

@ -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 <spdlog/cfg/helpers.h>
#endif
#include <spdlog/spdlog.h>
#include <spdlog/details/os.h>
#include <spdlog/details/registry.h>
#include <string>
#include <utility>
#include <sstream>
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<char>((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<std::string, std::string> 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<std::string, std::string> extract_key_vals_(const std::string &str)
{
std::string token;
std::istringstream token_stream(str);
std::unordered_map<std::string, std::string> 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

View File

@ -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 <spdlog/cfg/log_levels.h>
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

View File

@ -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 <spdlog/common.h>
#include <string>
#include <unordered_map>
namespace spdlog {
namespace cfg {
class log_levels
{
std::unordered_map<std::string, spdlog::level::level_enum> 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

View File

@ -34,6 +34,15 @@ SPDLOG_INLINE spdlog::level::level_enum from_str(const std::string &name) SPDLOG
} }
level++; 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; return level::off;
} }
} // namespace level } // namespace level
@ -54,4 +63,14 @@ SPDLOG_INLINE const char *spdlog_ex::what() const SPDLOG_NOEXCEPT
return msg_.c_str(); 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 } // namespace spdlog

View File

@ -15,22 +15,20 @@
#include <type_traits> #include <type_traits>
#include <functional> #include <functional>
#ifdef _WIN32
#ifndef NOMINMAX
#define NOMINMAX // prevent windows redefining min/max
#endif
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#include <windows.h>
#endif //_WIN32
#ifdef SPDLOG_COMPILED_LIB #ifdef SPDLOG_COMPILED_LIB
#undef SPDLOG_HEADER_ONLY #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 #define SPDLOG_INLINE
#else #else
#define SPDLOG_API
#define SPDLOG_HEADER_ONLY #define SPDLOG_HEADER_ONLY
#define SPDLOG_INLINE inline #define SPDLOG_INLINE inline
#endif #endif
@ -147,6 +145,7 @@ enum level_enum
err = SPDLOG_LEVEL_ERROR, err = SPDLOG_LEVEL_ERROR,
critical = SPDLOG_LEVEL_CRITICAL, critical = SPDLOG_LEVEL_CRITICAL,
off = SPDLOG_LEVEL_OFF, off = SPDLOG_LEVEL_OFF,
n_levels
}; };
#if !defined(SPDLOG_LEVEL_NAMES) #if !defined(SPDLOG_LEVEL_NAMES)
@ -164,9 +163,9 @@ enum level_enum
} }
#endif #endif
string_view_t &to_string_view(spdlog::level::level_enum l) SPDLOG_NOEXCEPT; SPDLOG_API 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_API 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 spdlog::level::level_enum from_str(const std::string &name) SPDLOG_NOEXCEPT;
using level_hasher = std::hash<int>; using level_hasher = std::hash<int>;
} // namespace level } // namespace level
@ -194,7 +193,7 @@ enum class pattern_time_type
// //
// Log exception // Log exception
// //
class spdlog_ex : public std::exception class SPDLOG_API spdlog_ex : public std::exception
{ {
public: public:
explicit spdlog_ex(std::string msg); explicit spdlog_ex(std::string msg);
@ -205,6 +204,9 @@ private:
std::string msg_; std::string msg_;
}; };
void throw_spdlog_ex(const std::string &msg, int last_errno);
void throw_spdlog_ex(std::string msg);
struct source_loc struct source_loc
{ {
SPDLOG_CONSTEXPR source_loc() = default; SPDLOG_CONSTEXPR source_loc() = default;
@ -237,7 +239,6 @@ std::unique_ptr<T> make_unique(Args &&... args)
} }
#endif #endif
} // namespace details } // namespace details
} // namespace spdlog } // namespace spdlog
#ifdef SPDLOG_HEADER_ONLY #ifdef SPDLOG_HEADER_ONLY

View File

@ -15,7 +15,7 @@
namespace spdlog { namespace spdlog {
namespace details { namespace details {
class backtracer class SPDLOG_API backtracer
{ {
mutable std::mutex mutex_; mutable std::mutex mutex_;
std::atomic<bool> enabled_{false}; std::atomic<bool> enabled_{false};

View File

@ -43,14 +43,14 @@ SPDLOG_INLINE void file_helper::open(const filename_t &fname, bool truncate)
details::os::sleep_for_millis(open_interval_); 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) SPDLOG_INLINE void file_helper::reopen(bool truncate)
{ {
if (filename_.empty()) 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); this->open(filename_, truncate);
} }
@ -75,7 +75,7 @@ SPDLOG_INLINE void file_helper::write(const memory_buf_t &buf)
auto data = buf.data(); auto data = buf.data();
if (std::fwrite(data, 1, msg_size, fd_) != msg_size) 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) 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_); return os::filesize(fd_);
} }

View File

@ -13,7 +13,7 @@ namespace details {
// When failing to open a file, retry several times(5) with a delay interval(10 ms). // When failing to open a file, retry several times(5) with a delay interval(10 ms).
// Throw spdlog_ex exception on errors. // Throw spdlog_ex exception on errors.
class file_helper class SPDLOG_API file_helper
{ {
public: public:
explicit file_helper() = default; explicit file_helper() = default;

View File

@ -20,11 +20,8 @@ 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) inline void append_string_view(spdlog::string_view_t view, memory_buf_t &dest)
{ {
auto *buf_ptr = view.data(); 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<typename T> template<typename T>
inline void append_int(T n, memory_buf_t &dest) inline void append_int(T n, memory_buf_t &dest)
@ -34,10 +31,10 @@ inline void append_int(T n, memory_buf_t &dest)
} }
template<typename T> template<typename T>
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; using count_type = typename std::conditional<(sizeof(T) > sizeof(uint32_t)), uint64_t, uint32_t>::type;
return static_cast<unsigned>(fmt::internal::count_digits(static_cast<count_type>(n))); return static_cast<unsigned int>(fmt::internal::count_digits(static_cast<count_type>(n)));
} }
inline void pad2(int n, memory_buf_t &dest) inline void pad2(int n, memory_buf_t &dest)
@ -66,11 +63,9 @@ template<typename T>
inline void pad_uint(T n, unsigned int width, memory_buf_t &dest) inline void pad_uint(T n, unsigned int width, memory_buf_t &dest)
{ {
static_assert(std::is_unsigned<T>::value, "pad_uint must get unsigned T"); static_assert(std::is_unsigned<T>::value, "pad_uint must get unsigned T");
auto digits = count_digits(n); for (auto digits = count_digits(n); digits < width; digits++)
if (width > digits)
{ {
const char *zeroes = "0000000000000000000"; dest.push_back('0');
dest.append(zeroes, zeroes + width - digits);
} }
append_int(n, dest); append_int(n, dest);
} }
@ -78,7 +73,18 @@ inline void pad_uint(T n, unsigned int width, memory_buf_t &dest)
template<typename T> template<typename T>
inline void pad3(T n, memory_buf_t &dest) inline void pad3(T n, memory_buf_t &dest)
{ {
pad_uint(n, 3, dest); static_assert(std::is_unsigned<T>::value, "pad3 must get unsigned T");
if(n < 1000)
{
dest.push_back(static_cast<char>(n / 100 + '0'));
n = n % 100;
dest.push_back(static_cast<char>((n / 10) + '0'));
dest.push_back(static_cast<char>((n % 10) + '0'));
}
else
{
append_int(n, dest);
}
} }
template<typename T> template<typename T>

View File

@ -8,7 +8,7 @@
namespace spdlog { namespace spdlog {
namespace details { namespace details {
struct log_msg struct SPDLOG_API log_msg
{ {
log_msg() = default; log_msg() = default;
log_msg(source_loc loc, string_view_t logger_name, level::level_enum lvl, string_view_t msg); log_msg(source_loc loc, string_view_t logger_name, level::level_enum lvl, string_view_t msg);

View File

@ -11,7 +11,7 @@ namespace details {
// Extend log_msg with internal buffer to store its payload. // Extend log_msg with internal buffer to store its payload.
// THis is needed since log_msg holds string_views that points to stack data. // 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; memory_buf_t buffer;
void update_string_views(); void update_string_views();

View File

@ -23,16 +23,9 @@
#ifdef _WIN32 #ifdef _WIN32
#ifndef NOMINMAX
#define NOMINMAX // prevent windows redefining min/max
#endif
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#include <io.h> // _get_osfhandle and _isatty support #include <io.h> // _get_osfhandle and _isatty support
#include <process.h> // _get_pid support #include <process.h> // _get_pid support
#include <windows.h> #include <spdlog/details/windows_include.h>
#ifdef __MINGW32__ #ifdef __MINGW32__
#include <share.h> #include <share.h>
@ -126,23 +119,6 @@ SPDLOG_INLINE std::tm gmtime() SPDLOG_NOEXCEPT
return gmtime(now_t); return gmtime(now_t);
} }
#ifdef SPDLOG_PREVENT_CHILD_FD
SPDLOG_INLINE void prevent_child_fd(FILE *f)
{
#ifdef _WIN32
auto file_handle = reinterpret_cast<HANDLE>(_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 // fopen_s on non windows for writing
SPDLOG_INLINE bool fopen_s(FILE **fp, const filename_t &filename, const filename_t &mode) 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 #else
*fp = ::_fsopen((filename.c_str()), mode.c_str(), _SH_DENYNO); *fp = ::_fsopen((filename.c_str()), mode.c_str(), _SH_DENYNO);
#endif #endif
#else // unix #if defined(SPDLOG_PREVENT_CHILD_FD)
*fp = ::fopen((filename.c_str()), mode.c_str());
#endif
#ifdef SPDLOG_PREVENT_CHILD_FD
// prevent child processes from inheriting log file descriptors
if (*fp != nullptr) if (*fp != nullptr)
{ {
prevent_child_fd(*fp); auto file_handle = reinterpret_cast<HANDLE>(_get_osfhandle(::_fileno(*fp)));
if (!::SetHandleInformation(file_handle, HANDLE_FLAG_INHERIT, 0))
{
::fclose(*fp);
*fp = nullptr;
}
} }
#endif #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; return *fp == nullptr;
} }
@ -210,7 +204,7 @@ SPDLOG_INLINE size_t filesize(FILE *f)
{ {
if (f == nullptr) 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__) #if defined(_WIN32) && !defined(__CYGWIN__)
int fd = ::_fileno(f); int fd = ::_fileno(f);
@ -251,7 +245,8 @@ SPDLOG_INLINE size_t filesize(FILE *f)
} }
#endif #endif
#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 // 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); auto rv = ::GetDynamicTimeZoneInformation(&tzinfo);
#endif #endif
if (rv == TIME_ZONE_ID_INVALID) 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; int offset = -tzinfo.Bias;
if (tm.tm_isdst) if (tm.tm_isdst)
@ -396,13 +391,13 @@ SPDLOG_INLINE int pid() SPDLOG_NOEXCEPT
} }
// Determine if the terminal supports colors // 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 SPDLOG_INLINE bool is_color_terminal() SPDLOG_NOEXCEPT
{ {
#ifdef _WIN32 #ifdef _WIN32
return true; return true;
#else #else
static constexpr std::array<const char *, 14> Terms = { static constexpr std::array<const char *, 14> terms = {
{"ansi", "color", "console", "cygwin", "gnome", "konsole", "kterm", "linux", "msys", "putty", "rxvt", "screen", "vt100", "xterm"}}; {"ansi", "color", "console", "cygwin", "gnome", "konsole", "kterm", "linux", "msys", "putty", "rxvt", "screen", "vt100", "xterm"}};
const char *env_p = std::getenv("TERM"); const char *env_p = std::getenv("TERM");
@ -412,7 +407,7 @@ SPDLOG_INLINE bool is_color_terminal() SPDLOG_NOEXCEPT
} }
static const bool result = 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; return result;
#endif #endif
} }
@ -434,7 +429,7 @@ SPDLOG_INLINE void wstr_to_utf8buf(wstring_view_t wstr, memory_buf_t &target)
{ {
if (wstr.size() > static_cast<size_t>((std::numeric_limits<int>::max)())) if (wstr.size() > static_cast<size_t>((std::numeric_limits<int>::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<int>(wstr.size()); int wstr_size = static_cast<int>(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) #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{}; 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 os
} // namespace details } // namespace details
} // namespace spdlog } // namespace spdlog

View File

@ -10,15 +10,15 @@ namespace spdlog {
namespace details { namespace details {
namespace os { 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 // eol definition
#if !defined(SPDLOG_EOL) #if !defined(SPDLOG_EOL)
@ -38,54 +38,50 @@ static const char folder_sep = '\\';
SPDLOG_CONSTEXPR static const char folder_sep = '/'; SPDLOG_CONSTEXPR static const char folder_sep = '/';
#endif #endif
#ifdef SPDLOG_PREVENT_CHILD_FD
void prevent_child_fd(FILE *f);
#endif
// fopen_s on non windows for writing // 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 // 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 // Remove file if exists. return 0 on success
// Note: Non atomic (might return failure to delete if concurrently deleted by other process/thread) // 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. // 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 // 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 // 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 // Return current thread id as size_t
// It exists because the std::this_thread::get_id() is much slower(especially // It exists because the std::this_thread::get_id() is much slower(especially
// under VS 2013) // 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) // 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. // This is avoid msvc issue in sleep_for that happens if the clock changes.
// See https://github.com/gabime/spdlog/issues/609 // 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 // Determine if the terminal supports colors
// Source: https://github.com/agauniyal/rang/ // 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 // Determine if the terminal attached
// Source: https://github.com/agauniyal/rang/ // 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) #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); 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" => "" // "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. // Create a dir from the given path.
// Return true if succeeded or if this dir already exists. // 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 os
} // namespace details } // namespace details

View File

@ -17,7 +17,7 @@
namespace spdlog { namespace spdlog {
namespace details { namespace details {
class periodic_worker class SPDLOG_API periodic_worker
{ {
public: public:
periodic_worker(const std::function<void()> &callback_fun, std::chrono::seconds interval); periodic_worker(const std::function<void()> &callback_fun, std::chrono::seconds interval);

View File

@ -10,7 +10,7 @@
#include <spdlog/common.h> #include <spdlog/common.h>
#include <spdlog/details/periodic_worker.h> #include <spdlog/details/periodic_worker.h>
#include <spdlog/logger.h> #include <spdlog/logger.h>
#include <spdlog/details/pattern_formatter.h> #include <spdlog/pattern_formatter.h>
#ifndef SPDLOG_DISABLE_DEFAULT_LOGGER #ifndef SPDLOG_DISABLE_DEFAULT_LOGGER
// support for the default stdout color logger // support for the default stdout color logger
@ -48,6 +48,9 @@ SPDLOG_INLINE registry::registry()
#endif // SPDLOG_DISABLE_DEFAULT_LOGGER #endif // SPDLOG_DISABLE_DEFAULT_LOGGER
} }
SPDLOG_INLINE registry::~registry() = default;
SPDLOG_INLINE void registry::register_logger(std::shared_ptr<logger> new_logger) SPDLOG_INLINE void registry::register_logger(std::shared_ptr<logger> new_logger)
{ {
std::lock_guard<std::mutex> lock(logger_map_mutex_); std::lock_guard<std::mutex> lock(logger_map_mutex_);
@ -64,7 +67,7 @@ SPDLOG_INLINE void registry::initialize_logger(std::shared_ptr<logger> new_logge
new_logger->set_error_handler(err_handler_); 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_); new_logger->flush_on(flush_level_);
if (backtrace_n_messages_ > 0) 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); 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) 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) SPDLOG_INLINE void registry::flush_every(std::chrono::seconds interval)
{ {
std::lock_guard<std::mutex> lock(flusher_mutex_); std::lock_guard<std::mutex> lock(flusher_mutex_);
std::function<void()> clbk = std::bind(&registry::flush_all, this); auto clbk = [this]() { this->flush_all(); };
periodic_flusher_ = details::make_unique<periodic_worker>(clbk, interval); periodic_flusher_ = details::make_unique<periodic_worker>(clbk, interval);
} }
@ -260,6 +263,17 @@ SPDLOG_INLINE void registry::set_automatic_registration(bool automatic_registrat
automatic_registration_ = automatic_registration; automatic_registration_ = automatic_registration;
} }
SPDLOG_INLINE void registry::update_levels(cfg::log_levels levels)
{
std::lock_guard<std::mutex> 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 &registry::instance() SPDLOG_INLINE registry &registry::instance()
{ {
static registry s_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()) 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<logger> new_logger
throw_if_exists_(logger_name); throw_if_exists_(logger_name);
loggers_[logger_name] = std::move(new_logger); loggers_[logger_name] = std::move(new_logger);
} }
} // namespace details } // namespace details
} // namespace spdlog } // namespace spdlog

View File

@ -9,6 +9,7 @@
// This class is thread safe // This class is thread safe
#include <spdlog/common.h> #include <spdlog/common.h>
#include <spdlog/cfg/log_levels.h>
#include <chrono> #include <chrono>
#include <functional> #include <functional>
@ -24,7 +25,7 @@ namespace details {
class thread_pool; class thread_pool;
class periodic_worker; class periodic_worker;
class registry class SPDLOG_API registry
{ {
public: public:
registry(const registry &) = delete; registry(const registry &) = delete;
@ -79,19 +80,21 @@ public:
void set_automatic_registration(bool automatic_registration); void set_automatic_registration(bool automatic_registration);
void update_levels(cfg::log_levels levels);
static registry &instance(); static registry &instance();
private: private:
registry(); registry();
~registry() = default; ~registry();
void throw_if_exists_(const std::string &logger_name); void throw_if_exists_(const std::string &logger_name);
void register_logger_(std::shared_ptr<logger> new_logger); void register_logger_(std::shared_ptr<logger> new_logger);
std::mutex logger_map_mutex_, flusher_mutex_; std::mutex logger_map_mutex_, flusher_mutex_;
std::recursive_mutex tp_mutex_; std::recursive_mutex tp_mutex_;
std::unordered_map<std::string, std::shared_ptr<logger>> loggers_; std::unordered_map<std::string, std::shared_ptr<logger>> loggers_;
cfg::log_levels levels_;
std::unique_ptr<formatter> formatter_; std::unique_ptr<formatter> formatter_;
level::level_enum level_ = level::info;
level::level_enum flush_level_ = level::off; level::level_enum flush_level_ = level::off;
void (*err_handler_)(const std::string &msg); void (*err_handler_)(const std::string &msg);
std::shared_ptr<thread_pool> tp_; std::shared_ptr<thread_pool> tp_;

View File

@ -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 <spdlog/common.h>
#include <spdlog/details/os.h>
#include <windows.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdlib.h>
#include <stdio.h>
#include <string>
#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<size_t>(write_result);
}
}
};
} // namespace details
} // namespace spdlog

View File

@ -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 <spdlog/common.h>
#include <spdlog/details/os.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <netdb.h>
#include <netinet/tcp.h>
#include <string>
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<size_t>(write_result);
}
}
};
} // namespace details
} // namespace spdlog

View File

@ -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) if (threads_n == 0 || threads_n > 1000)
{ {
SPDLOG_THROW(spdlog_ex("spdlog::thread_pool(): invalid threads_n param (valid " throw_spdlog_ex("spdlog::thread_pool(): invalid threads_n param (valid "
"range is 1-1000)")); "range is 1-1000)");
} }
for (size_t i = 0; i < threads_n; i++) for (size_t i = 0; i < threads_n; i++)
{ {
@ -113,7 +113,7 @@ bool SPDLOG_INLINE thread_pool::process_next_msg_()
} }
default: { default: {
assert(false && "Unexpected async_msg_type"); assert(false);
} }
} }

View File

@ -79,7 +79,7 @@ struct async_msg : log_msg_buffer
{} {}
}; };
class thread_pool class SPDLOG_API thread_pool
{ {
public: public:
using item_type = async_msg; using item_type = async_msg;

View File

@ -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 <windows.h>

View File

@ -5,6 +5,8 @@
#pragma once #pragma once
#include <cctype>
// //
// Support for logging binary data as hex // Support for logging binary data as hex
// format flags: // format flags:
@ -12,6 +14,7 @@
// {:s} - don't separate each byte with space. // {:s} - don't separate each byte with space.
// {:p} - don't print the position on each line start. // {:p} - don't print the position on each line start.
// {:n} - don't split the output to lines. // {:n} - don't split the output to lines.
// {:a} - show ASCII if :n is not set
// //
// Examples: // Examples:
@ -20,17 +23,19 @@
// logger->info("Some buffer {}", spdlog::to_hex(v)); // logger->info("Some buffer {}", spdlog::to_hex(v));
// char buf[128]; // 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)));
// logger->info("Some buffer {:X}", spdlog::to_hex(std::begin(buf), std::end(buf), 16));
namespace spdlog { namespace spdlog {
namespace details { namespace details {
template<typename It> template<typename It>
class bytes_range class dump_info
{ {
public: 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) : begin_(range_begin)
, end_(range_end) , end_(range_end)
, size_per_line_(size_per_line)
{} {}
It begin() const It begin() const
@ -41,26 +46,31 @@ public:
{ {
return end_; return end_;
} }
size_t size_per_line() const
{
return size_per_line_;
}
private: private:
It begin_, end_; It begin_, end_;
size_t size_per_line_;
}; };
} // namespace details } // namespace details
// create a bytes_range that wraps the given container // create a dump_info that wraps the given container
template<typename Container> template<typename Container>
inline details::bytes_range<typename Container::const_iterator> to_hex(const Container &container) inline details::dump_info<typename Container::const_iterator> to_hex(const Container &container, size_t size_per_line = 32)
{ {
static_assert(sizeof(typename Container::value_type) == 1, "sizeof(Container::value_type) != 1"); static_assert(sizeof(typename Container::value_type) == 1, "sizeof(Container::value_type) != 1");
using Iter = typename Container::const_iterator; using Iter = typename Container::const_iterator;
return details::bytes_range<Iter>(std::begin(container), std::end(container)); return details::dump_info<Iter>(std::begin(container), std::end(container), size_per_line);
} }
// create bytes_range from ranges // create dump_info from ranges
template<typename It> template<typename It>
inline details::bytes_range<It> to_hex(const It range_begin, const It range_end) inline details::dump_info<It> to_hex(const It range_begin, const It range_end, size_t size_per_line = 32)
{ {
return details::bytes_range<It>(range_begin, range_end); return details::dump_info<It>(range_begin, range_end, size_per_line);
} }
} // namespace spdlog } // namespace spdlog
@ -68,15 +78,14 @@ inline details::bytes_range<It> to_hex(const It range_begin, const It range_end)
namespace fmt { namespace fmt {
template<typename T> template<typename T>
struct formatter<spdlog::details::bytes_range<T>> struct formatter<spdlog::details::dump_info<T>>
{ {
const std::size_t line_size = 100;
const char delimiter = ' '; const char delimiter = ' ';
bool put_newlines = true; bool put_newlines = true;
bool put_delimiters = true; bool put_delimiters = true;
bool use_uppercase = false; bool use_uppercase = false;
bool put_positions = true; // position on start of each line bool put_positions = true; // position on start of each line
bool show_ascii = false;
// parse the format string flags // parse the format string flags
template<typename ParseContext> template<typename ParseContext>
@ -98,6 +107,13 @@ struct formatter<spdlog::details::bytes_range<T>>
break; break;
case 'n': case 'n':
put_newlines = false; put_newlines = false;
show_ascii = false;
break;
case 'a':
if (put_newlines)
{
show_ascii = true;
}
break; break;
} }
@ -108,53 +124,83 @@ struct formatter<spdlog::details::bytes_range<T>>
// format the given bytes range as hex // format the given bytes range as hex
template<typename FormatContext, typename Container> template<typename FormatContext, typename Container>
auto format(const spdlog::details::bytes_range<Container> &the_range, FormatContext &ctx) -> decltype(ctx.out()) auto format(const spdlog::details::dump_info<Container> &the_range, FormatContext &ctx) -> decltype(ctx.out())
{ {
SPDLOG_CONSTEXPR const char *hex_upper = "0123456789ABCDEF"; SPDLOG_CONSTEXPR const char *hex_upper = "0123456789ABCDEF";
SPDLOG_CONSTEXPR const char *hex_lower = "0123456789abcdef"; SPDLOG_CONSTEXPR const char *hex_lower = "0123456789abcdef";
const char *hex_chars = use_uppercase ? hex_upper : hex_lower; 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 #if FMT_VERSION < 60000
auto inserter = ctx.begin(); auto inserter = ctx.begin();
#else #else
auto inserter = ctx.out(); auto inserter = ctx.out();
#endif #endif
for (auto &item : the_range) int size_per_line = static_cast<int>(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<unsigned char>(item); auto ch = static_cast<unsigned char>(*i);
pos++;
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<unsigned char>(*j);
*inserter++ = std::isprint(pc) ? static_cast<char>(*j) : '.';
}
}
put_newline(inserter, static_cast<size_t>(i - the_range.begin()));
// put first byte without delimiter in front of it // put first byte without delimiter in front of it
*inserter++ = hex_chars[(ch >> 4) & 0x0f]; *inserter++ = hex_chars[(ch >> 4) & 0x0f];
*inserter++ = hex_chars[ch & 0x0f]; *inserter++ = hex_chars[ch & 0x0f];
column += 2; start_of_line = i;
continue; continue;
} }
if (put_delimiters) if (put_delimiters)
{ {
*inserter++ = delimiter; *inserter++ = delimiter;
++column;
} }
*inserter++ = hex_chars[(ch >> 4) & 0x0f]; *inserter++ = hex_chars[(ch >> 4) & 0x0f];
*inserter++ = hex_chars[ch & 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<unsigned char>(*j);
*inserter++ = std::isprint(pc) ? static_cast<char>(*j) : '.';
}
} }
return inserter; return inserter;
} }
// put newline(and position header) // put newline(and position header)
// return the next column
template<typename It> template<typename It>
std::size_t put_newline(It inserter, std::size_t pos) void put_newline(It inserter, std::size_t pos)
{ {
#ifdef _WIN32 #ifdef _WIN32
*inserter++ = '\r'; *inserter++ = '\r';
@ -163,12 +209,7 @@ struct formatter<spdlog::details::bytes_range<T>>
if (put_positions) if (put_positions)
{ {
fmt::format_to(inserter, "{:<04X}: ", pos - 1); fmt::format_to(inserter, "{:<04X}: ", pos);
return 7;
}
else
{
return 1;
} }
} }
}; };

View File

@ -696,7 +696,7 @@ inline int to_nonnegative_int(T value, int upper) {
template <typename T, FMT_ENABLE_IF(std::is_integral<T>::value)> template <typename T, FMT_ENABLE_IF(std::is_integral<T>::value)>
inline T mod(T x, int y) { inline T mod(T x, int y) {
return x % y; return x % static_cast<T>(y);
} }
template <typename T, FMT_ENABLE_IF(std::is_floating_point<T>::value)> template <typename T, FMT_ENABLE_IF(std::is_floating_point<T>::value)>
inline T mod(T x, int y) { inline T mod(T x, int y) {
@ -793,7 +793,10 @@ struct chrono_formatter {
explicit chrono_formatter(FormatContext& ctx, OutputIt o, explicit chrono_formatter(FormatContext& ctx, OutputIt o,
std::chrono::duration<Rep, Period> d) std::chrono::duration<Rep, Period> d)
: context(ctx), out(o), val(d.count()), negative(false) { : context(ctx),
out(o),
val(static_cast<rep>(d.count())),
negative(false) {
if (d.count() < 0) { if (d.count() < 0) {
val = 0 - val; val = 0 - val;
negative = true; negative = true;
@ -1023,8 +1026,8 @@ struct formatter<std::chrono::duration<Rep, Period>, Char> {
void on_error(const char* msg) { FMT_THROW(format_error(msg)); } void on_error(const char* msg) { FMT_THROW(format_error(msg)); }
void on_fill(Char fill) { f.specs.fill[0] = fill; } void on_fill(Char fill) { f.specs.fill[0] = fill; }
void on_align(align_t align) { f.specs.align = align; } void on_align(align_t align) { f.specs.align = align; }
void on_width(unsigned width) { f.specs.width = width; } void on_width(int width) { f.specs.width = width; }
void on_precision(unsigned _precision) { f.precision = _precision; } void on_precision(int _precision) { f.precision = _precision; }
void end_precision() {} void end_precision() {}
template <typename Id> void on_dynamic_width(Id arg_id) { template <typename Id> void on_dynamic_width(Id arg_id) {

View File

@ -26,11 +26,11 @@ template <typename Char> struct format_part {
kind part_kind; kind part_kind;
union value { union value {
unsigned arg_index; int arg_index;
basic_string_view<Char> str; basic_string_view<Char> str;
replacement repl; 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<Char> s) : str(s) {} FMT_CONSTEXPR value(basic_string_view<Char> s) : str(s) {}
FMT_CONSTEXPR value(replacement r) : repl(r) {} FMT_CONSTEXPR value(replacement r) : repl(r) {}
} val; } val;
@ -40,7 +40,7 @@ template <typename Char> struct format_part {
FMT_CONSTEXPR format_part(kind k = kind::arg_index, value v = {}) FMT_CONSTEXPR format_part(kind k = kind::arg_index, value v = {})
: part_kind(k), val(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); return format_part(kind::arg_index, index);
} }
static FMT_CONSTEXPR format_part make_arg_name(basic_string_view<Char> name) { static FMT_CONSTEXPR format_part make_arg_name(basic_string_view<Char> name) {
@ -62,7 +62,7 @@ template <typename Char> struct part_counter {
} }
FMT_CONSTEXPR void on_arg_id() { ++num_parts; } 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<Char>) { ++num_parts; } FMT_CONSTEXPR void on_arg_id(basic_string_view<Char>) { ++num_parts; }
FMT_CONSTEXPR void on_replacement_field(const Char*) {} 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()); 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); parse_context_.check_arg_id(id);
part_ = part::make_arg_index(id); part_ = part::make_arg_index(id);
} }
@ -512,8 +512,6 @@ template <typename CompiledFormat, typename... Args,
CompiledFormat>::value)> CompiledFormat>::value)>
std::basic_string<Char> format(const CompiledFormat& cf, const Args&... args) { std::basic_string<Char> format(const CompiledFormat& cf, const Args&... args) {
basic_memory_buffer<Char> buffer; basic_memory_buffer<Char> buffer;
using range = buffer_range<Char>;
using context = buffer_context<Char>;
cf.format(std::back_inserter(buffer), args...); cf.format(std::back_inserter(buffer), args...);
return to_string(buffer); return to_string(buffer);
} }

View File

@ -15,7 +15,7 @@
#include <type_traits> #include <type_traits>
// The fmt library version in the form major * 10000 + minor * 100 + patch. // The fmt library version in the form major * 10000 + minor * 100 + patch.
#define FMT_VERSION 60101 #define FMT_VERSION 60102
#ifdef __has_feature #ifdef __has_feature
# define FMT_HAS_FEATURE(x) __has_feature(x) # define FMT_HAS_FEATURE(x) __has_feature(x)
@ -878,7 +878,7 @@ template <typename Context> struct arg_mapper {
FMT_ENABLE_IF( FMT_ENABLE_IF(
std::is_constructible<std_string_view<char_type>, T>::value && std::is_constructible<std_string_view<char_type>, T>::value &&
!std::is_constructible<basic_string_view<char_type>, T>::value && !std::is_constructible<basic_string_view<char_type>, T>::value &&
!is_string<T>::value)> !is_string<T>::value && !has_formatter<T, Context>::value)>
FMT_CONSTEXPR basic_string_view<char_type> map(const T& val) { FMT_CONSTEXPR basic_string_view<char_type> map(const T& val) {
return std_string_view<char_type>(val); return std_string_view<char_type>(val);
} }
@ -911,12 +911,14 @@ template <typename Context> struct arg_mapper {
map(static_cast<typename std::underlying_type<T>::type>(val))) { map(static_cast<typename std::underlying_type<T>::type>(val))) {
return map(static_cast<typename std::underlying_type<T>::type>(val)); return map(static_cast<typename std::underlying_type<T>::type>(val));
} }
template <typename T, template <
FMT_ENABLE_IF(!is_string<T>::value && !is_char<T>::value && typename T,
!std::is_constructible<basic_string_view<char_type>, FMT_ENABLE_IF(
T>::value && !is_string<T>::value && !is_char<T>::value &&
!std::is_constructible<basic_string_view<char_type>, T>::value &&
(has_formatter<T, Context>::value || (has_formatter<T, Context>::value ||
has_fallback_formatter<T, Context>::value))> (has_fallback_formatter<T, Context>::value &&
!std::is_constructible<std_string_view<char_type>, T>::value)))>
FMT_CONSTEXPR const T& map(const T& val) { FMT_CONSTEXPR const T& map(const T& val) {
return val; return val;
} }
@ -1283,7 +1285,7 @@ template <typename Context> class basic_format_args {
*/ */
template <typename... Args> template <typename... Args>
basic_format_args(const format_arg_store<Context, Args...>& store) basic_format_args(const format_arg_store<Context, Args...>& store)
: types_(static_cast<unsigned long long>(store.types)) { : types_(store.types) {
set_data(store.data_); set_data(store.data_);
} }

View File

@ -69,7 +69,8 @@
# define FMT_HAS_BUILTIN(x) 0 # define FMT_HAS_BUILTIN(x) 0
#endif #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]] # define FMT_FALLTHROUGH [[fallthrough]]
#else #else
# define FMT_FALLTHROUGH # define FMT_FALLTHROUGH
@ -801,60 +802,6 @@ template <> int count_digits<4>(internal::fallback_uintptr n);
# define FMT_ALWAYS_INLINE # define FMT_ALWAYS_INLINE
#endif #endif
// Computes g = floor(log10(n)) and calls h.on<g>(n);
template <typename Handler> 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 <unsigned N> char* on(uint32_t u) {
if (N == 0) {
*buffer_ = static_cast<char>(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<uint32_t>(t);
write_pair(i, t >> 32);
}
if (N % 2 == 0) {
buffer_[N] =
static_cast<char>((10ULL * static_cast<uint32_t>(t)) >> 32) + '0';
}
}
return buffer_ += N + 1;
}
};
#ifdef FMT_BUILTIN_CLZ #ifdef FMT_BUILTIN_CLZ
// Optional version of count_digits for better performance on 32-bit platforms. // Optional version of count_digits for better performance on 32-bit platforms.
inline int count_digits(uint32_t n) { inline int count_digits(uint32_t n) {
@ -2620,7 +2567,7 @@ class format_string_checker {
public: public:
explicit FMT_CONSTEXPR format_string_checker( explicit FMT_CONSTEXPR format_string_checker(
basic_string_view<Char> format_str, ErrorHandler eh) basic_string_view<Char> format_str, ErrorHandler eh)
: arg_id_(max_value<unsigned>()), : arg_id_(-1),
context_(format_str, eh), context_(format_str, eh),
parse_funcs_{&parse_format_specs<Args, parse_context_type>...} {} parse_funcs_{&parse_format_specs<Args, parse_context_type>...} {}
@ -2661,7 +2608,7 @@ class format_string_checker {
// Format specifier parsing function. // Format specifier parsing function.
using parse_func = const Char* (*)(parse_context_type&); using parse_func = const Char* (*)(parse_context_type&);
unsigned arg_id_; int arg_id_;
parse_context_type context_; parse_context_type context_;
parse_func parse_funcs_[num_args > 0 ? num_args : 1]; parse_func parse_funcs_[num_args > 0 ? num_args : 1];
}; };

View File

@ -333,12 +333,12 @@ template <typename OutputIt, typename Char> class basic_printf_context {
static void parse_flags(format_specs& specs, const Char*& it, static void parse_flags(format_specs& specs, const Char*& it,
const Char* end); const Char* end);
// Returns the argument with specified index or, if arg_index is equal // Returns the argument with specified index or, if arg_index is -1, the next
// to the maximum unsigned value, the next argument. // argument.
format_arg get_arg(unsigned arg_index = internal::max_value<unsigned>()); format_arg get_arg(int arg_index = -1);
// Parses argument index, flags and width and returns the argument index. // 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: public:
/** /**
@ -355,7 +355,7 @@ template <typename OutputIt, typename Char> class basic_printf_context {
OutputIt out() { return out_; } OutputIt out() { return out_; }
void advance_to(OutputIt it) { out_ = it; } 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<Char>& parse_context() { return parse_ctx_; } basic_format_parse_context<Char>& parse_context() { return parse_ctx_; }
@ -397,8 +397,8 @@ void basic_printf_context<OutputIt, Char>::parse_flags(format_specs& specs,
template <typename OutputIt, typename Char> template <typename OutputIt, typename Char>
typename basic_printf_context<OutputIt, Char>::format_arg typename basic_printf_context<OutputIt, Char>::format_arg
basic_printf_context<OutputIt, Char>::get_arg(unsigned arg_index) { basic_printf_context<OutputIt, Char>::get_arg(int arg_index) {
if (arg_index == internal::max_value<unsigned>()) if (arg_index < 0)
arg_index = parse_ctx_.next_arg_id(); arg_index = parse_ctx_.next_arg_id();
else else
parse_ctx_.check_arg_id(--arg_index); parse_ctx_.check_arg_id(--arg_index);
@ -406,15 +406,15 @@ basic_printf_context<OutputIt, Char>::get_arg(unsigned arg_index) {
} }
template <typename OutputIt, typename Char> template <typename OutputIt, typename Char>
unsigned basic_printf_context<OutputIt, Char>::parse_header( int basic_printf_context<OutputIt, Char>::parse_header(
const Char*& it, const Char* end, format_specs& specs) { const Char*& it, const Char* end, format_specs& specs) {
unsigned arg_index = internal::max_value<unsigned>(); int arg_index = -1;
char_type c = *it; char_type c = *it;
if (c >= '0' && c <= '9') { if (c >= '0' && c <= '9') {
// Parse an argument index (if followed by '$') or a width possibly // Parse an argument index (if followed by '$') or a width possibly
// preceded with '0' flag(s). // preceded with '0' flag(s).
internal::error_handler eh; 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 if (it != end && *it == '$') { // value is an argument index
++it; ++it;
arg_index = value; arg_index = value;
@ -436,8 +436,8 @@ unsigned basic_printf_context<OutputIt, Char>::parse_header(
specs.width = parse_nonnegative_int(it, end, eh); specs.width = parse_nonnegative_int(it, end, eh);
} else if (*it == '*') { } else if (*it == '*') {
++it; ++it;
specs.width = visit_format_arg( specs.width = static_cast<int>(visit_format_arg(
internal::printf_width_handler<char_type>(specs), get_arg()); internal::printf_width_handler<char_type>(specs), get_arg()));
} }
} }
return arg_index; return arg_index;
@ -464,7 +464,7 @@ OutputIt basic_printf_context<OutputIt, Char>::format() {
specs.align = align::right; specs.align = align::right;
// Parse argument index, flags and width. // 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"); if (arg_index == 0) on_error("argument index out of range");
// Parse precision. // Parse precision.
@ -473,11 +473,11 @@ OutputIt basic_printf_context<OutputIt, Char>::format() {
c = it != end ? *it : 0; c = it != end ? *it : 0;
if ('0' <= c && c <= '9') { if ('0' <= c && c <= '9') {
internal::error_handler eh; internal::error_handler eh;
specs.precision = static_cast<int>(parse_nonnegative_int(it, end, eh)); specs.precision = parse_nonnegative_int(it, end, eh);
} else if (c == '*') { } else if (c == '*') {
++it; ++it;
specs.precision = specs.precision =
visit_format_arg(internal::printf_precision_handler(), get_arg()); static_cast<int>(visit_format_arg(internal::printf_precision_handler(), get_arg()));
} else { } else {
specs.precision = 0; specs.precision = 0;
} }

View File

@ -10,30 +10,16 @@
// By default spdlog include its own copy. // 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) #if !defined(SPDLOG_FMT_EXTERNAL)
#ifdef SPDLOG_HEADER_ONLY #if !defined(SPDLOG_COMPILED_LIB) && !defined(FMT_HEADER_ONLY)
#ifndef FMT_HEADER_ONLY
#define FMT_HEADER_ONLY #define FMT_HEADER_ONLY
#endif #endif
#endif
#ifndef FMT_USE_WINDOWS_H #ifndef FMT_USE_WINDOWS_H
#define FMT_USE_WINDOWS_H 0 #define FMT_USE_WINDOWS_H 0
#endif #endif
#include "bundled/core.h" #include <spdlog/fmt/bundled/core.h>
#include "bundled/format.h" #include <spdlog/fmt/bundled/format.h>
#else // SPDLOG_FMT_EXTERNAL is defined - use external fmtlib #else // SPDLOG_FMT_EXTERNAL is defined - use external fmtlib
#include <fmt/core.h> #include <fmt/core.h>
#include <fmt/format.h> #include <fmt/format.h>
#endif #endif
// pop warnings supressions
#if defined(__GNUC__) || defined(__clang__)
#pragma GCC diagnostic pop
#endif

View File

@ -7,12 +7,14 @@
// //
// include bundled or external copy of fmtlib's ostream support // include bundled or external copy of fmtlib's ostream support
// //
#if !defined(SPDLOG_FMT_EXTERNAL) #if !defined(SPDLOG_FMT_EXTERNAL)
#ifdef SPDLOG_HEADER_ONLY
#ifndef FMT_HEADER_ONLY #ifndef FMT_HEADER_ONLY
#define FMT_HEADER_ONLY #define FMT_HEADER_ONLY
#endif #endif
#include "bundled/ostream.h" #endif
#include "fmt.h" #include <spdlog/fmt/bundled/ostream.h>
#else #else
#include <fmt/ostream.h> #include <fmt/ostream.h>
#endif #endif

14
third_party/spdlog/include/spdlog/fwd.h vendored Normal file
View File

@ -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

View File

@ -9,7 +9,7 @@
#include <spdlog/sinks/sink.h> #include <spdlog/sinks/sink.h>
#include <spdlog/details/backtracer.h> #include <spdlog/details/backtracer.h>
#include <spdlog/details/pattern_formatter.h> #include <spdlog/pattern_formatter.h>
#include <cstdio> #include <cstdio>
@ -89,6 +89,7 @@ SPDLOG_INLINE void logger::set_formatter(std::unique_ptr<formatter> f)
{ {
// last element - we can be move it. // last element - we can be move it.
(*it)->set_formatter(std::move(f)); (*it)->set_formatter(std::move(f));
break; // to prevent clang-tidy warning
} }
else else
{ {

View File

@ -39,7 +39,7 @@
namespace spdlog { namespace spdlog {
class logger class SPDLOG_API logger
{ {
public: public:
// Empty logger // Empty logger
@ -143,6 +143,11 @@ public:
// T can be statically converted to string_view // T can be statically converted to string_view
template<class T, typename std::enable_if<std::is_convertible<const T &, spdlog::string_view_t>::value, T>::type * = nullptr> template<class T, typename std::enable_if<std::is_convertible<const T &, spdlog::string_view_t>::value, T>::type * = nullptr>
void log(source_loc loc, level::level_enum lvl, const T &msg) 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 log_enabled = should_log(lvl);
bool traceback_enabled = tracer_.enabled(); bool traceback_enabled = tracer_.enabled();

View File

@ -4,7 +4,7 @@
#pragma once #pragma once
#ifndef SPDLOG_HEADER_ONLY #ifndef SPDLOG_HEADER_ONLY
#include <spdlog/details/pattern_formatter.h> #include <spdlog/pattern_formatter.h>
#endif #endif
#include <spdlog/details/fmt_helper.h> #include <spdlog/details/fmt_helper.h>
@ -90,7 +90,7 @@ struct null_scoped_padder
}; };
template<typename ScopedPadder> template<typename ScopedPadder>
class name_formatter : public flag_formatter class name_formatter final : public flag_formatter
{ {
public: public:
explicit name_formatter(padding_info padinfo) explicit name_formatter(padding_info padinfo)
@ -106,7 +106,7 @@ public:
// log level appender // log level appender
template<typename ScopedPadder> template<typename ScopedPadder>
class level_formatter : public flag_formatter class level_formatter final : public flag_formatter
{ {
public: public:
explicit level_formatter(padding_info padinfo) explicit level_formatter(padding_info padinfo)
@ -123,7 +123,7 @@ public:
// short log level appender // short log level appender
template<typename ScopedPadder> template<typename ScopedPadder>
class short_level_formatter : public flag_formatter class short_level_formatter final : public flag_formatter
{ {
public: public:
explicit short_level_formatter(padding_info padinfo) explicit short_level_formatter(padding_info padinfo)
@ -156,7 +156,7 @@ static int to12h(const tm &t)
static std::array<const char *, 7> days{{"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"}}; static std::array<const char *, 7> days{{"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"}};
template<typename ScopedPadder> template<typename ScopedPadder>
class a_formatter : public flag_formatter class a_formatter final : public flag_formatter
{ {
public: public:
explicit a_formatter(padding_info padinfo) explicit a_formatter(padding_info padinfo)
@ -194,7 +194,7 @@ public:
static const std::array<const char *, 12> months{{"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sept", "Oct", "Nov", "Dec"}}; static const std::array<const char *, 12> months{{"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sept", "Oct", "Nov", "Dec"}};
template<typename ScopedPadder> template<typename ScopedPadder>
class b_formatter : public flag_formatter class b_formatter final : public flag_formatter
{ {
public: public:
explicit b_formatter(padding_info padinfo) explicit b_formatter(padding_info padinfo)
@ -214,7 +214,7 @@ static const std::array<const char *, 12> full_months{
{"January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"}}; {"January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"}};
template<typename ScopedPadder> template<typename ScopedPadder>
class B_formatter : public flag_formatter class B_formatter final : public flag_formatter
{ {
public: public:
explicit B_formatter(padding_info padinfo) explicit B_formatter(padding_info padinfo)
@ -933,16 +933,15 @@ public:
dest.push_back(']'); dest.push_back(']');
dest.push_back(' '); dest.push_back(' ');
#ifndef SPDLOG_NO_NAME // append logger name if exists
if (msg.logger_name.size() > 0) if (msg.logger_name.size() > 0)
{ {
dest.push_back('['); dest.push_back('[');
// fmt_helper::append_str(*msg.logger_name, dest);
fmt_helper::append_string_view(msg.logger_name, dest); fmt_helper::append_string_view(msg.logger_name, dest);
dest.push_back(']'); dest.push_back(']');
dest.push_back(' '); dest.push_back(' ');
} }
#endif
dest.push_back('['); dest.push_back('[');
// wrap the level name with color // wrap the level name with color
msg.color_range_start = dest.size(); msg.color_range_start = dest.size();
@ -974,11 +973,13 @@ private:
} // namespace details } // 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)) : pattern_(std::move(pattern))
, eol_(std::move(eol)) , eol_(std::move(eol))
, pattern_time_type_(time_type) , pattern_time_type_(time_type)
, last_log_secs_(0) , last_log_secs_(0)
, custom_handlers_(std::move(custom_user_flags))
{ {
std::memset(&cached_tm_, 0, sizeof(cached_tm_)); std::memset(&cached_tm_, 0, sizeof(cached_tm_));
compile_pattern_(pattern_); compile_pattern_(pattern_);
@ -997,7 +998,12 @@ SPDLOG_INLINE pattern_formatter::pattern_formatter(pattern_time_type time_type,
SPDLOG_INLINE std::unique_ptr<formatter> pattern_formatter::clone() const SPDLOG_INLINE std::unique_ptr<formatter> pattern_formatter::clone() const
{ {
return details::make_unique<pattern_formatter>(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_formatter>(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) 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); 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) SPDLOG_INLINE std::tm pattern_formatter::get_time_(const details::log_msg &msg)
{ {
if (pattern_time_type_ == pattern_time_type::local) 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<typename Padder> template<typename Padder>
SPDLOG_INLINE void pattern_formatter::handle_flag_(char flag, details::padding_info padding) 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) switch (flag)
{ {
case ('+'): // default formatter case ('+'): // default formatter
formatters_.push_back(details::make_unique<details::full_formatter>(padding)); formatters_.push_back(details::make_unique<details::full_formatter>(padding));
break; break;

View File

@ -14,6 +14,7 @@
#include <string> #include <string>
#include <vector> #include <vector>
#include <unordered_map>
namespace spdlog { namespace spdlog {
namespace details { namespace details {
@ -40,13 +41,13 @@ struct padding_info
{ {
return enabled_; return enabled_;
} }
const size_t width_ = 0; size_t width_ = 0;
const pad_side side_ = left; pad_side side_ = left;
bool truncate_ = false; bool truncate_ = false;
bool enabled_ = false; bool enabled_ = false;
}; };
class flag_formatter class SPDLOG_API flag_formatter
{ {
public: public:
explicit flag_formatter(padding_info padinfo) explicit flag_formatter(padding_info padinfo)
@ -62,11 +63,24 @@ protected:
} // namespace details } // namespace details
class pattern_formatter final : public formatter class SPDLOG_API custom_flag_formatter : public details::flag_formatter
{ {
public: public:
explicit pattern_formatter( virtual std::unique_ptr<custom_flag_formatter> clone() const = 0;
std::string pattern, pattern_time_type time_type = pattern_time_type::local, std::string eol = spdlog::details::os::default_eol);
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<char, std::unique_ptr<custom_flag_formatter>>;
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 // 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); 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<formatter> clone() const override; std::unique_ptr<formatter> clone() const override;
void format(const details::log_msg &msg, memory_buf_t &dest) override; void format(const details::log_msg &msg, memory_buf_t &dest) override;
template<typename T, typename... Args>
pattern_formatter &add_flag(char flag, const Args &... args)
{
custom_handlers_[flag] = details::make_unique<T>(args...);
return *this;
}
void set_pattern(std::string pattern);
private: private:
std::string pattern_; std::string pattern_;
std::string eol_; std::string eol_;
@ -84,6 +106,7 @@ private:
std::tm cached_tm_; std::tm cached_tm_;
std::chrono::seconds last_log_secs_; std::chrono::seconds last_log_secs_;
std::vector<std::unique_ptr<details::flag_formatter>> formatters_; std::vector<std::unique_ptr<details::flag_formatter>> formatters_;
custom_flags custom_handlers_;
std::tm get_time_(const details::log_msg &msg); std::tm get_time_(const details::log_msg &msg);
template<typename Padder> template<typename Padder>
@ -92,7 +115,7 @@ private:
// Extract given pad spec (e.g. %8X) // Extract given pad spec (e.g. %8X)
// Advance the given it pass the end of the padding spec found (if any) // Advance the given it pass the end of the padding spec found (if any)
// Return padding. // 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); void compile_pattern_(const std::string &pattern);
}; };

View File

@ -64,7 +64,7 @@ protected:
if (ret < 0) if (ret < 0)
{ {
SPDLOG_THROW(spdlog_ex("__android_log_write() failed", ret)); throw_spdlog_ex("__android_log_write() failed", ret);
} }
} }

View File

@ -7,7 +7,7 @@
#include <spdlog/sinks/ansicolor_sink.h> #include <spdlog/sinks/ansicolor_sink.h>
#endif #endif
#include <spdlog/details/pattern_formatter.h> #include <spdlog/pattern_formatter.h>
#include <spdlog/details/os.h> #include <spdlog/details/os.h>
namespace spdlog { namespace spdlog {
@ -43,7 +43,8 @@ SPDLOG_INLINE void ansicolor_sink<ConsoleMutex>::log(const details::log_msg &msg
// Wrap the originally formatted message in color codes. // Wrap the originally formatted message in color codes.
// If color is not supported in the terminal, log as is instead. // If color is not supported in the terminal, log as is instead.
std::lock_guard<mutex_t> lock(mutex_); std::lock_guard<mutex_t> lock(mutex_);
msg.color_range_start = 0;
msg.color_range_end = 0;
memory_buf_t formatted; memory_buf_t formatted;
formatter_->format(msg, formatted); formatter_->format(msg, formatted);
if (should_do_colors_ && msg.color_range_end > msg.color_range_start) if (should_do_colors_ && msg.color_range_end > msg.color_range_start)
@ -111,7 +112,7 @@ SPDLOG_INLINE void ansicolor_sink<ConsoleMutex>::set_color_mode(color_mode mode)
template<typename ConsoleMutex> template<typename ConsoleMutex>
SPDLOG_INLINE void ansicolor_sink<ConsoleMutex>::print_ccode_(const string_view_t &color_code) SPDLOG_INLINE void ansicolor_sink<ConsoleMutex>::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<typename ConsoleMutex> template<typename ConsoleMutex>

View File

@ -9,7 +9,7 @@
#include <memory> #include <memory>
#include <mutex> #include <mutex>
#include <string> #include <string>
#include <unordered_map> #include <array>
namespace spdlog { namespace spdlog {
namespace sinks { namespace sinks {
@ -30,7 +30,11 @@ public:
~ansicolor_sink() override = default; ~ansicolor_sink() override = default;
ansicolor_sink(const ansicolor_sink &other) = delete; ansicolor_sink(const ansicolor_sink &other) = delete;
ansicolor_sink(ansicolor_sink &&other) = delete;
ansicolor_sink &operator=(const 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(level::level_enum color_level, string_view_t color);
void set_color_mode(color_mode mode); void set_color_mode(color_mode mode);
bool should_color(); bool should_color();
@ -80,7 +84,7 @@ private:
mutex_t &mutex_; mutex_t &mutex_;
bool should_do_colors_; bool should_do_colors_;
std::unique_ptr<spdlog::formatter> formatter_; std::unique_ptr<spdlog::formatter> formatter_;
std::unordered_map<level::level_enum, string_view_t, level::level_hasher> colors_; std::array<string_view_t, level::n_levels> colors_;
void print_ccode_(const string_view_t &color_code); void print_ccode_(const string_view_t &color_code);
void print_range_(const memory_buf_t &formatted, size_t start, size_t end); void print_range_(const memory_buf_t &formatted, size_t start, size_t end);
}; };

View File

@ -8,7 +8,7 @@
#endif #endif
#include <spdlog/common.h> #include <spdlog/common.h>
#include <spdlog/details/pattern_formatter.h> #include <spdlog/pattern_formatter.h>
#include <memory> #include <memory>

View File

@ -21,8 +21,14 @@ class base_sink : public sink
public: public:
base_sink(); base_sink();
explicit base_sink(std::unique_ptr<spdlog::formatter> formatter); explicit base_sink(std::unique_ptr<spdlog::formatter> formatter);
~base_sink() override = default;
base_sink(const base_sink &) = delete; base_sink(const base_sink &) = delete;
base_sink(base_sink &&) = delete;
base_sink &operator=(const 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 log(const details::log_msg &msg) final;
void flush() final; void flush() final;
void set_pattern(const std::string &pattern) final; void set_pattern(const std::string &pattern) final;

View File

@ -56,7 +56,7 @@ public:
{ {
if (rotation_hour < 0 || rotation_hour > 23 || rotation_minute < 0 || rotation_minute > 59) 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(); auto now = log_clock::now();
@ -66,13 +66,13 @@ public:
if (max_files_ > 0) if (max_files_ > 0)
{ {
filenames_q_ = details::circular_q<filename_t>(static_cast<size_t>(max_files_)); init_filenames_q_();
filenames_q_.push_back(std::move(filename));
} }
} }
const filename_t &filename() const filename_t filename()
{ {
std::lock_guard<Mutex> lock(base_sink<Mutex>::mutex_);
return file_helper_.filename(); return file_helper_.filename();
} }
@ -104,6 +104,29 @@ protected:
} }
private: private:
void init_filenames_q_()
{
using details::os::path_exists;
filenames_q_ = details::circular_q<filename_t>(static_cast<size_t>(max_files_));
std::vector<filename_t> 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) tm now_tm(log_clock::time_point tp)
{ {
time_t tnow = log_clock::to_time_t(tp); time_t tnow = log_clock::to_time_t(tp);
@ -141,7 +164,7 @@ private:
if (!ok) if (!ok)
{ {
filenames_q_.push_back(std::move(current_file)); 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)); filenames_q_.push_back(std::move(current_file));
@ -167,15 +190,15 @@ using daily_file_sink_st = daily_file_sink<details::null_mutex>;
// //
template<typename Factory = spdlog::synchronous_factory> template<typename Factory = spdlog::synchronous_factory>
inline std::shared_ptr<logger> daily_logger_mt( inline std::shared_ptr<logger> 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<sinks::daily_file_sink_mt>(logger_name, filename, hour, minute, truncate); return Factory::template create<sinks::daily_file_sink_mt>(logger_name, filename, hour, minute, truncate, max_files);
} }
template<typename Factory = spdlog::synchronous_factory> template<typename Factory = spdlog::synchronous_factory>
inline std::shared_ptr<logger> daily_logger_st( inline std::shared_ptr<logger> 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<sinks::daily_file_sink_st>(logger_name, filename, hour, minute, truncate); return Factory::template create<sinks::daily_file_sink_st>(logger_name, filename, hour, minute, truncate, max_files);
} }
} // namespace spdlog } // namespace spdlog

View File

@ -6,7 +6,7 @@
#include "base_sink.h" #include "base_sink.h"
#include <spdlog/details/log_msg.h> #include <spdlog/details/log_msg.h>
#include <spdlog/details/null_mutex.h> #include <spdlog/details/null_mutex.h>
#include <spdlog/details/pattern_formatter.h> #include <spdlog/pattern_formatter.h>
#include <algorithm> #include <algorithm>
#include <memory> #include <memory>

View File

@ -8,6 +8,7 @@
#include <spdlog/details/null_mutex.h> #include <spdlog/details/null_mutex.h>
#include <spdlog/sinks/base_sink.h> #include <spdlog/sinks/base_sink.h>
#include <spdlog/details/windows_include.h>
#include <winbase.h> #include <winbase.h>
#include <mutex> #include <mutex>

View File

@ -54,8 +54,9 @@ SPDLOG_INLINE filename_t rotating_file_sink<Mutex>::calc_filename(const filename
} }
template<typename Mutex> template<typename Mutex>
SPDLOG_INLINE const filename_t &rotating_file_sink<Mutex>::filename() const SPDLOG_INLINE filename_t rotating_file_sink<Mutex>::filename()
{ {
std::lock_guard<Mutex> lock(base_sink<Mutex>::mutex_);
return file_helper_.filename(); return file_helper_.filename();
} }
@ -99,18 +100,17 @@ SPDLOG_INLINE void rotating_file_sink<Mutex>::rotate_()
} }
filename_t target = calc_filename(base_filename_, i); 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. // if failed try again after a small delay.
// this is a workaround to a windows issue, where very high rotation // 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?). // rates can cause the rename to fail with permission denied (because of antivirus?).
details::os::sleep_for_millis(100); 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! file_helper_.reopen(true); // truncate the log file anyway to prevent it to grow beyond its limit!
current_size_ = 0; current_size_ = 0;
SPDLOG_THROW( throw_spdlog_ex("rotating_file_sink: failed renaming " + filename_to_str(src) + " to " + filename_to_str(target), errno);
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<Mutex>::rotate_()
// delete the target if exists, and rename the src file to target // delete the target if exists, and rename the src file to target
// return true on success, false otherwise. // return true on success, false otherwise.
template<typename Mutex> template<typename Mutex>
SPDLOG_INLINE bool rotating_file_sink<Mutex>::rename_file(const filename_t &src_filename, const filename_t &target_filename) SPDLOG_INLINE bool rotating_file_sink<Mutex>::rename_file_(const filename_t &src_filename, const filename_t &target_filename)
{ {
// try to delete the target file in case it already exists. // try to delete the target file in case it already exists.
(void)details::os::remove(target_filename); (void)details::os::remove(target_filename);

View File

@ -24,7 +24,7 @@ class rotating_file_sink final : public base_sink<Mutex>
public: public:
rotating_file_sink(filename_t base_filename, std::size_t max_size, std::size_t max_files, bool rotate_on_open = false); 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); static filename_t calc_filename(const filename_t &filename, std::size_t index);
const filename_t &filename() const; filename_t filename();
protected: protected:
void sink_it_(const details::log_msg &msg) override; 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 // delete the target if exists, and rename the src file to target
// return true on success, false otherwise. // 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_; filename_t base_filename_;
std::size_t max_size_; std::size_t max_size_;

View File

@ -9,7 +9,7 @@
namespace spdlog { namespace spdlog {
namespace sinks { namespace sinks {
class sink class SPDLOG_API sink
{ {
public: public:
virtual ~sink() = default; virtual ~sink() = default;

View File

@ -8,7 +8,7 @@
#endif #endif
#include <spdlog/details/console_globals.h> #include <spdlog/details/console_globals.h>
#include <spdlog/details/pattern_formatter.h> #include <spdlog/pattern_formatter.h>
#include <memory> #include <memory>
namespace spdlog { namespace spdlog {

View File

@ -19,8 +19,12 @@ public:
using mutex_t = typename ConsoleMutex::mutex_t; using mutex_t = typename ConsoleMutex::mutex_t;
explicit stdout_sink_base(FILE *file); explicit stdout_sink_base(FILE *file);
~stdout_sink_base() override = default; ~stdout_sink_base() override = default;
stdout_sink_base(const stdout_sink_base &other) = delete; 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=(const stdout_sink_base &other) = delete;
stdout_sink_base &operator=(stdout_sink_base &&other) = delete;
void log(const details::log_msg &msg) override; void log(const details::log_msg &msg) override;
void flush() override; void flush() override;

View File

@ -72,7 +72,7 @@ protected:
if (err) if (err)
{ {
SPDLOG_THROW(spdlog_ex("Failed writing to systemd", errno)); throw_spdlog_ex("Failed writing to systemd", errno);
} }
} }

View File

@ -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 <spdlog/common.h>
#include <spdlog/sinks/base_sink.h>
#include <spdlog/details/null_mutex.h>
#ifdef _WIN32
#include <spdlog/details/tcp_client-windows.h>
#else
#include <spdlog/details/tcp_client.h>
#endif
#include <mutex>
#include <string>
#include <chrono>
#include <functional>
#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<typename Mutex>
class tcp_sink : public spdlog::sinks::base_sink<Mutex>
{
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<Mutex>::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<std::mutex>;
using tcp_sink_st = tcp_sink<spdlog::details::null_mutex>;
} // namespace sinks
} // namespace spdlog

View File

@ -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. <log_name> should be replaced with your log name (e.g. your application name)
// 2. <source_name> 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\<log_name>]
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\EventLog\<log_name>\<source_name>]
"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 <spdlog/details/null_mutex.h>
#include <spdlog/sinks/base_sink.h>
#include <spdlog/details/windows_include.h>
#include <winbase.h>
#include <mutex>
#include <string>
#include <vector>
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<char> 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<unsigned char> buffer(static_cast<size_t>(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<typename Mutex>
class win_eventlog_sink : public base_sink<Mutex>
{
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<Mutex>::formatter_->format(msg, formatted);
formatted.push_back('\0');
LPCSTR lp_str = static_cast<LPCSTR>(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<std::mutex>;
using win_eventlog_sink_st = win_eventlog::win_eventlog_sink<details::null_mutex>;
} // namespace sinks
} // namespace spdlog

View File

@ -8,7 +8,7 @@
#endif #endif
#include <spdlog/common.h> #include <spdlog/common.h>
#include <spdlog/details/pattern_formatter.h> #include <spdlog/pattern_formatter.h>
namespace spdlog { namespace spdlog {
namespace sinks { namespace sinks {
@ -52,6 +52,8 @@ template<typename ConsoleMutex>
void SPDLOG_INLINE wincolor_sink<ConsoleMutex>::log(const details::log_msg &msg) void SPDLOG_INLINE wincolor_sink<ConsoleMutex>::log(const details::log_msg &msg)
{ {
std::lock_guard<mutex_t> lock(mutex_); std::lock_guard<mutex_t> lock(mutex_);
msg.color_range_start = 0;
msg.color_range_end = 0;
memory_buf_t formatted; memory_buf_t formatted;
formatter_->format(msg, formatted); formatter_->format(msg, formatted);
if (!in_console_) if (!in_console_)
@ -59,7 +61,6 @@ void SPDLOG_INLINE wincolor_sink<ConsoleMutex>::log(const details::log_msg &msg)
write_to_file_(formatted); write_to_file_(formatted);
return; return;
} }
if (should_do_colors_ && msg.color_range_end > msg.color_range_start) if (should_do_colors_ && msg.color_range_end > msg.color_range_start)
{ {
// before color range // before color range
@ -157,7 +158,7 @@ void SPDLOG_INLINE wincolor_sink<ConsoleMutex>::write_to_file_(const memory_buf_
bool ok = ::WriteFile(out_handle_, formatted.data() + total_written, size - total_written, &bytes_written, nullptr) != 0; bool ok = ::WriteFile(out_handle_, formatted.data() + total_written, size - total_written, &bytes_written, nullptr) != 0;
if (!ok || bytes_written == 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; total_written += bytes_written;
} while (total_written < size); } while (total_written < size);

View File

@ -11,7 +11,9 @@
#include <memory> #include <memory>
#include <mutex> #include <mutex>
#include <string> #include <string>
#include <unordered_map> #include <array>
#include <spdlog/details/windows_include.h>
#include <wincon.h> #include <wincon.h>
namespace spdlog { namespace spdlog {
@ -52,7 +54,7 @@ protected:
bool in_console_; bool in_console_;
bool should_do_colors_; bool should_do_colors_;
std::unique_ptr<spdlog::formatter> formatter_; std::unique_ptr<spdlog::formatter> formatter_;
std::unordered_map<level::level_enum, WORD, level::level_hasher> colors_; std::array<WORD, level::n_levels> colors_;
// set foreground color and return the orig console attributes (for resetting later) // set foreground color and return the orig console attributes (for resetting later)
WORD set_foreground_color_(WORD attribs); WORD set_foreground_color_(WORD attribs);

View File

@ -8,7 +8,7 @@
#endif #endif
#include <spdlog/common.h> #include <spdlog/common.h>
#include <spdlog/details/pattern_formatter.h> #include <spdlog/pattern_formatter.h>
namespace spdlog { namespace spdlog {

View File

@ -39,68 +39,66 @@ inline std::shared_ptr<spdlog::logger> create(std::string logger_name, SinkArgs
// Initialize and register a logger, // Initialize and register a logger,
// formatter and flush level will be set according the global settings. // formatter and flush level will be set according the global settings.
// //
// NOTE: // Useful for initializing manually created loggers with the global settings.
// Use this function when creating loggers manually.
// //
// Example: // Example:
// auto console_sink = std::make_shared<spdlog::sinks::stdout_sink_mt>(); // auto mylogger = std::make_shared<spdlog::logger>("mylogger", ...);
// auto console_logger = std::make_shared<spdlog::logger>("console_logger", console_sink); // spdlog::initialize_logger(mylogger);
// spdlog::initialize_logger(console_logger); SPDLOG_API void initialize_logger(std::shared_ptr<logger> logger);
void initialize_logger(std::shared_ptr<logger> logger);
// Return an existing logger or nullptr if a logger with such name doesn't // Return an existing logger or nullptr if a logger with such name doesn't
// exist. // exist.
// example: spdlog::get("my_logger")->info("hello {}", "world"); // example: spdlog::get("my_logger")->info("hello {}", "world");
std::shared_ptr<logger> get(const std::string &name); SPDLOG_API std::shared_ptr<logger> get(const std::string &name);
// Set global formatter. Each sink in each logger will get a clone of this object // Set global formatter. Each sink in each logger will get a clone of this object
void set_formatter(std::unique_ptr<spdlog::formatter> formatter); SPDLOG_API void set_formatter(std::unique_ptr<spdlog::formatter> formatter);
// Set global format string. // Set global format string.
// example: spdlog::set_pattern("%Y-%m-%d %H:%M:%S.%e %l : %v"); // 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 // enable global backtrace support
void enable_backtrace(size_t n_messages); SPDLOG_API void enable_backtrace(size_t n_messages);
// disable global backtrace support // disable global backtrace support
void disable_backtrace(); SPDLOG_API void disable_backtrace();
// call dump backtrace on default logger // call dump backtrace on default logger
void dump_backtrace(); SPDLOG_API void dump_backtrace();
// Set global logging level // 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 // 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 // Start/Restart a periodic flusher thread
// Warning: Use only if all your loggers are thread safe! // 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 // 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 // Register the given logger with the given name
void register_logger(std::shared_ptr<logger> logger); SPDLOG_API void register_logger(std::shared_ptr<logger> logger);
// Apply a user defined function on all registered loggers // Apply a user defined function on all registered loggers
// Example: // Example:
// spdlog::apply_all([&](std::shared_ptr<spdlog::logger> l) {l->flush();}); // spdlog::apply_all([&](std::shared_ptr<spdlog::logger> l) {l->flush();});
void apply_all(const std::function<void(std::shared_ptr<logger>)> &fun); SPDLOG_API void apply_all(const std::function<void(std::shared_ptr<logger>)> &fun);
// Drop the reference to the given logger // 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 // 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 // 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 // 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), // API for using default logger (stdout_color_mt),
// e.g: spdlog::info("Message {}", 1); // 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. // 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. // e.g do not call set_default_logger() from one thread while calling spdlog::info() from another.
std::shared_ptr<spdlog::logger> default_logger(); SPDLOG_API std::shared_ptr<spdlog::logger> default_logger();
spdlog::logger *default_logger_raw(); SPDLOG_API spdlog::logger *default_logger_raw();
void set_default_logger(std::shared_ptr<spdlog::logger> default_logger); SPDLOG_API void set_default_logger(std::shared_ptr<spdlog::logger> default_logger);
template<typename... Args> template<typename... Args>
inline void log(source_loc source, level::level_enum lvl, string_view_t fmt, const Args &... args) inline void log(source_loc source, level::level_enum lvl, string_view_t fmt, const Args &... args)

View File

@ -24,7 +24,7 @@
// This will prevent spdlog from querying the thread id on each log call. // 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 // 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 // #define SPDLOG_NO_THREAD_ID
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
@ -38,13 +38,6 @@
// #define SPDLOG_NO_TLS // #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 // Uncomment to avoid spdlog's usage of atomic log levels
// Use only if your code never modifies a logger's log levels concurrently by // Use only if your code never modifies a logger's log levels concurrently by

View File

@ -4,7 +4,7 @@
#pragma once #pragma once
#define SPDLOG_VER_MAJOR 1 #define SPDLOG_VER_MAJOR 1
#define SPDLOG_VER_MINOR 5 #define SPDLOG_VER_MINOR 6
#define SPDLOG_VER_PATCH 0 #define SPDLOG_VER_PATCH 0
#define SPDLOG_VERSION (SPDLOG_VER_MAJOR * 10000 + SPDLOG_VER_MINOR * 100 + SPDLOG_VER_PATCH) #define SPDLOG_VERSION (SPDLOG_VER_MAJOR * 10000 + SPDLOG_VER_MINOR * 100 + SPDLOG_VER_PATCH)

View File

@ -0,0 +1,43 @@
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="263" height="147" viewBox="0 0 263 147">
<defs>
<linearGradient id="linear-gradient" x1="54.4568" y1="122.5936" x2="251.779" y2="10.2057" gradientUnits="userSpaceOnUse">
<stop offset="0" stop-color="#00adee"/>
<stop offset="1" stop-color="#9f76a6"/>
</linearGradient>
<linearGradient id="linear-gradient-2" x1="80.247" y1="38.7607" x2="241.2622" y2="10.9511" gradientUnits="userSpaceOnUse">
<stop offset="0" stop-color="#ec037c"/>
<stop offset="1" stop-color="#9f76a6"/>
</linearGradient>
<linearGradient id="linear-gradient-3" x1="75.7205" y1="33.5582" x2="127.8253" y2="123.9392" gradientUnits="userSpaceOnUse">
<stop offset="0" stop-color="#ec037c"/>
<stop offset="1" stop-color="#5c2d90"/>
</linearGradient>
<linearGradient id="linear-gradient-4" x1="7.4647" y1="44.578" x2="129.4543" y2="125.0813" gradientUnits="userSpaceOnUse">
<stop offset="0" stop-color="#44c7f4"/>
<stop offset="1" stop-color="#5c2d90"/>
</linearGradient>
</defs>
<g>
<path d="M261.1839,10.3622a9.6784,9.6784,0,0,0-14.7448-8.2463l0-.0006L20.6942,136.0746h0a4.6974,4.6974,0,1,0,4.1326,8.4348h0q0.09-.0467.1784-0.097l230.5273-125.25a9.653,9.653,0,0,0,1.1508-.6253l0.0332-.018-0.0014-.0023A9.6682,9.6682,0,0,0,261.1839,10.3622Z" fill="url(#linear-gradient)"/>
<path d="M261.1839,10.3622A9.6782,9.6782,0,0,0,251.5057.684q-0.2747,0-.5456.0157-0.25.0143-.4975,0.041L76.7981,25.4187A13.7347,13.7347,0,1,0,83.5355,51.983L252.8044,19.9512a9.6363,9.6363,0,0,0,1.0358-.196l0.02-.0039,0-.0008A9.6811,9.6811,0,0,0,261.1839,10.3622Z" fill="url(#linear-gradient-2)"/>
<path d="M145.2028,123.63a17.2372,17.2372,0,0,0-3.0637-9.4254L91.3045,32.3521A13.7366,13.7366,0,0,0,66.1132,42.9507h0a13.6332,13.6332,0,0,0,1.043,2.4984s45.2334,86.37,45.5824,86.9979q0.3089,0.556.6567,1.0861h0A17.32,17.32,0,0,0,145.2028,123.63Z" fill="url(#linear-gradient-3)"/>
<path d="M145.2028,123.63a17.2979,17.2979,0,0,0-7.63-13.9419h0a17.3061,17.3061,0,0,0-2.6994-1.4911L9.5484,38.9679a6.064,6.064,0,0,0-6.5074,10.187l114.3963,88.704A17.3191,17.3191,0,0,0,145.2028,123.63Z" fill="url(#linear-gradient-4)"/>
<g>
<rect x="69" y="51" width="70" height="70"/>
<g>
<rect x="75.038" y="107.8746" width="26.2498" height="4.375" fill="#fff"/>
<g>
<path d="M74.7429,69.4315L76.78,67.5082a2.31,2.31,0,0,0,1.7929,1.0594A1.33,1.33,0,0,0,79.8607,66.97V59.75h3.1456v7.2366a4.2386,4.2386,0,0,1-1.1246,3.2108,4.2989,4.2989,0,0,1-3.1293,1.1572A4.6592,4.6592,0,0,1,74.7429,69.4315Z" fill="#fff"/>
<path d="M83.7394,59.75h9.1761v2.673H86.8688v1.744H92.345v2.4937H86.8688V68.47H92.997v2.6893H83.7394V59.75Z" fill="#fff"/>
<path d="M97.049,62.5208H93.6426V59.75h9.9911v2.7708h-3.4227v8.6383H97.049V62.5208Z" fill="#fff"/>
<path d="M75.0363,73.8257h5.8511A4.2728,4.2728,0,0,1,84,74.8363a2.5675,2.5675,0,0,1,.7335,1.858v0.0326a2.6407,2.6407,0,0,1-1.76,2.5425,2.7686,2.7686,0,0,1,2.2655,2.7871v0.0326c0,1.9558-1.5973,3.1456-4.3191,3.1456H75.0363V73.8257Zm6.5846,3.5206c0-.6357-0.5052-0.9779-1.4343-0.9779h-2.07v2.0047h1.9884c0.9616,0,1.5158-.326,1.5158-0.9942V77.3463ZM80.5289,80.59H78.1166v2.1025h2.4448c0.9779,0,1.5158-.3749,1.5158-1.0431V81.6165C82.0773,80.9972,81.5883,80.59,80.5289,80.59Z" fill="#fff"/>
<path d="M85.7116,73.8257h5.3949a5.0512,5.0512,0,0,1,3.7161,1.2224,3.5623,3.5623,0,0,1,1.01,2.6567v0.0326a3.6146,3.6146,0,0,1-2.3469,3.5205l2.7218,3.9769H92.5733l-2.2981-3.4553H88.8735v3.4553H85.7116V73.8257Zm5.2644,5.4764a1.433,1.433,0,0,0,1.6951-1.3528V77.9167c0-.9128-0.6682-1.3691-1.7114-1.3691H88.8735v2.7545H90.976Z" fill="#fff"/>
<path d="M99.5324,73.7443H102.58l4.8571,11.4905h-3.39l-0.815-2.0536H98.8153L98,85.2348H94.6917Zm2.7707,6.9758-1.2712-3.2271L99.7443,80.72h2.5589Z" fill="#fff"/>
<path d="M107.8117,73.8257h3.1619V85.2348h-3.1619V73.8257Z" fill="#fff"/>
<path d="M111.7558,73.8257h2.95l4.694,6.0306V73.8257h3.1294V85.2348h-2.7545l-4.89-6.2587v6.2587h-3.1293V73.8257Z" fill="#fff"/>
<path d="M122.7274,83.54l1.76-2.1025a5.9106,5.9106,0,0,0,3.7,1.3691c0.8638,0,1.32-.2934,1.32-0.7824V81.9914c0-.489-0.3749-0.7335-1.9395-1.1084-2.4285-.5541-4.3029-1.2387-4.3029-3.5694V77.2811c0-2.1188,1.6788-3.6509,4.417-3.6509a7.1807,7.1807,0,0,1,4.694,1.5158l-1.5809,2.2329a5.6006,5.6006,0,0,0-3.1946-1.1246c-0.766,0-1.1409.31-1.1409,0.7334V77.02c0,0.5216.3912,0.75,1.9884,1.1083,2.6077,0.57,4.2377,1.418,4.2377,3.5531v0.0326c0,2.3307-1.8418,3.7161-4.6126,3.7161A7.9992,7.9992,0,0,1,122.7274,83.54Z" fill="#fff"/>
</g>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 4.6 KiB

View File

@ -23,7 +23,7 @@ if get_option('external_fmt')
if not meson.version().version_compare('>=0.49.0') if not meson.version().version_compare('>=0.49.0')
warning('Finding fmt can fail with meson versions before 0.49.0') warning('Finding fmt can fail with meson versions before 0.49.0')
endif endif
dep_list += dependency('fmt') dep_list += dependency('fmt', fallback : ['fmt', 'fmt_dep'])
compile_args += '-DSPDLOG_FMT_EXTERNAL' compile_args += '-DSPDLOG_FMT_EXTERNAL'
endif endif
@ -82,7 +82,8 @@ spdlog_srcs = files([
'src/color_sinks.cpp', 'src/color_sinks.cpp',
'src/file_sinks.cpp', 'src/file_sinks.cpp',
'src/spdlog.cpp', 'src/spdlog.cpp',
'src/stdout_sinks.cpp' 'src/stdout_sinks.cpp',
'src/cfg.cpp'
]) ])
if not get_option('external_fmt') if not get_option('external_fmt')
@ -148,7 +149,7 @@ endif
# --- Conditionally add subdirs --- # --- 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') subdir('tests')
endif endif

View File

@ -1,5 +0,0 @@
#!/bin/bash
cd "$(dirname "$0")"
clang-tidy ../example/example.cpp -- -I ../include

View File

@ -1,12 +1,12 @@
#!/bin/bash #!/bin/bash
cd "$(dirname "$0")" cd "$(dirname "$0")"/..
pwd
echo -n "Running dos2unix " 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
echo -n "Running clang-format " 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 echo

View File

@ -5,8 +5,9 @@
#error Please define SPDLOG_COMPILED_LIB to compile this file. #error Please define SPDLOG_COMPILED_LIB to compile this file.
#endif #endif
#include "spdlog/async.h" #include <spdlog/async.h>
#include "spdlog/async_logger-inl.h" #include <spdlog/async_logger-inl.h>
#include "spdlog/details/periodic_worker-inl.h" #include <spdlog/details/periodic_worker-inl.h>
#include "spdlog/details/thread_pool-inl.h" #include <spdlog/details/thread_pool-inl.h>
template class spdlog::details::mpmc_blocking_queue<spdlog::details::async_msg>;
template class SPDLOG_API spdlog::details::mpmc_blocking_queue<spdlog::details::async_msg>;

8
third_party/spdlog/src/cfg.cpp vendored Normal file
View File

@ -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 <spdlog/cfg/helpers-inl.h>

View File

@ -7,19 +7,19 @@
#include <mutex> #include <mutex>
#include "spdlog/details/null_mutex.h" #include <spdlog/details/null_mutex.h>
#include "spdlog/async.h" #include <spdlog/async.h>
// //
// color sinks // color sinks
// //
#ifdef _WIN32 #ifdef _WIN32
#include "spdlog/sinks/wincolor_sink-inl.h" #include <spdlog/sinks/wincolor_sink-inl.h>
template class spdlog::sinks::wincolor_sink<spdlog::details::console_mutex>; template class SPDLOG_API spdlog::sinks::wincolor_sink<spdlog::details::console_mutex>;
template class spdlog::sinks::wincolor_sink<spdlog::details::console_nullmutex>; template class SPDLOG_API spdlog::sinks::wincolor_sink<spdlog::details::console_nullmutex>;
template class spdlog::sinks::wincolor_stdout_sink<spdlog::details::console_mutex>; template class SPDLOG_API spdlog::sinks::wincolor_stdout_sink<spdlog::details::console_mutex>;
template class spdlog::sinks::wincolor_stdout_sink<spdlog::details::console_nullmutex>; template class SPDLOG_API spdlog::sinks::wincolor_stdout_sink<spdlog::details::console_nullmutex>;
template class spdlog::sinks::wincolor_stderr_sink<spdlog::details::console_mutex>; template class SPDLOG_API spdlog::sinks::wincolor_stderr_sink<spdlog::details::console_mutex>;
template class spdlog::sinks::wincolor_stderr_sink<spdlog::details::console_nullmutex>; template class SPDLOG_API spdlog::sinks::wincolor_stderr_sink<spdlog::details::console_nullmutex>;
#else #else
#include "spdlog/sinks/ansicolor_sink-inl.h" #include "spdlog/sinks/ansicolor_sink-inl.h"
template class spdlog::sinks::ansicolor_sink<spdlog::details::console_mutex>; template class spdlog::sinks::ansicolor_sink<spdlog::details::console_mutex>;
@ -32,16 +32,20 @@ template class spdlog::sinks::ansicolor_stderr_sink<spdlog::details::console_nul
// factory methods for color loggers // factory methods for color loggers
#include "spdlog/sinks/stdout_color_sinks-inl.h" #include "spdlog/sinks/stdout_color_sinks-inl.h"
template std::shared_ptr<spdlog::logger> spdlog::stdout_color_mt<spdlog::synchronous_factory>( template SPDLOG_API std::shared_ptr<spdlog::logger> spdlog::stdout_color_mt<spdlog::synchronous_factory>(
const std::string &logger_name, color_mode mode); const std::string &logger_name, color_mode mode);
template std::shared_ptr<spdlog::logger> spdlog::stdout_color_st<spdlog::synchronous_factory>( template SPDLOG_API std::shared_ptr<spdlog::logger> spdlog::stdout_color_st<spdlog::synchronous_factory>(
const std::string &logger_name, color_mode mode); const std::string &logger_name, color_mode mode);
template std::shared_ptr<spdlog::logger> spdlog::stderr_color_mt<spdlog::synchronous_factory>( template SPDLOG_API std::shared_ptr<spdlog::logger> spdlog::stderr_color_mt<spdlog::synchronous_factory>(
const std::string &logger_name, color_mode mode); const std::string &logger_name, color_mode mode);
template std::shared_ptr<spdlog::logger> spdlog::stderr_color_st<spdlog::synchronous_factory>( template SPDLOG_API std::shared_ptr<spdlog::logger> spdlog::stderr_color_st<spdlog::synchronous_factory>(
const std::string &logger_name, color_mode mode); const std::string &logger_name, color_mode mode);
template std::shared_ptr<spdlog::logger> spdlog::stdout_color_mt<spdlog::async_factory>(const std::string &logger_name, color_mode mode); template SPDLOG_API std::shared_ptr<spdlog::logger> spdlog::stdout_color_mt<spdlog::async_factory>(
template std::shared_ptr<spdlog::logger> spdlog::stdout_color_st<spdlog::async_factory>(const std::string &logger_name, color_mode mode); const std::string &logger_name, color_mode mode);
template std::shared_ptr<spdlog::logger> spdlog::stderr_color_mt<spdlog::async_factory>(const std::string &logger_name, color_mode mode); template SPDLOG_API std::shared_ptr<spdlog::logger> spdlog::stdout_color_st<spdlog::async_factory>(
template std::shared_ptr<spdlog::logger> spdlog::stderr_color_st<spdlog::async_factory>(const std::string &logger_name, color_mode mode); const std::string &logger_name, color_mode mode);
template SPDLOG_API std::shared_ptr<spdlog::logger> spdlog::stderr_color_mt<spdlog::async_factory>(
const std::string &logger_name, color_mode mode);
template SPDLOG_API std::shared_ptr<spdlog::logger> spdlog::stderr_color_st<spdlog::async_factory>(
const std::string &logger_name, color_mode mode);

View File

@ -5,14 +5,16 @@
#error Please define SPDLOG_COMPILED_LIB to compile this file. #error Please define SPDLOG_COMPILED_LIB to compile this file.
#endif #endif
#include <spdlog/details/null_mutex.h>
#include <spdlog/details/file_helper-inl.h>
#include <spdlog/sinks/basic_file_sink-inl.h>
#include <spdlog/sinks/base_sink-inl.h>
#include <mutex> #include <mutex>
#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<std::mutex>; template class SPDLOG_API spdlog::sinks::basic_file_sink<std::mutex>;
template class spdlog::sinks::basic_file_sink<spdlog::details::null_mutex>; template class SPDLOG_API spdlog::sinks::basic_file_sink<spdlog::details::null_mutex>;
#include "spdlog/sinks/rotating_file_sink-inl.h" #include <spdlog/sinks/rotating_file_sink-inl.h>
template class spdlog::sinks::rotating_file_sink<std::mutex>; template class SPDLOG_API spdlog::sinks::rotating_file_sink<std::mutex>;
template class spdlog::sinks::rotating_file_sink<spdlog::details::null_mutex>; template class SPDLOG_API spdlog::sinks::rotating_file_sink<spdlog::details::null_mutex>;

View File

@ -6,29 +6,150 @@
// Copyright (c) 2012 - 2016, Victor Zverovich // Copyright (c) 2012 - 2016, Victor Zverovich
// All rights reserved. // 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) #if !defined(SPDLOG_FMT_EXTERNAL)
#include "spdlog/fmt/bundled/format-inl.h" #include <spdlog/fmt/bundled/format-inl.h>
// pop warnings supressions
#if defined(__GNUC__) || defined(__clang__)
#pragma GCC diagnostic pop
#endif
FMT_BEGIN_NAMESPACE FMT_BEGIN_NAMESPACE
namespace internal {
template<typename T>
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<typename Char>
constexpr sprintf_specs(basic_format_specs<Char> 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<typename Double>
char *sprintf_format(Double value, internal::buffer<char> &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<Double, long double>::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<unsigned>(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<char> &, sprintf_specs);
template FMT_API char *internal::sprintf_format(long double, internal::buffer<char> &, sprintf_specs);
template struct FMT_API internal::basic_data<void>; template struct FMT_API internal::basic_data<void>;
// Workaround a bug in MSVC2013 that prevents instantiation of format_float. // Workaround a bug in MSVC2013 that prevents instantiation of format_float.
int (*instantiate_format_float)(double, int, internal::float_specs, int (*instantiate_format_float)(double, int, internal::float_specs, internal::buffer<char> &) = internal::format_float;
internal::buffer<char>&) =
internal::format_float;
#ifndef FMT_STATIC_THOUSANDS_SEPARATOR #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);
@ -43,26 +164,16 @@ template FMT_API char internal::decimal_point_impl(locale_ref);
template FMT_API void internal::buffer<char>::append(const char *, const char *); template FMT_API void internal::buffer<char>::append(const char *, const char *);
template FMT_API void internal::arg_map<format_context>::init( template FMT_API void internal::arg_map<format_context>::init(const basic_format_args<format_context> &args);
const basic_format_args<format_context>& args);
template FMT_API std::string internal::vformat<char>( template FMT_API std::string internal::vformat<char>(string_view, basic_format_args<format_context>);
string_view, basic_format_args<format_context>);
template FMT_API format_context::iterator internal::vformat_to( template FMT_API format_context::iterator internal::vformat_to(internal::buffer<char> &, string_view, basic_format_args<format_context>);
internal::buffer<char>&, string_view, basic_format_args<format_context>);
template FMT_API int internal::snprintf_float(double, int, template FMT_API int internal::snprintf_float(double, int, internal::float_specs, internal::buffer<char> &);
internal::float_specs, template FMT_API int internal::snprintf_float(long double, int, internal::float_specs, internal::buffer<char> &);
internal::buffer<char>&); template FMT_API int internal::format_float(double, int, internal::float_specs, internal::buffer<char> &);
template FMT_API int internal::snprintf_float(long double, int, template FMT_API int internal::format_float(long double, int, internal::float_specs, internal::buffer<char> &);
internal::float_specs,
internal::buffer<char>&);
template FMT_API int internal::format_float(double, int, internal::float_specs,
internal::buffer<char>&);
template FMT_API int internal::format_float(long double, int,
internal::float_specs,
internal::buffer<char>&);
// Explicit instantiations for wchar_t. // Explicit instantiations for wchar_t.
@ -70,11 +181,9 @@ template FMT_API std::string internal::grouping_impl<wchar_t>(locale_ref);
template FMT_API wchar_t internal::thousands_sep_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 wchar_t internal::decimal_point_impl(locale_ref);
template FMT_API void internal::buffer<wchar_t>::append(const wchar_t*, template FMT_API void internal::buffer<wchar_t>::append(const wchar_t *, const wchar_t *);
const wchar_t*);
template FMT_API std::wstring internal::vformat<wchar_t>( template FMT_API std::wstring internal::vformat<wchar_t>(wstring_view, basic_format_args<wformat_context>);
wstring_view, basic_format_args<wformat_context>);
FMT_END_NAMESPACE FMT_END_NAMESPACE
#endif #endif

View File

@ -5,22 +5,22 @@
#error Please define SPDLOG_COMPILED_LIB to compile this file. #error Please define SPDLOG_COMPILED_LIB to compile this file.
#endif #endif
#include "spdlog/spdlog-inl.h" #include <spdlog/spdlog-inl.h>
#include "spdlog/common-inl.h" #include <spdlog/common-inl.h>
#include "spdlog/details/backtracer-inl.h" #include <spdlog/details/backtracer-inl.h>
#include "spdlog/details/registry-inl.h" #include <spdlog/details/registry-inl.h>
#include "spdlog/details/os-inl.h" #include <spdlog/details/os-inl.h>
#include "spdlog/details/pattern_formatter-inl.h" #include <spdlog/pattern_formatter-inl.h>
#include "spdlog/details/log_msg-inl.h" #include <spdlog/details/log_msg-inl.h>
#include "spdlog/details/log_msg_buffer-inl.h" #include <spdlog/details/log_msg_buffer-inl.h>
#include "spdlog/logger-inl.h" #include <spdlog/logger-inl.h>
#include "spdlog/sinks/sink-inl.h" #include <spdlog/sinks/sink-inl.h>
#include "spdlog/sinks/base_sink-inl.h" #include <spdlog/sinks/base_sink-inl.h>
#include "spdlog/details/null_mutex.h" #include <spdlog/details/null_mutex.h>
#include <mutex> #include <mutex>
// template instantiate logger constructor with sinks init list // 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 SPDLOG_API spdlog::logger::logger(std::string name, sinks_init_list::iterator begin, sinks_init_list::iterator end);
template class spdlog::sinks::base_sink<std::mutex>; template class SPDLOG_API spdlog::sinks::base_sink<std::mutex>;
template class spdlog::sinks::base_sink<spdlog::details::null_mutex>; template class SPDLOG_API spdlog::sinks::base_sink<spdlog::details::null_mutex>;

View File

@ -7,23 +7,23 @@
#include <mutex> #include <mutex>
#include "spdlog/details/null_mutex.h" #include <spdlog/details/null_mutex.h>
#include "spdlog/async.h" #include <spdlog/async.h>
#include "spdlog/sinks/stdout_sinks-inl.h" #include <spdlog/sinks/stdout_sinks-inl.h>
template class spdlog::sinks::stdout_sink_base<spdlog::details::console_mutex>; template class SPDLOG_API spdlog::sinks::stdout_sink_base<spdlog::details::console_mutex>;
template class spdlog::sinks::stdout_sink_base<spdlog::details::console_nullmutex>; template class SPDLOG_API spdlog::sinks::stdout_sink_base<spdlog::details::console_nullmutex>;
template class spdlog::sinks::stdout_sink<spdlog::details::console_mutex>; template class SPDLOG_API spdlog::sinks::stdout_sink<spdlog::details::console_mutex>;
template class spdlog::sinks::stdout_sink<spdlog::details::console_nullmutex>; template class SPDLOG_API spdlog::sinks::stdout_sink<spdlog::details::console_nullmutex>;
template class spdlog::sinks::stderr_sink<spdlog::details::console_mutex>; template class SPDLOG_API spdlog::sinks::stderr_sink<spdlog::details::console_mutex>;
template class spdlog::sinks::stderr_sink<spdlog::details::console_nullmutex>; template class SPDLOG_API spdlog::sinks::stderr_sink<spdlog::details::console_nullmutex>;
template std::shared_ptr<spdlog::logger> spdlog::stdout_logger_mt<spdlog::synchronous_factory>(const std::string &logger_name); template SPDLOG_API std::shared_ptr<spdlog::logger> spdlog::stdout_logger_mt<spdlog::synchronous_factory>(const std::string &logger_name);
template std::shared_ptr<spdlog::logger> spdlog::stdout_logger_st<spdlog::synchronous_factory>(const std::string &logger_name); template SPDLOG_API std::shared_ptr<spdlog::logger> spdlog::stdout_logger_st<spdlog::synchronous_factory>(const std::string &logger_name);
template std::shared_ptr<spdlog::logger> spdlog::stderr_logger_mt<spdlog::synchronous_factory>(const std::string &logger_name); template SPDLOG_API std::shared_ptr<spdlog::logger> spdlog::stderr_logger_mt<spdlog::synchronous_factory>(const std::string &logger_name);
template std::shared_ptr<spdlog::logger> spdlog::stderr_logger_st<spdlog::synchronous_factory>(const std::string &logger_name); template SPDLOG_API std::shared_ptr<spdlog::logger> spdlog::stderr_logger_st<spdlog::synchronous_factory>(const std::string &logger_name);
template std::shared_ptr<spdlog::logger> spdlog::stdout_logger_mt<spdlog::async_factory>(const std::string &logger_name); template SPDLOG_API std::shared_ptr<spdlog::logger> spdlog::stdout_logger_mt<spdlog::async_factory>(const std::string &logger_name);
template std::shared_ptr<spdlog::logger> spdlog::stdout_logger_st<spdlog::async_factory>(const std::string &logger_name); template SPDLOG_API std::shared_ptr<spdlog::logger> spdlog::stdout_logger_st<spdlog::async_factory>(const std::string &logger_name);
template std::shared_ptr<spdlog::logger> spdlog::stderr_logger_mt<spdlog::async_factory>(const std::string &logger_name); template SPDLOG_API std::shared_ptr<spdlog::logger> spdlog::stderr_logger_mt<spdlog::async_factory>(const std::string &logger_name);
template std::shared_ptr<spdlog::logger> spdlog::stderr_logger_st<spdlog::async_factory>(const std::string &logger_name); template SPDLOG_API std::shared_ptr<spdlog::logger> spdlog::stderr_logger_st<spdlog::async_factory>(const std::string &logger_name);

View File

@ -1,5 +1,12 @@
cmake_minimum_required(VERSION 3.2)
project(spdlog_utests CXX) project(spdlog_utests CXX)
if(NOT TARGET spdlog)
# Stand-alone build
find_package(spdlog REQUIRED)
endif()
include(../cmake/utils.cmake) include(../cmake/utils.cmake)
find_package(PkgConfig) find_package(PkgConfig)
@ -12,6 +19,7 @@ set(SPDLOG_UTESTS_SOURCES
test_file_logging.cpp test_file_logging.cpp
test_daily_logger.cpp test_daily_logger.cpp
test_misc.cpp test_misc.cpp
test_eventlog.cpp
test_pattern_formatter.cpp test_pattern_formatter.cpp
test_async.cpp test_async.cpp
test_registry.cpp test_registry.cpp
@ -23,7 +31,8 @@ set(SPDLOG_UTESTS_SOURCES
test_fmt_helper.cpp test_fmt_helper.cpp
test_stdout_api.cpp test_stdout_api.cpp
test_backtrace.cpp test_backtrace.cpp
test_create_dir.cpp) test_create_dir.cpp
test_cfg.cpp)
if(NOT SPDLOG_NO_EXCEPTIONS) if(NOT SPDLOG_NO_EXCEPTIONS)
list(APPEND SPDLOG_UTESTS_SOURCES test_errors.cpp) 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}) spdlog_enable_sanitizer(${test_target})
endif() endif()
add_test(NAME ${test_target} COMMAND ${test_target}) add_test(NAME ${test_target} COMMAND ${test_target})
set_tests_properties(${test_target} PROPERTIES RUN_SERIAL ON)
endfunction() endfunction()
# The compiled library tests # The compiled library tests

View File

@ -11,6 +11,7 @@
#include <sstream> #include <sstream>
#include <string> #include <string>
#include <iomanip> #include <iomanip>
#include <stdlib.h>
#define SPDLOG_ACTIVE_LEVEL SPDLOG_LEVEL_DEBUG #define SPDLOG_ACTIVE_LEVEL SPDLOG_LEVEL_DEBUG
@ -22,4 +23,4 @@
#include "spdlog/sinks/ostream_sink.h" #include "spdlog/sinks/ostream_sink.h"
#include "spdlog/sinks/rotating_file_sink.h" #include "spdlog/sinks/rotating_file_sink.h"
#include "spdlog/sinks/stdout_color_sinks.h" #include "spdlog/sinks/stdout_color_sinks.h"
#include "spdlog/details/pattern_formatter.h" #include "spdlog/pattern_formatter.h"

View File

@ -14,7 +14,8 @@ test_sources = files([
'test_fmt_helper.cpp', 'test_fmt_helper.cpp',
'test_stdout_api.cpp', 'test_stdout_api.cpp',
'test_backtrace.cpp', 'test_backtrace.cpp',
'test_create_dir.cpp' 'test_create_dir.cpp',
'test_cfg.cpp',
]) ])
if not get_option('no_exceptions') if not get_option('no_exceptions')

View File

@ -5,14 +5,13 @@
TEST_CASE("basic async test ", "[async]") TEST_CASE("basic async test ", "[async]")
{ {
using namespace spdlog; auto test_sink = std::make_shared<spdlog::sinks::test_sink_mt>();
auto test_sink = std::make_shared<sinks::test_sink_mt>();
size_t overrun_counter = 0; size_t overrun_counter = 0;
size_t queue_size = 128; size_t queue_size = 128;
size_t messages = 256; size_t messages = 256;
{ {
auto tp = std::make_shared<details::thread_pool>(queue_size, 1); auto tp = std::make_shared<spdlog::details::thread_pool>(queue_size, 1);
auto logger = std::make_shared<async_logger>("as", test_sink, tp, async_overflow_policy::block); auto logger = std::make_shared<spdlog::async_logger>("as", test_sink, tp, spdlog::async_overflow_policy::block);
for (size_t i = 0; i < messages; i++) for (size_t i = 0; i < messages; i++)
{ {
logger->info("Hello message #{}", i); logger->info("Hello message #{}", i);
@ -27,14 +26,13 @@ TEST_CASE("basic async test ", "[async]")
TEST_CASE("discard policy ", "[async]") TEST_CASE("discard policy ", "[async]")
{ {
using namespace spdlog; auto test_sink = std::make_shared<spdlog::sinks::test_sink_mt>();
auto test_sink = std::make_shared<sinks::test_sink_mt>();
test_sink->set_delay(std::chrono::milliseconds(1)); test_sink->set_delay(std::chrono::milliseconds(1));
size_t queue_size = 4; size_t queue_size = 4;
size_t messages = 1024; size_t messages = 1024;
auto tp = std::make_shared<details::thread_pool>(queue_size, 1); auto tp = std::make_shared<spdlog::details::thread_pool>(queue_size, 1);
auto logger = std::make_shared<async_logger>("as", test_sink, tp, async_overflow_policy::overrun_oldest); auto logger = std::make_shared<spdlog::async_logger>("as", test_sink, tp, spdlog::async_overflow_policy::overrun_oldest);
for (size_t i = 0; i < messages; i++) for (size_t i = 0; i < messages; i++)
{ {
logger->info("Hello message"); logger->info("Hello message");
@ -45,13 +43,12 @@ TEST_CASE("discard policy ", "[async]")
TEST_CASE("discard policy using factory ", "[async]") TEST_CASE("discard policy using factory ", "[async]")
{ {
using namespace spdlog;
size_t queue_size = 4; size_t queue_size = 4;
size_t messages = 1024; size_t messages = 1024;
spdlog::init_thread_pool(queue_size, 1); spdlog::init_thread_pool(queue_size, 1);
auto logger = spdlog::create_async_nb<sinks::test_sink_mt>("as2"); auto logger = spdlog::create_async_nb<spdlog::sinks::test_sink_mt>("as2");
auto test_sink = std::static_pointer_cast<sinks::test_sink_mt>(logger->sinks()[0]); auto test_sink = std::static_pointer_cast<spdlog::sinks::test_sink_mt>(logger->sinks()[0]);
test_sink->set_delay(std::chrono::milliseconds(1)); test_sink->set_delay(std::chrono::milliseconds(1));
for (size_t i = 0; i < messages; i++) for (size_t i = 0; i < messages; i++)
@ -65,13 +62,12 @@ TEST_CASE("discard policy using factory ", "[async]")
TEST_CASE("flush", "[async]") TEST_CASE("flush", "[async]")
{ {
using namespace spdlog; auto test_sink = std::make_shared<spdlog::sinks::test_sink_mt>();
auto test_sink = std::make_shared<sinks::test_sink_mt>();
size_t queue_size = 256; size_t queue_size = 256;
size_t messages = 256; size_t messages = 256;
{ {
auto tp = std::make_shared<details::thread_pool>(queue_size, 1); auto tp = std::make_shared<spdlog::details::thread_pool>(queue_size, 1);
auto logger = std::make_shared<async_logger>("as", test_sink, tp, async_overflow_policy::block); auto logger = std::make_shared<spdlog::async_logger>("as", test_sink, tp, spdlog::async_overflow_policy::block);
for (size_t i = 0; i < messages; i++) for (size_t i = 0; i < messages; i++)
{ {
logger->info("Hello message #{}", i); logger->info("Hello message #{}", i);
@ -86,11 +82,9 @@ TEST_CASE("flush", "[async]")
TEST_CASE("async periodic flush", "[async]") TEST_CASE("async periodic flush", "[async]")
{ {
using namespace spdlog;
auto logger = spdlog::create_async<sinks::test_sink_mt>("as"); auto logger = spdlog::create_async<spdlog::sinks::test_sink_mt>("as");
auto test_sink = std::static_pointer_cast<spdlog::sinks::test_sink_mt>(logger->sinks()[0]);
auto test_sink = std::static_pointer_cast<sinks::test_sink_mt>(logger->sinks()[0]);
spdlog::flush_every(std::chrono::seconds(1)); spdlog::flush_every(std::chrono::seconds(1));
std::this_thread::sleep_for(std::chrono::milliseconds(1100)); 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]") TEST_CASE("tp->wait_empty() ", "[async]")
{ {
using namespace spdlog; auto test_sink = std::make_shared<spdlog::sinks::test_sink_mt>();
auto test_sink = std::make_shared<sinks::test_sink_mt>();
test_sink->set_delay(std::chrono::milliseconds(5)); test_sink->set_delay(std::chrono::milliseconds(5));
size_t messages = 100; size_t messages = 100;
auto tp = std::make_shared<details::thread_pool>(messages, 2); auto tp = std::make_shared<spdlog::details::thread_pool>(messages, 2);
auto logger = std::make_shared<async_logger>("as", test_sink, tp, async_overflow_policy::block); auto logger = std::make_shared<spdlog::async_logger>("as", test_sink, tp, spdlog::async_overflow_policy::block);
for (size_t i = 0; i < messages; i++) for (size_t i = 0; i < messages; i++)
{ {
logger->info("Hello message #{}", i); logger->info("Hello message #{}", i);
@ -121,14 +114,13 @@ TEST_CASE("tp->wait_empty() ", "[async]")
TEST_CASE("multi threads", "[async]") TEST_CASE("multi threads", "[async]")
{ {
using namespace spdlog; auto test_sink = std::make_shared<spdlog::sinks::test_sink_mt>();
auto test_sink = std::make_shared<sinks::test_sink_mt>();
size_t queue_size = 128; size_t queue_size = 128;
size_t messages = 256; size_t messages = 256;
size_t n_threads = 10; size_t n_threads = 10;
{ {
auto tp = std::make_shared<details::thread_pool>(queue_size, 1); auto tp = std::make_shared<spdlog::details::thread_pool>(queue_size, 1);
auto logger = std::make_shared<async_logger>("as", test_sink, tp, async_overflow_policy::block); auto logger = std::make_shared<spdlog::async_logger>("as", test_sink, tp, spdlog::async_overflow_policy::block);
std::vector<std::thread> threads; std::vector<std::thread> threads;
for (size_t i = 0; i < n_threads; i++) 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); 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]") 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);
} }

93
third_party/spdlog/tests/test_cfg.cpp vendored Normal file
View File

@ -0,0 +1,93 @@
#include "includes.h"
#include "test_sink.h"
#include <spdlog/cfg/env.h>
#include <spdlog/cfg/argv.h>
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<test_sink_st>("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<test_sink_st>("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<spdlog::sinks::test_sink_st>("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<test_sink_st>("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<test_sink_st>("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<test_sink_st>("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<test_sink_st>("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);
}

View File

@ -24,7 +24,7 @@ TEST_CASE("daily_logger with dateonly calculator", "[daily_logger]")
logger->flush(); logger->flush();
auto filename = fmt::to_string(w); auto filename = fmt::to_string(w);
REQUIRE(count_lines(filename) == 10); require_message_count(filename, 10);
} }
struct custom_daily_file_name_calculator 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->info("Test message {}", i);
} }
logger-> logger->flush();
flush();
auto filename = fmt::to_string(w); 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::log_clock;
using spdlog::details::log_msg; using spdlog::details::log_msg;
using spdlog::sinks::daily_file_sink_st; using spdlog::sinks::daily_file_sink_st;
using namespace spdlog::details;
prepare_logdir(); prepare_logdir();

View File

@ -2,11 +2,11 @@
#include "spdlog/sinks/dup_filter_sink.h" #include "spdlog/sinks/dup_filter_sink.h"
#include "test_sink.h" #include "test_sink.h"
using namespace spdlog;
using namespace spdlog::sinks;
TEST_CASE("dup_filter_test1", "[dup_filter_sink]") 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}}; dup_filter_sink_st dup_sink{std::chrono::seconds{5}};
auto test_sink = std::make_shared<test_sink_mt>(); auto test_sink = std::make_shared<test_sink_mt>();
dup_sink.add_sink(test_sink); 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]") 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}}; dup_filter_sink_st dup_sink{std::chrono::seconds{0}};
auto test_sink = std::make_shared<test_sink_mt>(); auto test_sink = std::make_shared<test_sink_mt>();
dup_sink.add_sink(test_sink); 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]") 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}}; dup_filter_sink_st dup_sink{std::chrono::seconds{1}};
auto test_sink = std::make_shared<test_sink_mt>(); auto test_sink = std::make_shared<test_sink_mt>();
dup_sink.add_sink(test_sink); 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]") 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}}; dup_filter_sink_mt dup_sink{std::chrono::milliseconds{10}};
auto test_sink = std::make_shared<test_sink_mt>(); auto test_sink = std::make_shared<test_sink_mt>();
dup_sink.add_sink(test_sink); 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]") 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}}; dup_filter_sink_mt dup_sink{std::chrono::seconds{5}};
auto test_sink = std::make_shared<test_sink_mt>(); auto test_sink = std::make_shared<test_sink_mt>();
dup_sink.add_sink(test_sink); dup_sink.add_sink(test_sink);

View File

@ -7,10 +7,6 @@
class failing_sink : public spdlog::sinks::base_sink<std::mutex> class failing_sink : public spdlog::sinks::base_sink<std::mutex>
{ {
public:
failing_sink() = default;
~failing_sink() final = default;
protected: protected:
void sink_it_(const spdlog::details::log_msg &) final 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->info("Test message {}", 2);
logger->flush(); 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); 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); REQUIRE_THROWS_AS(logger->info("Bad format msg {} {}", "xxx"), custom_ex);
logger->info("Good message #2"); logger->info("Good message #2");
REQUIRE(count_lines(filename) == 2); require_message_count(filename, 2);
} }
TEST_CASE("default_error_handler2", "[errors]]") 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::drop("logger"); // force logger to drain the queue and shutdown
} }
spdlog::init_thread_pool(128, 1); 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); REQUIRE(file_contents("test_logs/custom_err.txt") == err_msg);
} }

View File

@ -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<void(std::string const &)> 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<seconds>(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<char> 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<sinks::win_eventlog_sink_mt>(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

View File

@ -4,9 +4,6 @@
#include "includes.h" #include "includes.h"
using spdlog::details::file_helper; 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) 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(); prepare_logdir();
file_helper helper; file_helper helper;
std::string target_filename = "test_logs/file_helper_test.txt";
helper.open(target_filename); helper.open(target_filename);
REQUIRE(helper.filename() == 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()]]") TEST_CASE("file_helper_size", "[file_helper::size()]]")
{ {
prepare_logdir(); prepare_logdir();
std::string target_filename = "test_logs/file_helper_test.txt";
size_t expected_size = 123; size_t expected_size = 123;
{ {
file_helper helper; file_helper helper;
@ -41,6 +40,7 @@ TEST_CASE("file_helper_size", "[file_helper::size()]]")
TEST_CASE("file_helper_reopen", "[file_helper::reopen()]]") TEST_CASE("file_helper_reopen", "[file_helper::reopen()]]")
{ {
prepare_logdir(); prepare_logdir();
std::string target_filename = "test_logs/file_helper_test.txt";
file_helper helper; file_helper helper;
helper.open(target_filename); helper.open(target_filename);
write_with_helper(helper, 12); 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)]]") TEST_CASE("file_helper_reopen2", "[file_helper::reopen(false)]]")
{ {
prepare_logdir(); prepare_logdir();
std::string target_filename = "test_logs/file_helper_test.txt";
size_t expected_size = 14; size_t expected_size = 14;
file_helper helper; file_helper helper;
helper.open(target_filename); 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(filename.begin(), filename.end(), '/', '\\');
std::replace(expected_base.begin(), expected_base.end(), '/', '\\'); std::replace(expected_base.begin(), expected_base.end(), '/', '\\');
#endif #endif
spdlog::filename_t basename, ext; spdlog::filename_t basename;
spdlog::filename_t ext;
std::tie(basename, ext) = file_helper::split_by_extension(filename); std::tie(basename, ext) = file_helper::split_by_extension(filename);
REQUIRE(basename == expected_base); REQUIRE(basename == expected_base);
REQUIRE(ext == expected_ext); REQUIRE(ext == expected_ext);

Some files were not shown because too many files have changed in this diff Show More