Loading .gitignore +2 −5 Original line number Diff line number Diff line Loading @@ -66,6 +66,3 @@ install_manifest.txt # idea .idea/ No newline at end of file # vscode .vscode/ No newline at end of file .travis.yml +113 −91 Original line number Diff line number Diff line Loading @@ -2,23 +2,9 @@ # - Louis Dionne's Hana: https://github.com/ldionne/hana # - Paul Fultz II's FIT: https://github.com/pfultz2/Fit # - Eric Niebler's range-v3: https://github.com/ericniebler/range-v3 sudo: required language: cpp # Test matrix: # - Build matrix per compiler: C++11/C++14 + Debug/Release # - Optionally: AddressSanitizer (ASAN) # - Valgrind: all release builds are also tested with valgrind # - clang 3.4, 3.5, 3.6, trunk # - Note: 3.4 and trunk are tested with/without ASAN, # the rest is only tested with ASAN=On. # - gcc 4.9, 5.0 # matrix: include: # Test gcc-4.8: C++11, Build=Debug/Release, ASAN=Off - env: GCC_VERSION=4.8 BUILD_TYPE=Debug CPP=11 ASAN=Off LIBCXX=Off os: linux addons: &gcc48 apt: packages: Loading @@ -27,65 +13,101 @@ matrix: sources: - ubuntu-toolchain-r-test - env: GCC_VERSION=4.8 BUILD_TYPE=Release CPP=11 ASAN=Off LIBCXX=Off os: linux addons: *gcc48 addons: &gcc7 apt: packages: - g++-7 - valgrind sources: - ubuntu-toolchain-r-test # Test gcc-4.9: C++11, Build=Debug/Release, ASAN=Off - env: GCC_VERSION=4.9 BUILD_TYPE=Debug CPP=11 ASAN=Off LIBCXX=Off os: linux addons: &gcc49 addons: &clang35 apt: packages: - g++-4.9 - clang-3.5 - valgrind sources: - ubuntu-toolchain-r-test - llvm-toolchain-precise-3.5 addons: &clang6 apt: packages: - clang-6.0 - valgrind sources: - ubuntu-toolchain-r-test - llvm-toolchain-trusty-6.0 matrix: include: # Test gcc-4.8: C++11, Build=Debug/Release - env: GCC_VERSION=4.8 BUILD_TYPE=Debug CPP=11 os: linux addons: *gcc48 - env: GCC_VERSION=4.8 BUILD_TYPE=Release CPP=11 os: linux addons: *gcc48 - env: GCC_VERSION=7 BUILD_TYPE=Release CPP=11 os: linux addons: *gcc7 # Test clang-3.5: C++11, Build=Debug/Release - env: CLANG_VERSION=3.5 BUILD_TYPE=Debug CPP=11 os: linux addons: *clang35 - env: CLANG_VERSION=3.5 BUILD_TYPE=Release CPP=11 os: linux addons: *clang35 # Test clang-6.0: C++11, Build=Debug, ASAN=On - env: CLANG_VERSION=6.0 BUILD_TYPE=Debug CPP=11 ASAN=On TSAN=Off os: linux addons: *clang6 - env: CLANG_VERSION=6.0 BUILD_TYPE=Release CPP=11 ASAN=On TSAN=Off os: linux addons: *clang6 - env: GCC_VERSION=4.9 BUILD_TYPE=Release CPP=11 ASAN=Off LIBCXX=Off # Test clang-6.0: C++11, Build=Debug, TSAN=On - env: CLANG_VERSION=6.0 BUILD_TYPE=Debug CPP=11 ASAN=Off TSAN=On os: linux addons: *gcc49 addons: *clang6 - env: CLANG_VERSION=6.0 BUILD_TYPE=Release CPP=11 ASAN=Off TSAN=On os: linux addons: *clang6 # Install dependencies before_install: - export CHECKOUT_PATH=`pwd`; before_script: - if [ -n "$GCC_VERSION" ]; then export CXX="g++-${GCC_VERSION}" CC="gcc-${GCC_VERSION}"; fi - if [ -n "$CLANG_VERSION" ]; then export CXX="clang++-${CLANG_VERSION}" CC="clang-${CLANG_VERSION}"; fi - if [ "$CLANG_VERSION" == "3.4" ]; then export CXX="/usr/local/clang-3.4/bin/clang++" CC="/usr/local/clang-3.4/bin/clang"; fi - which $CXX - which $CC - which valgrind - if [ -n "$CLANG_VERSION" ]; then sudo CXX=$CXX CC=$CC ./tests/install_libcxx.sh; fi - $CXX --version - cmake --version - valgrind --version install: - cd $CHECKOUT_PATH # Workaround for valgrind bug: https://bugs.kde.org/show_bug.cgi?id=326469. # It is fixed in valgrind 3.10 so this won't be necessary if someone # replaces the current valgrind (3.7) with valgrind-3.10 - sed -i 's/march=native/msse4.2/' example/Makefile - if [ ! -d build ]; then mkdir build; fi - export CXX_FLAGS="-I${CHECKOUT_PATH}/include" - export CXX_LINKER_FLAGS="" - if [ -z "$BUILD_TYPE" ]; then export BUILD_TYPE=Release; fi - if [ "$ASAN" == "On"]; then export CXX_FLAGS="${CXX_FLAGS} -fsanitize=address,undefined,integer -fno-omit-frame-pointer -fno-sanitize=unsigned-integer-overflow"; fi - if [ -n "$CLANG_VERSION" ]; then CXX_FLAGS="${CXX_FLAGS} -D__extern_always_inline=inline"; fi - if [ "$LIBCXX" == "On" ]; then CXX_FLAGS="${CXX_FLAGS} -stdlib=libc++ -I/usr/include/c++/v1/"; fi - if [ "$LIBCXX" == "On" ]; then CXX_LINKER_FLAGS="${CXX_FLAGS} -L/usr/lib/ -lc++"; fi - CXX_FLAGS="${CXX_FLAGS} -std=c++${CPP}" # Build examples - cd example - if [ "$BUILD_TYPE" == "Release" ]; then make rebuild CXXFLAGS="${CXX_FLAGS} ${CXX_LINKER_FLAGS}" VERBOSE=1; export BIN=example; fi - if [ "$BUILD_TYPE" == "Debug" ]; then make rebuild debug CXXFLAGS="${CXX_FLAGS} ${CXX_LINKER_FLAGS}" VERBOSE=1; export BIN=example-debug; fi script: - cd ${TRAVIS_BUILD_DIR} - mkdir -p build && cd build - | cmake .. \ --warn-uninitialized \ -DCMAKE_BUILD_TYPE=$BUILD_TYPE \ -DCMAKE_CXX_STANDARD=$CPP \ -DSPDLOG_BUILD_EXAMPLES=ON \ -DSPDLOG_BUILD_BENCH=OFF \ -DSPDLOG_SANITIZE_ADDRESS=$ASAN \ -DSPDLOG_SANITIZE_THREAD=$TSAN - make VERBOSE=1 -j2 - ctest -j2 --output-on-failure script: - ./"${BIN}" - valgrind --trace-children=yes --leak-check=full ./"${BIN}" - cd $CHECKOUT_PATH/tests; make rebuild; ./tests - cd $CHECKOUT_PATH/tests; STYLE=printf make rebuild; ./tests notifications: email: false CMakeLists.txt +27 −3 Original line number Diff line number Diff line Loading @@ -4,27 +4,47 @@ # cmake_minimum_required(VERSION 3.1) project(spdlog VERSION 0.17.0 LANGUAGES CXX) project(spdlog VERSION 1.1.0 LANGUAGES CXX) include(CTest) include(CMakeDependentOption) include(GNUInstallDirs) #--------------------------------------------------------------------------------------- # set default build to release #--------------------------------------------------------------------------------------- if(NOT CMAKE_BUILD_TYPE) set(CMAKE_BUILD_TYPE "Release" CACHE STRING "Choose Release or Debug" FORCE) endif() message(STATUS "Build type: " ${CMAKE_BUILD_TYPE}) #--------------------------------------------------------------------------------------- # compiler config #--------------------------------------------------------------------------------------- set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_EXTENSIONS OFF) if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" OR "${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang") set(CMAKE_CXX_FLAGS "-Wall -O3 ${CMAKE_CXX_FLAGS}") add_compile_options("-Wall") add_compile_options("-Wextra") add_compile_options("-pedantic") endif() #--------------------------------------------------------------------------------------- # address sanitizers check #--------------------------------------------------------------------------------------- include(cmake/sanitizers.cmake) #--------------------------------------------------------------------------------------- # spdlog target #--------------------------------------------------------------------------------------- add_library(spdlog INTERFACE) add_library(spdlog::spdlog ALIAS spdlog) option(SPDLOG_BUILD_EXAMPLES "Build examples" ON) option(SPDLOG_BUILD_BENCH "Build benchmarks" ON) option(SPDLOG_BUILD_EXAMPLES "Build examples" OFF) cmake_dependent_option(SPDLOG_BUILD_TESTING "Build spdlog tests" ON "BUILD_TESTING" OFF Loading @@ -47,6 +67,10 @@ if(SPDLOG_BUILD_TESTING) add_subdirectory(tests) endif() if(SPDLOG_BUILD_BENCH) add_subdirectory(bench) endif() #--------------------------------------------------------------------------------------- # Install/export targets and files #--------------------------------------------------------------------------------------- Loading README.md +195 −134 Original line number Diff line number Diff line Loading @@ -6,7 +6,7 @@ Very fast, header only, C++ logging library. [ to your build tree and use a C++11 compiler. * Copy the source [folder](https://github.com/gabime/spdlog/tree/v1.x/include/spdlog) to your build tree and use a C++11 compiler. #### Or use your favorite package manager: Loading @@ -20,7 +20,7 @@ Very fast, header only, C++ logging library. [ * Mac OSX (clang 3.5+) * Android Loading @@ -28,9 +28,8 @@ Very fast, header only, C++ logging library. [ below). * Headers only, just copy and use. * Feature rich [call style](#usage-example) using the excellent [fmt](https://github.com/fmtlib/fmt) library. * Optional printf syntax support. * Asynchronous mode (optional) * Feature rich using the excellent [fmt](https://github.com/fmtlib/fmt) library. * Fast asynchronous mode (optional) * [Custom](https://github.com/gabime/spdlog/wiki/3.-Custom-formatting) formatting. * Conditional Logging * Multi/Single threaded loggers. Loading @@ -47,52 +46,51 @@ Very fast, header only, C++ logging library. [ comparing popular log libraries under Ubuntu 64 bit, Intel i7-4770 CPU @ 3.40GHz Below are some [benchmarks](https://github.com/gabime/spdlog/blob/v1.x/bench/bench.cpp) done in Ubuntu 64 bit, Intel i7-4770 CPU @ 3.40GHz #### Synchronous mode Time needed to log 1,000,000 lines in synchronous mode (in seconds, the best of 3 runs): |threads|boost log 1.54|glog |easylogging |spdlog| |-------|:-------:|:-----:|----------:|------:| |1| 4.169s |1.066s |0.975s |0.392s| |10| 6.180s |3.032s |2.857s |0.773s| |100| 5.981s |1.139s |4.512s |0.587s| ``` ******************************************************************************* Single thread, 1,000,000 iterations ******************************************************************************* basic_st... Elapsed: 0.226664 4,411,806/sec rotating_st... Elapsed: 0.214339 4,665,499/sec daily_st... Elapsed: 0.211292 4,732,797/sec null_st... Elapsed: 0.102815 9,726,227/sec ******************************************************************************* 10 threads sharing same logger, 1,000,000 iterations ******************************************************************************* basic_mt... Elapsed: 0.882268 1,133,441/sec rotating_mt... Elapsed: 0.875515 1,142,184/sec daily_mt... Elapsed: 0.879573 1,136,915/sec null_mt... Elapsed: 0.220114 4,543,105/sec ``` #### Asynchronous mode Time needed to log 1,000,000 lines in asynchronous mode, i.e. the time it takes to put them in the async queue (in seconds, the best of 3 runs): |threads|g2log <sup>async logger</sup> |spdlog <sup>async mode</sup>| |:-------|:-----:|-------------------------:| |1| 1.850s |0.39s | |10| 0.943s |0.416s| |100| 0.959s |0.413s| ``` ******************************************************************************* 10 threads sharing same logger, 1,000,000 iterations ******************************************************************************* async... Elapsed: 0.429088 2,330,524/sec async... Elapsed: 0.411501 2,430,126/sec async... Elapsed: 0.428979 2,331,116/sec ``` ## Usage samples ## Usage Example ```c++ #include "spdlog/spdlog.h" #include <iostream> #include <memory> void async_example(); void syslog_example(); void user_defined_example(); void err_handler_example(); namespace spd = spdlog; int main(int, char*[]) { try #include "spdlog/sinks/stdout_color_sinks.h" void stdout_example() { // Console logger with color auto console = spd::stdout_color_mt("console"); // create color multi threaded logger auto console = spdlog::stdout_color_mt("console"); console->info("Welcome to spdlog!"); console->error("Some error message with arg{}..", 1); console->error("Some error message with arg: {}", 1); auto err_logger = spdlog::stderr_color_mt("stderr"); err_logger->error("Some error message"); // Formatting examples console->warn("Easy padding in numbers like {:08d}", 12); Loading @@ -101,93 +99,135 @@ int main(int, char*[]) console->info("Positional args are {1} {0}..", "too", "supported"); console->info("{:<30}", "left aligned"); // Use global registry to retrieve loggers spd::get("console")->info("loggers can be retrieved from a global registry using the spdlog::get(logger_name) function"); // Create basic file logger (not rotated) auto my_logger = spd::basic_logger_mt("basic_logger", "logs/basic.txt"); my_logger->info("Some log message"); // Create a file rotating logger with 5mb size max and 3 rotated files auto rotating_logger = spd::rotating_logger_mt("some_logger_name", "logs/mylogfile.txt", 1048576 * 5, 3); for (int i = 0; i < 10; ++i) rotating_logger->info("{} * {} equals {:>10}", i, i, i*i); // Create a daily logger - a new file is created every day on 2:30am auto daily_logger = spd::daily_logger_mt("daily_logger", "logs/daily.txt", 2, 30); // trigger flush if the log severity is error or higher daily_logger->flush_on(spd::level::err); daily_logger->info(123.44); // Customize msg format for all messages spd::set_pattern("[%^+++%$] [%H:%M:%S %z] [thread %t] %v"); console->info("This an info message with custom format (and custom color range between the '%^' and '%$')"); console->error("This an error message with custom format (and custom color range between the '%^' and '%$')"); spdlog::get("console")->info("loggers can be retrieved from a global registry using the spdlog::get(logger_name)"); // Runtime log levels spd::set_level(spd::level::info); //Set global log level to info spdlog::set_level(spdlog::level::info); // Set global log level to info console->debug("This message should not be displayed!"); console->set_level(spd::level::debug); // Set specific logger's log level console->set_level(spdlog::level::trace); // Set specific logger's log level console->debug("This message should be displayed.."); // Customize msg format for all loggers spdlog::set_pattern("[%H:%M:%S %z] [%n] [%^---%L---%$] [thread %t] %v"); console->info("This an info message with custom format"); // Compile time log levels // define SPDLOG_DEBUG_ON or SPDLOG_TRACE_ON SPDLOG_TRACE(console, "Enabled only #ifdef SPDLOG_TRACE_ON..{} ,{}", 1, 3.23); SPDLOG_DEBUG(console, "Enabled only #ifdef SPDLOG_DEBUG_ON.. {} ,{}", 1, 3.23); } ``` --- #### Basic file logger ```c++ #include "spdlog/sinks/basic_file_sink.h" void basic_logfile_example() { try { auto my_logger = spdlog::basic_logger_mt("basic_logger", "logs/basic-log.txt"); } catch (const spdlog::spdlog_ex &ex) { std::cout << "Log init failed: " << ex.what() << std::endl; return 1; } } ``` --- #### Rotating files ```c++ #include "spdlog/sinks/rotating_file_sink.h" void rotating_example() { // Create a file rotating logger with 5mb size max and 3 rotated files auto rotating_logger = spdlog::rotating_logger_mt("some_logger_name", "logs/rotating.txt", 1048576 * 5, 3); } ``` // Asynchronous logging is very fast.. // Just call spdlog::set_async_mode(q_size) and all created loggers from now on will be asynchronous.. async_example(); --- #### Daily files ```c++ // syslog example. linux/osx only syslog_example(); #include "spdlog/sinks/daily_file_sink.h" void daily_example() { // Create a daily logger - a new file is created every day on 2:30am auto daily_logger = spdlog::daily_logger_mt("daily_logger", "logs/daily.txt", 2, 30); } // android example. compile with NDK android_example(); ``` // Log user-defined types example user_defined_example(); --- #### Periodic flush ```c++ // periodically flush all *registered* loggers every 3 seconds: // warning: only use if all your loggers are thread safe! spdlog::flush_every(std::chrono::seconds(3)); // Change default log error handler err_handler_example(); ``` // Apply a function on all registered loggers spd::apply_all([&](std::shared_ptr<spd::logger> l) { l->info("End of example."); }); // Release and close all loggers spd::drop_all(); } // Exceptions will only be thrown upon failed logger or sink construction (not during logging) catch (const spd::spdlog_ex& ex) --- #### Logger with multi sinks - each with different format and log level ```c++ // create logger with 2 targets with different log levels and formats. // the console will show only warnings or errors, while the file will log all. void multi_sink_example() { std::cout << "Log init failed: " << ex.what() << std::endl; return 1; } auto console_sink = std::make_shared<spdlog::sinks::stdout_color_sink_mt>(); console_sink->set_level(spdlog::level::warn); console_sink->set_pattern("[multi_sink_example] [%^%l%$] %v"); auto file_sink = std::make_shared<spdlog::sinks::basic_file_sink_mt>("logs/multisink.txt", true); file_sink->set_level(spdlog::level::trace); spdlog::logger logger("multi_sink", {console_sink, file_sink}); logger.set_level(spdlog::level::debug); logger.warn("this should appear in both console and file"); logger.info("this message should not appear in the console, only in the file"); } ``` --- #### Asynchronous logging ```c++ #include "spdlog/async.h" #include "spdlog/sinks/basic_file_sink.h" void async_example() { size_t q_size = 4096; spd::set_async_mode(q_size); auto async_file = spd::daily_logger_st("async_file_logger", "logs/async_log.txt"); for (int i = 0; i < 100; ++i) async_file->info("Async message #{}", i); // default thread pool settings can be modified *before* creating the async logger: // spdlog::init_thread_pool(8192, 1); // queue with 8k items and 1 backing thread. auto async_file = spdlog::basic_logger_mt<spdlog::async_factory>("async_file_logger", "logs/async_log.txt"); // alternatively: // auto async_file = spdlog::create_async<spdlog::sinks::basic_file_sink_mt>("async_file_logger", "logs/async_log.txt"); } //syslog example void syslog_example() ``` --- #### Asynchronous logger with multi sinks ```c++ #include "spdlog/sinks/stdout_color_sinks.h" #include "spdlog/sinks/rotating_file_sink.h" void multi_sink_example2() { #ifdef SPDLOG_ENABLE_SYSLOG std::string ident = "spdlog-example"; auto syslog_logger = spd::syslog_logger("syslog", ident, LOG_PID); syslog_logger->warn("This is warning that will end up in syslog.."); #endif spdlog::init_thread_pool(8192, 1); auto stdout_sink = std::make_shared<spdlog::sinks::stdout_color_sink_mt >(); auto rotating_sink = std::make_shared<spdlog::sinks::rotating_file_sink_mt>("mylog.txt", 1024*1024*10, 3); std::vector<spdlog::sink_ptr> sinks {stdout_sink, rotating_sink}; auto logger = std::make_shared<spdlog::async_logger>("loggername", sinks.begin(), sinks.end(), spdlog::thread_pool(), spdlog::async_overflow_policy::block); spdlog::register_logger(logger); } ``` --- #### User defined types ```c++ // user defined types logging by implementing operator<< #include "spdlog/fmt/ostr.h" // must be included struct my_type { int i; Loading @@ -198,23 +238,44 @@ struct my_type } }; #include <spdlog/fmt/ostr.h> // must be included void user_defined_example() { spd::get("console")->info("user defined type: {}", my_type { 14 }); spdlog::get("console")->info("user defined type: {}", my_type{14}); } // //custom error handler // ``` --- #### Custom error handler ```c++ void err_handler_example() { spd::set_error_handler([](const std::string& msg) { std::cerr << "my err handler: " << msg << std::endl; }); // (or logger->set_error_handler(..) to set for specific logger) // can be set globally or per logger(logger->set_error_handler(..)) spdlog::set_error_handler([](const std::string &msg) { spdlog::get("console")->error("*** LOGGER ERROR ***: {}", msg); }); spdlog::get("console")->info("some invalid message to trigger an error {}{}{}{}", 3); } ``` --- #### syslog ```c++ #include "spdlog/sinks/syslog_sink.h" void syslog_example() { std::string ident = "spdlog-example"; auto syslog_logger = spdlog::syslog_logger_mt("syslog", ident, LOG_PID); syslog_logger->warn("This is warning that will end up in syslog."); } ``` --- #### Android example ```c++ #incude "spdlog/sinks/android_sink.h" void android_example() { std::string tag = "spdlog-android"; auto android_logger = spdlog::android_logger("android", tag); android_logger->critical("Use \"adb shell logcat\" to view this message."); } ``` ## Documentation Loading bench/CMakeLists.txt 0 → 100644 +43 −0 Original line number Diff line number Diff line # *************************************************************************/ # * Copyright (c) 2015 Ruslan Baratov. */ # * */ # * Permission is hereby granted, free of charge, to any person obtaining */ # * a copy of this software and associated documentation files (the */ # * "Software"), to deal in the Software without restriction, including */ # * without limitation the rights to use, copy, modify, merge, publish, */ # * distribute, sublicense, and/or sell copies of the Software, and to */ # * permit persons to whom the Software is furnished to do so, subject to */ # * the following conditions: */ # * */ # * The above copyright notice and this permission notice shall be */ # * included in all copies or substantial portions of the Software. */ # * */ # * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ # * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ # * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ # * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ # * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ # * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ # * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ # *************************************************************************/ cmake_minimum_required(VERSION 3.1) project(SpdlogBench CXX) if(NOT TARGET spdlog) # Stand-alone build find_package(spdlog CONFIG REQUIRED) endif() find_package(Threads REQUIRED) add_executable(bench bench.cpp) target_link_libraries(bench spdlog::spdlog Threads::Threads) add_executable(async_bench async_bench.cpp) target_link_libraries(async_bench spdlog::spdlog Threads::Threads) add_executable(latency latency.cpp) target_link_libraries(latency spdlog::spdlog Threads::Threads) file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/logs") Loading
.gitignore +2 −5 Original line number Diff line number Diff line Loading @@ -66,6 +66,3 @@ install_manifest.txt # idea .idea/ No newline at end of file # vscode .vscode/ No newline at end of file
.travis.yml +113 −91 Original line number Diff line number Diff line Loading @@ -2,23 +2,9 @@ # - Louis Dionne's Hana: https://github.com/ldionne/hana # - Paul Fultz II's FIT: https://github.com/pfultz2/Fit # - Eric Niebler's range-v3: https://github.com/ericniebler/range-v3 sudo: required language: cpp # Test matrix: # - Build matrix per compiler: C++11/C++14 + Debug/Release # - Optionally: AddressSanitizer (ASAN) # - Valgrind: all release builds are also tested with valgrind # - clang 3.4, 3.5, 3.6, trunk # - Note: 3.4 and trunk are tested with/without ASAN, # the rest is only tested with ASAN=On. # - gcc 4.9, 5.0 # matrix: include: # Test gcc-4.8: C++11, Build=Debug/Release, ASAN=Off - env: GCC_VERSION=4.8 BUILD_TYPE=Debug CPP=11 ASAN=Off LIBCXX=Off os: linux addons: &gcc48 apt: packages: Loading @@ -27,65 +13,101 @@ matrix: sources: - ubuntu-toolchain-r-test - env: GCC_VERSION=4.8 BUILD_TYPE=Release CPP=11 ASAN=Off LIBCXX=Off os: linux addons: *gcc48 addons: &gcc7 apt: packages: - g++-7 - valgrind sources: - ubuntu-toolchain-r-test # Test gcc-4.9: C++11, Build=Debug/Release, ASAN=Off - env: GCC_VERSION=4.9 BUILD_TYPE=Debug CPP=11 ASAN=Off LIBCXX=Off os: linux addons: &gcc49 addons: &clang35 apt: packages: - g++-4.9 - clang-3.5 - valgrind sources: - ubuntu-toolchain-r-test - llvm-toolchain-precise-3.5 addons: &clang6 apt: packages: - clang-6.0 - valgrind sources: - ubuntu-toolchain-r-test - llvm-toolchain-trusty-6.0 matrix: include: # Test gcc-4.8: C++11, Build=Debug/Release - env: GCC_VERSION=4.8 BUILD_TYPE=Debug CPP=11 os: linux addons: *gcc48 - env: GCC_VERSION=4.8 BUILD_TYPE=Release CPP=11 os: linux addons: *gcc48 - env: GCC_VERSION=7 BUILD_TYPE=Release CPP=11 os: linux addons: *gcc7 # Test clang-3.5: C++11, Build=Debug/Release - env: CLANG_VERSION=3.5 BUILD_TYPE=Debug CPP=11 os: linux addons: *clang35 - env: CLANG_VERSION=3.5 BUILD_TYPE=Release CPP=11 os: linux addons: *clang35 # Test clang-6.0: C++11, Build=Debug, ASAN=On - env: CLANG_VERSION=6.0 BUILD_TYPE=Debug CPP=11 ASAN=On TSAN=Off os: linux addons: *clang6 - env: CLANG_VERSION=6.0 BUILD_TYPE=Release CPP=11 ASAN=On TSAN=Off os: linux addons: *clang6 - env: GCC_VERSION=4.9 BUILD_TYPE=Release CPP=11 ASAN=Off LIBCXX=Off # Test clang-6.0: C++11, Build=Debug, TSAN=On - env: CLANG_VERSION=6.0 BUILD_TYPE=Debug CPP=11 ASAN=Off TSAN=On os: linux addons: *gcc49 addons: *clang6 - env: CLANG_VERSION=6.0 BUILD_TYPE=Release CPP=11 ASAN=Off TSAN=On os: linux addons: *clang6 # Install dependencies before_install: - export CHECKOUT_PATH=`pwd`; before_script: - if [ -n "$GCC_VERSION" ]; then export CXX="g++-${GCC_VERSION}" CC="gcc-${GCC_VERSION}"; fi - if [ -n "$CLANG_VERSION" ]; then export CXX="clang++-${CLANG_VERSION}" CC="clang-${CLANG_VERSION}"; fi - if [ "$CLANG_VERSION" == "3.4" ]; then export CXX="/usr/local/clang-3.4/bin/clang++" CC="/usr/local/clang-3.4/bin/clang"; fi - which $CXX - which $CC - which valgrind - if [ -n "$CLANG_VERSION" ]; then sudo CXX=$CXX CC=$CC ./tests/install_libcxx.sh; fi - $CXX --version - cmake --version - valgrind --version install: - cd $CHECKOUT_PATH # Workaround for valgrind bug: https://bugs.kde.org/show_bug.cgi?id=326469. # It is fixed in valgrind 3.10 so this won't be necessary if someone # replaces the current valgrind (3.7) with valgrind-3.10 - sed -i 's/march=native/msse4.2/' example/Makefile - if [ ! -d build ]; then mkdir build; fi - export CXX_FLAGS="-I${CHECKOUT_PATH}/include" - export CXX_LINKER_FLAGS="" - if [ -z "$BUILD_TYPE" ]; then export BUILD_TYPE=Release; fi - if [ "$ASAN" == "On"]; then export CXX_FLAGS="${CXX_FLAGS} -fsanitize=address,undefined,integer -fno-omit-frame-pointer -fno-sanitize=unsigned-integer-overflow"; fi - if [ -n "$CLANG_VERSION" ]; then CXX_FLAGS="${CXX_FLAGS} -D__extern_always_inline=inline"; fi - if [ "$LIBCXX" == "On" ]; then CXX_FLAGS="${CXX_FLAGS} -stdlib=libc++ -I/usr/include/c++/v1/"; fi - if [ "$LIBCXX" == "On" ]; then CXX_LINKER_FLAGS="${CXX_FLAGS} -L/usr/lib/ -lc++"; fi - CXX_FLAGS="${CXX_FLAGS} -std=c++${CPP}" # Build examples - cd example - if [ "$BUILD_TYPE" == "Release" ]; then make rebuild CXXFLAGS="${CXX_FLAGS} ${CXX_LINKER_FLAGS}" VERBOSE=1; export BIN=example; fi - if [ "$BUILD_TYPE" == "Debug" ]; then make rebuild debug CXXFLAGS="${CXX_FLAGS} ${CXX_LINKER_FLAGS}" VERBOSE=1; export BIN=example-debug; fi script: - cd ${TRAVIS_BUILD_DIR} - mkdir -p build && cd build - | cmake .. \ --warn-uninitialized \ -DCMAKE_BUILD_TYPE=$BUILD_TYPE \ -DCMAKE_CXX_STANDARD=$CPP \ -DSPDLOG_BUILD_EXAMPLES=ON \ -DSPDLOG_BUILD_BENCH=OFF \ -DSPDLOG_SANITIZE_ADDRESS=$ASAN \ -DSPDLOG_SANITIZE_THREAD=$TSAN - make VERBOSE=1 -j2 - ctest -j2 --output-on-failure script: - ./"${BIN}" - valgrind --trace-children=yes --leak-check=full ./"${BIN}" - cd $CHECKOUT_PATH/tests; make rebuild; ./tests - cd $CHECKOUT_PATH/tests; STYLE=printf make rebuild; ./tests notifications: email: false
CMakeLists.txt +27 −3 Original line number Diff line number Diff line Loading @@ -4,27 +4,47 @@ # cmake_minimum_required(VERSION 3.1) project(spdlog VERSION 0.17.0 LANGUAGES CXX) project(spdlog VERSION 1.1.0 LANGUAGES CXX) include(CTest) include(CMakeDependentOption) include(GNUInstallDirs) #--------------------------------------------------------------------------------------- # set default build to release #--------------------------------------------------------------------------------------- if(NOT CMAKE_BUILD_TYPE) set(CMAKE_BUILD_TYPE "Release" CACHE STRING "Choose Release or Debug" FORCE) endif() message(STATUS "Build type: " ${CMAKE_BUILD_TYPE}) #--------------------------------------------------------------------------------------- # compiler config #--------------------------------------------------------------------------------------- set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_EXTENSIONS OFF) if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" OR "${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang") set(CMAKE_CXX_FLAGS "-Wall -O3 ${CMAKE_CXX_FLAGS}") add_compile_options("-Wall") add_compile_options("-Wextra") add_compile_options("-pedantic") endif() #--------------------------------------------------------------------------------------- # address sanitizers check #--------------------------------------------------------------------------------------- include(cmake/sanitizers.cmake) #--------------------------------------------------------------------------------------- # spdlog target #--------------------------------------------------------------------------------------- add_library(spdlog INTERFACE) add_library(spdlog::spdlog ALIAS spdlog) option(SPDLOG_BUILD_EXAMPLES "Build examples" ON) option(SPDLOG_BUILD_BENCH "Build benchmarks" ON) option(SPDLOG_BUILD_EXAMPLES "Build examples" OFF) cmake_dependent_option(SPDLOG_BUILD_TESTING "Build spdlog tests" ON "BUILD_TESTING" OFF Loading @@ -47,6 +67,10 @@ if(SPDLOG_BUILD_TESTING) add_subdirectory(tests) endif() if(SPDLOG_BUILD_BENCH) add_subdirectory(bench) endif() #--------------------------------------------------------------------------------------- # Install/export targets and files #--------------------------------------------------------------------------------------- Loading
README.md +195 −134 Original line number Diff line number Diff line Loading @@ -6,7 +6,7 @@ Very fast, header only, C++ logging library. [ to your build tree and use a C++11 compiler. * Copy the source [folder](https://github.com/gabime/spdlog/tree/v1.x/include/spdlog) to your build tree and use a C++11 compiler. #### Or use your favorite package manager: Loading @@ -20,7 +20,7 @@ Very fast, header only, C++ logging library. [ * Mac OSX (clang 3.5+) * Android Loading @@ -28,9 +28,8 @@ Very fast, header only, C++ logging library. [ below). * Headers only, just copy and use. * Feature rich [call style](#usage-example) using the excellent [fmt](https://github.com/fmtlib/fmt) library. * Optional printf syntax support. * Asynchronous mode (optional) * Feature rich using the excellent [fmt](https://github.com/fmtlib/fmt) library. * Fast asynchronous mode (optional) * [Custom](https://github.com/gabime/spdlog/wiki/3.-Custom-formatting) formatting. * Conditional Logging * Multi/Single threaded loggers. Loading @@ -47,52 +46,51 @@ Very fast, header only, C++ logging library. [ comparing popular log libraries under Ubuntu 64 bit, Intel i7-4770 CPU @ 3.40GHz Below are some [benchmarks](https://github.com/gabime/spdlog/blob/v1.x/bench/bench.cpp) done in Ubuntu 64 bit, Intel i7-4770 CPU @ 3.40GHz #### Synchronous mode Time needed to log 1,000,000 lines in synchronous mode (in seconds, the best of 3 runs): |threads|boost log 1.54|glog |easylogging |spdlog| |-------|:-------:|:-----:|----------:|------:| |1| 4.169s |1.066s |0.975s |0.392s| |10| 6.180s |3.032s |2.857s |0.773s| |100| 5.981s |1.139s |4.512s |0.587s| ``` ******************************************************************************* Single thread, 1,000,000 iterations ******************************************************************************* basic_st... Elapsed: 0.226664 4,411,806/sec rotating_st... Elapsed: 0.214339 4,665,499/sec daily_st... Elapsed: 0.211292 4,732,797/sec null_st... Elapsed: 0.102815 9,726,227/sec ******************************************************************************* 10 threads sharing same logger, 1,000,000 iterations ******************************************************************************* basic_mt... Elapsed: 0.882268 1,133,441/sec rotating_mt... Elapsed: 0.875515 1,142,184/sec daily_mt... Elapsed: 0.879573 1,136,915/sec null_mt... Elapsed: 0.220114 4,543,105/sec ``` #### Asynchronous mode Time needed to log 1,000,000 lines in asynchronous mode, i.e. the time it takes to put them in the async queue (in seconds, the best of 3 runs): |threads|g2log <sup>async logger</sup> |spdlog <sup>async mode</sup>| |:-------|:-----:|-------------------------:| |1| 1.850s |0.39s | |10| 0.943s |0.416s| |100| 0.959s |0.413s| ``` ******************************************************************************* 10 threads sharing same logger, 1,000,000 iterations ******************************************************************************* async... Elapsed: 0.429088 2,330,524/sec async... Elapsed: 0.411501 2,430,126/sec async... Elapsed: 0.428979 2,331,116/sec ``` ## Usage samples ## Usage Example ```c++ #include "spdlog/spdlog.h" #include <iostream> #include <memory> void async_example(); void syslog_example(); void user_defined_example(); void err_handler_example(); namespace spd = spdlog; int main(int, char*[]) { try #include "spdlog/sinks/stdout_color_sinks.h" void stdout_example() { // Console logger with color auto console = spd::stdout_color_mt("console"); // create color multi threaded logger auto console = spdlog::stdout_color_mt("console"); console->info("Welcome to spdlog!"); console->error("Some error message with arg{}..", 1); console->error("Some error message with arg: {}", 1); auto err_logger = spdlog::stderr_color_mt("stderr"); err_logger->error("Some error message"); // Formatting examples console->warn("Easy padding in numbers like {:08d}", 12); Loading @@ -101,93 +99,135 @@ int main(int, char*[]) console->info("Positional args are {1} {0}..", "too", "supported"); console->info("{:<30}", "left aligned"); // Use global registry to retrieve loggers spd::get("console")->info("loggers can be retrieved from a global registry using the spdlog::get(logger_name) function"); // Create basic file logger (not rotated) auto my_logger = spd::basic_logger_mt("basic_logger", "logs/basic.txt"); my_logger->info("Some log message"); // Create a file rotating logger with 5mb size max and 3 rotated files auto rotating_logger = spd::rotating_logger_mt("some_logger_name", "logs/mylogfile.txt", 1048576 * 5, 3); for (int i = 0; i < 10; ++i) rotating_logger->info("{} * {} equals {:>10}", i, i, i*i); // Create a daily logger - a new file is created every day on 2:30am auto daily_logger = spd::daily_logger_mt("daily_logger", "logs/daily.txt", 2, 30); // trigger flush if the log severity is error or higher daily_logger->flush_on(spd::level::err); daily_logger->info(123.44); // Customize msg format for all messages spd::set_pattern("[%^+++%$] [%H:%M:%S %z] [thread %t] %v"); console->info("This an info message with custom format (and custom color range between the '%^' and '%$')"); console->error("This an error message with custom format (and custom color range between the '%^' and '%$')"); spdlog::get("console")->info("loggers can be retrieved from a global registry using the spdlog::get(logger_name)"); // Runtime log levels spd::set_level(spd::level::info); //Set global log level to info spdlog::set_level(spdlog::level::info); // Set global log level to info console->debug("This message should not be displayed!"); console->set_level(spd::level::debug); // Set specific logger's log level console->set_level(spdlog::level::trace); // Set specific logger's log level console->debug("This message should be displayed.."); // Customize msg format for all loggers spdlog::set_pattern("[%H:%M:%S %z] [%n] [%^---%L---%$] [thread %t] %v"); console->info("This an info message with custom format"); // Compile time log levels // define SPDLOG_DEBUG_ON or SPDLOG_TRACE_ON SPDLOG_TRACE(console, "Enabled only #ifdef SPDLOG_TRACE_ON..{} ,{}", 1, 3.23); SPDLOG_DEBUG(console, "Enabled only #ifdef SPDLOG_DEBUG_ON.. {} ,{}", 1, 3.23); } ``` --- #### Basic file logger ```c++ #include "spdlog/sinks/basic_file_sink.h" void basic_logfile_example() { try { auto my_logger = spdlog::basic_logger_mt("basic_logger", "logs/basic-log.txt"); } catch (const spdlog::spdlog_ex &ex) { std::cout << "Log init failed: " << ex.what() << std::endl; return 1; } } ``` --- #### Rotating files ```c++ #include "spdlog/sinks/rotating_file_sink.h" void rotating_example() { // Create a file rotating logger with 5mb size max and 3 rotated files auto rotating_logger = spdlog::rotating_logger_mt("some_logger_name", "logs/rotating.txt", 1048576 * 5, 3); } ``` // Asynchronous logging is very fast.. // Just call spdlog::set_async_mode(q_size) and all created loggers from now on will be asynchronous.. async_example(); --- #### Daily files ```c++ // syslog example. linux/osx only syslog_example(); #include "spdlog/sinks/daily_file_sink.h" void daily_example() { // Create a daily logger - a new file is created every day on 2:30am auto daily_logger = spdlog::daily_logger_mt("daily_logger", "logs/daily.txt", 2, 30); } // android example. compile with NDK android_example(); ``` // Log user-defined types example user_defined_example(); --- #### Periodic flush ```c++ // periodically flush all *registered* loggers every 3 seconds: // warning: only use if all your loggers are thread safe! spdlog::flush_every(std::chrono::seconds(3)); // Change default log error handler err_handler_example(); ``` // Apply a function on all registered loggers spd::apply_all([&](std::shared_ptr<spd::logger> l) { l->info("End of example."); }); // Release and close all loggers spd::drop_all(); } // Exceptions will only be thrown upon failed logger or sink construction (not during logging) catch (const spd::spdlog_ex& ex) --- #### Logger with multi sinks - each with different format and log level ```c++ // create logger with 2 targets with different log levels and formats. // the console will show only warnings or errors, while the file will log all. void multi_sink_example() { std::cout << "Log init failed: " << ex.what() << std::endl; return 1; } auto console_sink = std::make_shared<spdlog::sinks::stdout_color_sink_mt>(); console_sink->set_level(spdlog::level::warn); console_sink->set_pattern("[multi_sink_example] [%^%l%$] %v"); auto file_sink = std::make_shared<spdlog::sinks::basic_file_sink_mt>("logs/multisink.txt", true); file_sink->set_level(spdlog::level::trace); spdlog::logger logger("multi_sink", {console_sink, file_sink}); logger.set_level(spdlog::level::debug); logger.warn("this should appear in both console and file"); logger.info("this message should not appear in the console, only in the file"); } ``` --- #### Asynchronous logging ```c++ #include "spdlog/async.h" #include "spdlog/sinks/basic_file_sink.h" void async_example() { size_t q_size = 4096; spd::set_async_mode(q_size); auto async_file = spd::daily_logger_st("async_file_logger", "logs/async_log.txt"); for (int i = 0; i < 100; ++i) async_file->info("Async message #{}", i); // default thread pool settings can be modified *before* creating the async logger: // spdlog::init_thread_pool(8192, 1); // queue with 8k items and 1 backing thread. auto async_file = spdlog::basic_logger_mt<spdlog::async_factory>("async_file_logger", "logs/async_log.txt"); // alternatively: // auto async_file = spdlog::create_async<spdlog::sinks::basic_file_sink_mt>("async_file_logger", "logs/async_log.txt"); } //syslog example void syslog_example() ``` --- #### Asynchronous logger with multi sinks ```c++ #include "spdlog/sinks/stdout_color_sinks.h" #include "spdlog/sinks/rotating_file_sink.h" void multi_sink_example2() { #ifdef SPDLOG_ENABLE_SYSLOG std::string ident = "spdlog-example"; auto syslog_logger = spd::syslog_logger("syslog", ident, LOG_PID); syslog_logger->warn("This is warning that will end up in syslog.."); #endif spdlog::init_thread_pool(8192, 1); auto stdout_sink = std::make_shared<spdlog::sinks::stdout_color_sink_mt >(); auto rotating_sink = std::make_shared<spdlog::sinks::rotating_file_sink_mt>("mylog.txt", 1024*1024*10, 3); std::vector<spdlog::sink_ptr> sinks {stdout_sink, rotating_sink}; auto logger = std::make_shared<spdlog::async_logger>("loggername", sinks.begin(), sinks.end(), spdlog::thread_pool(), spdlog::async_overflow_policy::block); spdlog::register_logger(logger); } ``` --- #### User defined types ```c++ // user defined types logging by implementing operator<< #include "spdlog/fmt/ostr.h" // must be included struct my_type { int i; Loading @@ -198,23 +238,44 @@ struct my_type } }; #include <spdlog/fmt/ostr.h> // must be included void user_defined_example() { spd::get("console")->info("user defined type: {}", my_type { 14 }); spdlog::get("console")->info("user defined type: {}", my_type{14}); } // //custom error handler // ``` --- #### Custom error handler ```c++ void err_handler_example() { spd::set_error_handler([](const std::string& msg) { std::cerr << "my err handler: " << msg << std::endl; }); // (or logger->set_error_handler(..) to set for specific logger) // can be set globally or per logger(logger->set_error_handler(..)) spdlog::set_error_handler([](const std::string &msg) { spdlog::get("console")->error("*** LOGGER ERROR ***: {}", msg); }); spdlog::get("console")->info("some invalid message to trigger an error {}{}{}{}", 3); } ``` --- #### syslog ```c++ #include "spdlog/sinks/syslog_sink.h" void syslog_example() { std::string ident = "spdlog-example"; auto syslog_logger = spdlog::syslog_logger_mt("syslog", ident, LOG_PID); syslog_logger->warn("This is warning that will end up in syslog."); } ``` --- #### Android example ```c++ #incude "spdlog/sinks/android_sink.h" void android_example() { std::string tag = "spdlog-android"; auto android_logger = spdlog::android_logger("android", tag); android_logger->critical("Use \"adb shell logcat\" to view this message."); } ``` ## Documentation Loading
bench/CMakeLists.txt 0 → 100644 +43 −0 Original line number Diff line number Diff line # *************************************************************************/ # * Copyright (c) 2015 Ruslan Baratov. */ # * */ # * Permission is hereby granted, free of charge, to any person obtaining */ # * a copy of this software and associated documentation files (the */ # * "Software"), to deal in the Software without restriction, including */ # * without limitation the rights to use, copy, modify, merge, publish, */ # * distribute, sublicense, and/or sell copies of the Software, and to */ # * permit persons to whom the Software is furnished to do so, subject to */ # * the following conditions: */ # * */ # * The above copyright notice and this permission notice shall be */ # * included in all copies or substantial portions of the Software. */ # * */ # * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ # * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ # * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ # * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ # * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ # * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ # * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ # *************************************************************************/ cmake_minimum_required(VERSION 3.1) project(SpdlogBench CXX) if(NOT TARGET spdlog) # Stand-alone build find_package(spdlog CONFIG REQUIRED) endif() find_package(Threads REQUIRED) add_executable(bench bench.cpp) target_link_libraries(bench spdlog::spdlog Threads::Threads) add_executable(async_bench async_bench.cpp) target_link_libraries(async_bench spdlog::spdlog Threads::Threads) add_executable(latency latency.cpp) target_link_libraries(latency spdlog::spdlog Threads::Threads) file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/logs")