astyle
This commit is contained in:
parent
9230d9e63d
commit
495ecaeaee
216
.travis.yml
216
.travis.yml
@ -1,108 +1,108 @@
|
|||||||
# Adapted from various sources, including:
|
# Adapted from various sources, including:
|
||||||
# - Louis Dionne's Hana: https://github.com/ldionne/hana
|
# - Louis Dionne's Hana: https://github.com/ldionne/hana
|
||||||
# - Paul Fultz II's FIT: https://github.com/pfultz2/Fit
|
# - Paul Fultz II's FIT: https://github.com/pfultz2/Fit
|
||||||
# - Eric Niebler's range-v3: https://github.com/ericniebler/range-v3
|
# - Eric Niebler's range-v3: https://github.com/ericniebler/range-v3
|
||||||
language: cpp
|
language: cpp
|
||||||
|
|
||||||
# Test matrix:
|
# Test matrix:
|
||||||
# - Build matrix per compiler: C++11/C++14 + Debug/Release
|
# - Build matrix per compiler: C++11/C++14 + Debug/Release
|
||||||
# - Optionally: AddressSanitizer (ASAN)
|
# - Optionally: AddressSanitizer (ASAN)
|
||||||
# - Valgrind: all release builds are also tested with valgrind
|
# - Valgrind: all release builds are also tested with valgrind
|
||||||
# - clang 3.4, 3.5, 3.6, trunk
|
# - clang 3.4, 3.5, 3.6, trunk
|
||||||
# - Note: 3.4 and trunk are tested with/without ASAN,
|
# - Note: 3.4 and trunk are tested with/without ASAN,
|
||||||
# the rest is only tested with ASAN=On.
|
# the rest is only tested with ASAN=On.
|
||||||
# - gcc 4.9, 5.0
|
# - gcc 4.9, 5.0
|
||||||
#
|
#
|
||||||
matrix:
|
matrix:
|
||||||
include:
|
include:
|
||||||
# Test clang-3.5: C++11/C++14, Buidd=Debug/Release, ASAN=On/Off
|
# Test clang-3.5: C++11/C++14, Buidd=Debug/Release, ASAN=On/Off
|
||||||
- env: CLANG_VERSION=3.5 BUILD_TYPE=Debug CPP=11 ASAN=On LIBCXX=On
|
- env: CLANG_VERSION=3.5 BUILD_TYPE=Debug CPP=11 ASAN=On LIBCXX=On
|
||||||
os: linux
|
os: linux
|
||||||
addons: &clang35
|
addons: &clang35
|
||||||
apt:
|
apt:
|
||||||
packages:
|
packages:
|
||||||
- clang-3.5
|
- clang-3.5
|
||||||
- valgrind
|
- valgrind
|
||||||
sources:
|
sources:
|
||||||
- ubuntu-toolchain-r-test
|
- ubuntu-toolchain-r-test
|
||||||
- llvm-toolchain-precise-3.5
|
- llvm-toolchain-precise-3.5
|
||||||
|
|
||||||
|
|
||||||
- env: CLANG_VERSION=3.5 BUILD_TYPE=Release CPP=11 ASAN=Off LIBCXX=On
|
- env: CLANG_VERSION=3.5 BUILD_TYPE=Release CPP=11 ASAN=Off LIBCXX=On
|
||||||
os: linux
|
os: linux
|
||||||
addons: *clang35
|
addons: *clang35
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Test gcc-4.8: C++11, Build=Debug/Release, ASAN=Off
|
# 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
|
- env: GCC_VERSION=4.8 BUILD_TYPE=Debug CPP=11 ASAN=Off LIBCXX=Off
|
||||||
os: linux
|
os: linux
|
||||||
addons: &gcc48
|
addons: &gcc48
|
||||||
apt:
|
apt:
|
||||||
packages:
|
packages:
|
||||||
- g++-4.8
|
- g++-4.8
|
||||||
- valgrind
|
- valgrind
|
||||||
sources:
|
sources:
|
||||||
- ubuntu-toolchain-r-test
|
- ubuntu-toolchain-r-test
|
||||||
|
|
||||||
- env: GCC_VERSION=4.8 BUILD_TYPE=Release CPP=11 ASAN=Off LIBCXX=Off
|
- env: GCC_VERSION=4.8 BUILD_TYPE=Release CPP=11 ASAN=Off LIBCXX=Off
|
||||||
os: linux
|
os: linux
|
||||||
addons: *gcc48
|
addons: *gcc48
|
||||||
|
|
||||||
# Test gcc-4.9: C++11, Build=Debug/Release, ASAN=Off
|
# 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
|
- env: GCC_VERSION=4.9 BUILD_TYPE=Debug CPP=11 ASAN=Off LIBCXX=Off
|
||||||
os: linux
|
os: linux
|
||||||
addons: &gcc49
|
addons: &gcc49
|
||||||
apt:
|
apt:
|
||||||
packages:
|
packages:
|
||||||
- g++-4.9
|
- g++-4.9
|
||||||
- valgrind
|
- valgrind
|
||||||
sources:
|
sources:
|
||||||
- ubuntu-toolchain-r-test
|
- ubuntu-toolchain-r-test
|
||||||
|
|
||||||
- env: GCC_VERSION=4.9 BUILD_TYPE=Release CPP=11 ASAN=Off LIBCXX=Off
|
- env: GCC_VERSION=4.9 BUILD_TYPE=Release CPP=11 ASAN=Off LIBCXX=Off
|
||||||
os: linux
|
os: linux
|
||||||
addons: *gcc49
|
addons: *gcc49
|
||||||
|
|
||||||
# Install dependencies
|
# Install dependencies
|
||||||
before_install:
|
before_install:
|
||||||
- export CHECKOUT_PATH=`pwd`;
|
- export CHECKOUT_PATH=`pwd`;
|
||||||
- if [ -n "$GCC_VERSION" ]; then export CXX="g++-${GCC_VERSION}" CC="gcc-${GCC_VERSION}"; fi
|
- 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 [ -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
|
- 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 $CXX
|
||||||
- which $CC
|
- which $CC
|
||||||
- which valgrind
|
- which valgrind
|
||||||
- if [ -n "$CLANG_VERSION" ]; then sudo CXX=$CXX CC=$CC ./tests/install_libcxx.sh; fi
|
- if [ -n "$CLANG_VERSION" ]; then sudo CXX=$CXX CC=$CC ./tests/install_libcxx.sh; fi
|
||||||
|
|
||||||
install:
|
install:
|
||||||
- cd $CHECKOUT_PATH
|
- cd $CHECKOUT_PATH
|
||||||
|
|
||||||
# Workaround for valgrind bug: https://bugs.kde.org/show_bug.cgi?id=326469.
|
# 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
|
# 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
|
# replaces the current valgrind (3.7) with valgrind-3.10
|
||||||
- sed -i 's/march=native/msse4.2/' example/Makefile
|
- sed -i 's/march=native/msse4.2/' example/Makefile
|
||||||
|
|
||||||
- if [ ! -d build ]; then mkdir build; fi
|
- if [ ! -d build ]; then mkdir build; fi
|
||||||
- export CXX_FLAGS="-I${CHECKOUT_PATH}/include"
|
- export CXX_FLAGS="-I${CHECKOUT_PATH}/include"
|
||||||
- export CXX_LINKER_FLAGS=""
|
- export CXX_LINKER_FLAGS=""
|
||||||
- if [ -z "$BUILD_TYPE" ]; then export BUILD_TYPE=Release; fi
|
- 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 [ "$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 [ -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_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
|
- if [ "$LIBCXX" == "On" ]; then CXX_LINKER_FLAGS="${CXX_FLAGS} -L/usr/lib/ -lc++"; fi
|
||||||
- CXX_FLAGS="${CXX_FLAGS} -std=c++${CPP}"
|
- CXX_FLAGS="${CXX_FLAGS} -std=c++${CPP}"
|
||||||
|
|
||||||
# Build examples
|
# Build examples
|
||||||
- cd example
|
- cd example
|
||||||
- if [ "$BUILD_TYPE" == "Release" ]; then make rebuild CXXFLAGS="${CXX_FLAGS} ${CXX_LINKER_FLAGS}" VERBOSE=1; export BIN=example; fi
|
- 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
|
- if [ "$BUILD_TYPE" == "Debug" ]; then make rebuild debug CXXFLAGS="${CXX_FLAGS} ${CXX_LINKER_FLAGS}" VERBOSE=1; export BIN=example-debug; fi
|
||||||
|
|
||||||
|
|
||||||
script:
|
script:
|
||||||
- ./"${BIN}"
|
- ./"${BIN}"
|
||||||
- valgrind --trace-children=yes --leak-check=full ./"${BIN}"
|
- valgrind --trace-children=yes --leak-check=full ./"${BIN}"
|
||||||
- cd $CHECKOUT_PATH/tests; make rebuild; ./tests
|
- cd $CHECKOUT_PATH/tests; make rebuild; ./tests
|
||||||
|
|
||||||
notifications:
|
notifications:
|
||||||
email: false
|
email: false
|
||||||
|
130
CMakeLists.txt
130
CMakeLists.txt
@ -1,65 +1,65 @@
|
|||||||
#
|
#
|
||||||
# Copyright(c) 2015 Ruslan Baratov.
|
# Copyright(c) 2015 Ruslan Baratov.
|
||||||
# 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.0)
|
cmake_minimum_required(VERSION 3.0)
|
||||||
project(spdlog VERSION 1.0.0)
|
project(spdlog VERSION 1.0.0)
|
||||||
|
|
||||||
set(CMAKE_CXX_STANDARD 11)
|
set(CMAKE_CXX_STANDARD 11)
|
||||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||||
|
|
||||||
add_library(spdlog INTERFACE)
|
add_library(spdlog INTERFACE)
|
||||||
|
|
||||||
option(SPDLOG_BUILD_EXAMPLES "Build examples" OFF)
|
option(SPDLOG_BUILD_EXAMPLES "Build examples" OFF)
|
||||||
|
|
||||||
target_include_directories(
|
target_include_directories(
|
||||||
spdlog
|
spdlog
|
||||||
INTERFACE
|
INTERFACE
|
||||||
"$<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/include>"
|
"$<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/include>"
|
||||||
"$<INSTALL_INTERFACE:include>"
|
"$<INSTALL_INTERFACE:include>"
|
||||||
)
|
)
|
||||||
|
|
||||||
if(SPDLOG_BUILD_EXAMPLES)
|
if(SPDLOG_BUILD_EXAMPLES)
|
||||||
enable_testing()
|
enable_testing()
|
||||||
add_subdirectory(example)
|
add_subdirectory(example)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
### Install ###
|
### Install ###
|
||||||
# * https://github.com/forexample/package-example
|
# * https://github.com/forexample/package-example
|
||||||
set(generated_dir "${CMAKE_CURRENT_BINARY_DIR}/generated")
|
set(generated_dir "${CMAKE_CURRENT_BINARY_DIR}/generated")
|
||||||
|
|
||||||
set(config_install_dir "lib/cmake/${PROJECT_NAME}")
|
set(config_install_dir "lib/cmake/${PROJECT_NAME}")
|
||||||
set(include_install_dir "include")
|
set(include_install_dir "include")
|
||||||
|
|
||||||
set(version_config "${generated_dir}/${PROJECT_NAME}ConfigVersion.cmake")
|
set(version_config "${generated_dir}/${PROJECT_NAME}ConfigVersion.cmake")
|
||||||
set(project_config "${generated_dir}/${PROJECT_NAME}Config.cmake")
|
set(project_config "${generated_dir}/${PROJECT_NAME}Config.cmake")
|
||||||
set(targets_export_name "${PROJECT_NAME}Targets")
|
set(targets_export_name "${PROJECT_NAME}Targets")
|
||||||
set(namespace "${PROJECT_NAME}::")
|
set(namespace "${PROJECT_NAME}::")
|
||||||
|
|
||||||
include(CMakePackageConfigHelpers)
|
include(CMakePackageConfigHelpers)
|
||||||
write_basic_package_version_file(
|
write_basic_package_version_file(
|
||||||
"${version_config}" COMPATIBILITY SameMajorVersion
|
"${version_config}" COMPATIBILITY SameMajorVersion
|
||||||
)
|
)
|
||||||
|
|
||||||
# Note: use 'targets_export_name'
|
# Note: use 'targets_export_name'
|
||||||
configure_file("cmake/Config.cmake.in" "${project_config}" @ONLY)
|
configure_file("cmake/Config.cmake.in" "${project_config}" @ONLY)
|
||||||
|
|
||||||
install(
|
install(
|
||||||
TARGETS spdlog
|
TARGETS spdlog
|
||||||
EXPORT "${targets_export_name}"
|
EXPORT "${targets_export_name}"
|
||||||
INCLUDES DESTINATION "${include_install_dir}"
|
INCLUDES DESTINATION "${include_install_dir}"
|
||||||
)
|
)
|
||||||
|
|
||||||
install(DIRECTORY "include/spdlog" DESTINATION "${include_install_dir}")
|
install(DIRECTORY "include/spdlog" DESTINATION "${include_install_dir}")
|
||||||
|
|
||||||
install(
|
install(
|
||||||
FILES "${project_config}" "${version_config}"
|
FILES "${project_config}" "${version_config}"
|
||||||
DESTINATION "${config_install_dir}"
|
DESTINATION "${config_install_dir}"
|
||||||
)
|
)
|
||||||
|
|
||||||
install(
|
install(
|
||||||
EXPORT "${targets_export_name}"
|
EXPORT "${targets_export_name}"
|
||||||
NAMESPACE "${namespace}"
|
NAMESPACE "${namespace}"
|
||||||
DESTINATION "${config_install_dir}"
|
DESTINATION "${config_install_dir}"
|
||||||
)
|
)
|
||||||
|
316
README.md
316
README.md
@ -1,158 +1,158 @@
|
|||||||
# spdlog
|
# spdlog
|
||||||
|
|
||||||
Very fast, header only, C++ logging library. [](https://travis-ci.org/gabime/spdlog)
|
Very fast, header only, C++ logging library. [](https://travis-ci.org/gabime/spdlog)
|
||||||
|
|
||||||
## Install
|
## Install
|
||||||
Just copy the source [folder](https://github.com/gabime/spdlog/tree/master/include/spdlog) to your build tree and use a C++11 compiler
|
Just copy the source [folder](https://github.com/gabime/spdlog/tree/master/include/spdlog) to your build tree and use a C++11 compiler
|
||||||
|
|
||||||
## Platforms
|
## Platforms
|
||||||
* Linux (gcc 4.8.1+, clang 3.5+)
|
* Linux (gcc 4.8.1+, clang 3.5+)
|
||||||
* Windows (visual studio 2013+, cygwin/mingw with g++ 4.9.1+)
|
* Windows (visual studio 2013+, cygwin/mingw with g++ 4.9.1+)
|
||||||
* Mac OSX (clang 3.5+)
|
* Mac OSX (clang 3.5+)
|
||||||
|
|
||||||
##Features
|
##Features
|
||||||
* Very fast - performance is the primary goal (see [benchmarks](#benchmarks) below).
|
* Very fast - performance is the primary goal (see [benchmarks](#benchmarks) below).
|
||||||
* Headers only.
|
* Headers only.
|
||||||
* No dependencies - just copy and use.
|
* No dependencies - just copy and use.
|
||||||
* Feature rich [call style](#usage-example) using the excellent [cppformat](http://cppformat.github.io/) library.
|
* Feature rich [call style](#usage-example) using the excellent [cppformat](http://cppformat.github.io/) library.
|
||||||
* ostream call style is supported too.
|
* ostream call style is supported too.
|
||||||
* Extremely fast asynchronous mode (optional) - using lockfree queues and other tricks to reach millions of calls/sec.
|
* Extremely fast asynchronous mode (optional) - using lockfree queues and other tricks to reach millions of calls/sec.
|
||||||
* [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:
|
||||||
* Rotating log files.
|
* Rotating log files.
|
||||||
* Daily log files.
|
* Daily log files.
|
||||||
* Console logging (including colors).
|
* Console logging (including colors).
|
||||||
* Linux syslog.
|
* Linux syslog.
|
||||||
* 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.
|
* Severity based filtering - threshold levels can be modified in runtime as well as in compile time.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Benchmarks
|
## Benchmarks
|
||||||
|
|
||||||
Below are some [benchmarks](bench) comparing popular log libraries under Ubuntu 64 bit, Intel i7-4770 CPU @ 3.40GHz
|
Below are some [benchmarks](bench) comparing popular log libraries under Ubuntu 64 bit, Intel i7-4770 CPU @ 3.40GHz
|
||||||
|
|
||||||
#### Synchronous mode
|
#### Synchronous mode
|
||||||
Time needed to log 1,000,000 lines in synchronous mode (in seconds, the best of 3 runs):
|
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|
|
|threads|boost log 1.54|glog |easylogging |spdlog|
|
||||||
|-------|:-------:|:-----:|----------:|------:|
|
|-------|:-------:|:-----:|----------:|------:|
|
||||||
|1| 4.169s |1.066s |0.975s |0.302s|
|
|1| 4.169s |1.066s |0.975s |0.302s|
|
||||||
|10| 6.180s |3.032s |2.857s |0.968s|
|
|10| 6.180s |3.032s |2.857s |0.968s|
|
||||||
|100| 5.981s |1.139s |4.512s |0.497s|
|
|100| 5.981s |1.139s |4.512s |0.497s|
|
||||||
|
|
||||||
|
|
||||||
#### Asynchronous mode
|
#### 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):
|
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>|
|
|threads|g2log <sup>async logger</sup> |spdlog <sup>async mode</sup>|
|
||||||
|:-------|:-----:|-------------------------:|
|
|:-------|:-----:|-------------------------:|
|
||||||
|1| 1.850s |0.216s |
|
|1| 1.850s |0.216s |
|
||||||
|10| 0.943s |0.173s|
|
|10| 0.943s |0.173s|
|
||||||
|100| 0.959s |0.202s|
|
|100| 0.959s |0.202s|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Usage Example
|
## Usage Example
|
||||||
```c++
|
```c++
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include "spdlog/spdlog.h"
|
#include "spdlog/spdlog.h"
|
||||||
|
|
||||||
int main(int, char* [])
|
int main(int, char* [])
|
||||||
{
|
{
|
||||||
namespace spd = spdlog;
|
namespace spd = spdlog;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// console logger (multithreaded and with color)
|
// console logger (multithreaded and with color)
|
||||||
auto console = spd::stdout_logger_mt("console", true);
|
auto console = spd::stdout_logger_mt("console", true);
|
||||||
console->info("Welcome to spdlog!") ;
|
console->info("Welcome to spdlog!") ;
|
||||||
console->info("An info message example {}..", 1);
|
console->info("An info message example {}..", 1);
|
||||||
console->info() << "Streams are supported too " << 1;
|
console->info() << "Streams are supported too " << 1;
|
||||||
|
|
||||||
//Formatting examples
|
//Formatting examples
|
||||||
console->info("Easy padding in numbers like {:08d}", 12);
|
console->info("Easy padding in numbers like {:08d}", 12);
|
||||||
console->info("Support for int: {0:d}; hex: {0:x}; oct: {0:o}; bin: {0:b}", 42);
|
console->info("Support for int: {0:d}; hex: {0:x}; oct: {0:o}; bin: {0:b}", 42);
|
||||||
console->info("Support for floats {:03.2f}", 1.23456);
|
console->info("Support for floats {:03.2f}", 1.23456);
|
||||||
console->info("Positional args are {1} {0}..", "too", "supported");
|
console->info("Positional args are {1} {0}..", "too", "supported");
|
||||||
|
|
||||||
console->info("{:<30}", "left aligned");
|
console->info("{:<30}", "left aligned");
|
||||||
console->info("{:>30}", "right aligned");
|
console->info("{:>30}", "right aligned");
|
||||||
console->info("{:^30}", "centered");
|
console->info("{:^30}", "centered");
|
||||||
|
|
||||||
//
|
//
|
||||||
// Runtime log levels
|
// Runtime log levels
|
||||||
//
|
//
|
||||||
spd::set_level(spd::level::info); //Set global log level to info
|
spd::set_level(spd::level::info); //Set global log level to info
|
||||||
console->debug("This message shold not be displayed!");
|
console->debug("This message shold not be displayed!");
|
||||||
console->set_level(spd::level::debug); // Set specific logger's log level
|
console->set_level(spd::level::debug); // Set specific logger's log level
|
||||||
console->debug("Now it should..");
|
console->debug("Now it should..");
|
||||||
|
|
||||||
//
|
//
|
||||||
// Create a file rotating logger with 5mb size max and 3 rotated files
|
// Create a file rotating logger with 5mb size max and 3 rotated files
|
||||||
//
|
//
|
||||||
auto file_logger = spd::rotating_logger_mt("file_logger", "logs/mylogfile", 1048576 * 5, 3);
|
auto file_logger = spd::rotating_logger_mt("file_logger", "logs/mylogfile", 1048576 * 5, 3);
|
||||||
for(int i = 0; i < 10; ++i)
|
for(int i = 0; i < 10; ++i)
|
||||||
file_logger->info("{} * {} equals {:>10}", i, i, i*i);
|
file_logger->info("{} * {} equals {:>10}", i, i, i*i);
|
||||||
|
|
||||||
//
|
//
|
||||||
// Create a daily logger - a new file is created every day on 2:30am
|
// 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", 2, 30);
|
auto daily_logger = spd::daily_logger_mt("daily_logger", "logs/daily", 2, 30);
|
||||||
|
|
||||||
//
|
//
|
||||||
// Customize msg format for all messages
|
// Customize msg format for all messages
|
||||||
//
|
//
|
||||||
spd::set_pattern("*** [%H:%M:%S %z] [thread %t] %v ***");
|
spd::set_pattern("*** [%H:%M:%S %z] [thread %t] %v ***");
|
||||||
file_logger->info("This is another message with custom format");
|
file_logger->info("This is another message with custom format");
|
||||||
|
|
||||||
spd::get("console")->info("loggers can be retrieved from a global registry using the spdlog::get(logger_name) function");
|
spd::get("console")->info("loggers can be retrieved from a global registry using the spdlog::get(logger_name) function");
|
||||||
|
|
||||||
//
|
//
|
||||||
// Compile time debug or trace macros.
|
// Compile time debug or trace macros.
|
||||||
// Enabled #ifdef SPDLOG_DEBUG_ON or #ifdef SPDLOG_TRACE_ON
|
// Enabled #ifdef SPDLOG_DEBUG_ON or #ifdef SPDLOG_TRACE_ON
|
||||||
//
|
//
|
||||||
SPDLOG_TRACE(console, "Enabled only #ifdef SPDLOG_TRACE_ON..{} ,{}", 1, 3.23);
|
SPDLOG_TRACE(console, "Enabled only #ifdef SPDLOG_TRACE_ON..{} ,{}", 1, 3.23);
|
||||||
SPDLOG_DEBUG(console, "Enabled only #ifdef SPDLOG_DEBUG_ON.. {} ,{}", 1, 3.23);
|
SPDLOG_DEBUG(console, "Enabled only #ifdef SPDLOG_DEBUG_ON.. {} ,{}", 1, 3.23);
|
||||||
|
|
||||||
//
|
//
|
||||||
// Asynchronous logging is very fast..
|
// Asynchronous logging is very fast..
|
||||||
// Just call spdlog::set_async_mode(q_size) and all created loggers from now on will be asynchronous..
|
// Just call spdlog::set_async_mode(q_size) and all created loggers from now on will be asynchronous..
|
||||||
//
|
//
|
||||||
size_t q_size = 1048576; //queue size must be power of 2
|
size_t q_size = 1048576; //queue size must be power of 2
|
||||||
spdlog::set_async_mode(q_size);
|
spdlog::set_async_mode(q_size);
|
||||||
auto async_file= spd::daily_logger_st("async_file_logger", "logs/async_log.txt");
|
auto async_file= spd::daily_logger_st("async_file_logger", "logs/async_log.txt");
|
||||||
async_file->info() << "This is async log.." << "Should be very fast!";
|
async_file->info() << "This is async log.." << "Should be very fast!";
|
||||||
|
|
||||||
//
|
//
|
||||||
// syslog example. linux only..
|
// syslog example. linux only..
|
||||||
//
|
//
|
||||||
#ifdef __linux__
|
#ifdef __linux__
|
||||||
std::string ident = "spdlog-example";
|
std::string ident = "spdlog-example";
|
||||||
auto syslog_logger = spd::syslog_logger("syslog", ident, LOG_PID);
|
auto syslog_logger = spd::syslog_logger("syslog", ident, LOG_PID);
|
||||||
syslog_logger->warn("This is warning that will end up in syslog. This is Linux only!");
|
syslog_logger->warn("This is warning that will end up in syslog. This is Linux only!");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
}
|
}
|
||||||
catch (const spd::spdlog_ex& ex)
|
catch (const spd::spdlog_ex& ex)
|
||||||
{
|
{
|
||||||
std::cout << "Log failed: " << ex.what() << std::endl;
|
std::cout << "Log failed: " << ex.what() << std::endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Example of user defined class with operator<<
|
// Example of user defined class with operator<<
|
||||||
class some_class {};
|
class some_class {};
|
||||||
std::ostream& operator<<(std::ostream& os, const some_class& c) { return os << "some_class"; }
|
std::ostream& operator<<(std::ostream& os, const some_class& c) { return os << "some_class"; }
|
||||||
|
|
||||||
void custom_class_example()
|
void custom_class_example()
|
||||||
{
|
{
|
||||||
some_class c;
|
some_class c;
|
||||||
spdlog::get("console")->info("custom class with operator<<: {}..", c);
|
spdlog::get("console")->info("custom class with operator<<: {}..", c);
|
||||||
spdlog::get("console")->info() << "custom class with operator<<: " << c << "..";
|
spdlog::get("console")->info() << "custom class with operator<<: " << c << "..";
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
## Documentation
|
## Documentation
|
||||||
Documentation can be found in the [wiki](https://github.com/gabime/spdlog/wiki/1.-QuickStart) pages.
|
Documentation can be found in the [wiki](https://github.com/gabime/spdlog/wiki/1.-QuickStart) pages.
|
||||||
|
130
bench/Makefile
130
bench/Makefile
@ -1,65 +1,65 @@
|
|||||||
CXX ?= g++
|
CXX ?= g++
|
||||||
CXXFLAGS = -march=native -Wall -Wextra -pedantic -std=c++11 -pthread -Wl,--no-as-needed -I../include
|
CXXFLAGS = -march=native -Wall -Wextra -pedantic -std=c++11 -pthread -Wl,--no-as-needed -I../include
|
||||||
CXX_RELEASE_FLAGS = -O3 -flto -DNDEBUG
|
CXX_RELEASE_FLAGS = -O3 -flto -DNDEBUG
|
||||||
|
|
||||||
|
|
||||||
binaries=spdlog-bench spdlog-bench-mt spdlog-async zf_log-bench zf_log-bench-mt boost-bench boost-bench-mt glog-bench glog-bench-mt g2log-async easylogging-bench easylogging-bench-mt
|
binaries=spdlog-bench spdlog-bench-mt spdlog-async zf_log-bench zf_log-bench-mt boost-bench boost-bench-mt glog-bench glog-bench-mt g2log-async easylogging-bench easylogging-bench-mt
|
||||||
|
|
||||||
all: $(binaries)
|
all: $(binaries)
|
||||||
|
|
||||||
spdlog-bench: spdlog-bench.cpp
|
spdlog-bench: spdlog-bench.cpp
|
||||||
$(CXX) spdlog-bench.cpp -o spdlog-bench $(CXXFLAGS) $(CXX_RELEASE_FLAGS)
|
$(CXX) spdlog-bench.cpp -o spdlog-bench $(CXXFLAGS) $(CXX_RELEASE_FLAGS)
|
||||||
|
|
||||||
spdlog-bench-mt: spdlog-bench-mt.cpp
|
spdlog-bench-mt: spdlog-bench-mt.cpp
|
||||||
$(CXX) spdlog-bench-mt.cpp -o spdlog-bench-mt $(CXXFLAGS) $(CXX_RELEASE_FLAGS)
|
$(CXX) spdlog-bench-mt.cpp -o spdlog-bench-mt $(CXXFLAGS) $(CXX_RELEASE_FLAGS)
|
||||||
|
|
||||||
spdlog-async: spdlog-async.cpp
|
spdlog-async: spdlog-async.cpp
|
||||||
$(CXX) spdlog-async.cpp -o spdlog-async $(CXXFLAGS) $(CXX_RELEASE_FLAGS)
|
$(CXX) spdlog-async.cpp -o spdlog-async $(CXXFLAGS) $(CXX_RELEASE_FLAGS)
|
||||||
|
|
||||||
|
|
||||||
ZF_LOG_FLAGS = -I../../zf_log.git/zf_log/
|
ZF_LOG_FLAGS = -I../../zf_log.git/zf_log/
|
||||||
zf_log-bench: zf_log-bench.cpp
|
zf_log-bench: zf_log-bench.cpp
|
||||||
$(CXX) zf_log-bench.cpp -o zf_log-bench $(CXXFLAGS) $(CXX_RELEASE_FLAGS) $(ZF_LOG_FLAGS)
|
$(CXX) zf_log-bench.cpp -o zf_log-bench $(CXXFLAGS) $(CXX_RELEASE_FLAGS) $(ZF_LOG_FLAGS)
|
||||||
|
|
||||||
zf_log-bench-mt: zf_log-bench-mt.cpp
|
zf_log-bench-mt: zf_log-bench-mt.cpp
|
||||||
$(CXX) zf_log-bench-mt.cpp -o zf_log-bench-mt $(CXXFLAGS) $(CXX_RELEASE_FLAGS) $(ZF_LOG_FLAGS)
|
$(CXX) zf_log-bench-mt.cpp -o zf_log-bench-mt $(CXXFLAGS) $(CXX_RELEASE_FLAGS) $(ZF_LOG_FLAGS)
|
||||||
|
|
||||||
|
|
||||||
BOOST_FLAGS = -DBOOST_LOG_DYN_LINK -I/usr/include -lboost_log -lboost_log_setup -lboost_filesystem -lboost_system -lboost_thread -lboost_regex -lboost_date_time -lboost_chrono
|
BOOST_FLAGS = -DBOOST_LOG_DYN_LINK -I/usr/include -lboost_log -lboost_log_setup -lboost_filesystem -lboost_system -lboost_thread -lboost_regex -lboost_date_time -lboost_chrono
|
||||||
|
|
||||||
boost-bench: boost-bench.cpp
|
boost-bench: boost-bench.cpp
|
||||||
$(CXX) boost-bench.cpp -o boost-bench $(CXXFLAGS) $(BOOST_FLAGS) $(CXX_RELEASE_FLAGS)
|
$(CXX) boost-bench.cpp -o boost-bench $(CXXFLAGS) $(BOOST_FLAGS) $(CXX_RELEASE_FLAGS)
|
||||||
|
|
||||||
boost-bench-mt: boost-bench-mt.cpp
|
boost-bench-mt: boost-bench-mt.cpp
|
||||||
$(CXX) boost-bench-mt.cpp -o boost-bench-mt $(CXXFLAGS) $(BOOST_FLAGS) $(CXX_RELEASE_FLAGS)
|
$(CXX) boost-bench-mt.cpp -o boost-bench-mt $(CXXFLAGS) $(BOOST_FLAGS) $(CXX_RELEASE_FLAGS)
|
||||||
|
|
||||||
|
|
||||||
GLOG_FLAGS = -lglog
|
GLOG_FLAGS = -lglog
|
||||||
glog-bench: glog-bench.cpp
|
glog-bench: glog-bench.cpp
|
||||||
$(CXX) glog-bench.cpp -o glog-bench $(CXXFLAGS) $(GLOG_FLAGS) $(CXX_RELEASE_FLAGS)
|
$(CXX) glog-bench.cpp -o glog-bench $(CXXFLAGS) $(GLOG_FLAGS) $(CXX_RELEASE_FLAGS)
|
||||||
|
|
||||||
glog-bench-mt: glog-bench-mt.cpp
|
glog-bench-mt: glog-bench-mt.cpp
|
||||||
$(CXX) glog-bench-mt.cpp -o glog-bench-mt $(CXXFLAGS) $(GLOG_FLAGS) $(CXX_RELEASE_FLAGS)
|
$(CXX) glog-bench-mt.cpp -o glog-bench-mt $(CXXFLAGS) $(GLOG_FLAGS) $(CXX_RELEASE_FLAGS)
|
||||||
|
|
||||||
|
|
||||||
G2LOG_FLAGS = -I/home/gabi/devel/g2log/g2log/src -L/home/gabi/devel/g2log/g2log -llib_g2logger
|
G2LOG_FLAGS = -I/home/gabi/devel/g2log/g2log/src -L/home/gabi/devel/g2log/g2log -llib_g2logger
|
||||||
g2log-async: g2log-async.cpp
|
g2log-async: g2log-async.cpp
|
||||||
$(CXX) g2log-async.cpp -o g2log-async $(CXXFLAGS) $(G2LOG_FLAGS) $(CXX_RELEASE_FLAGS)
|
$(CXX) g2log-async.cpp -o g2log-async $(CXXFLAGS) $(G2LOG_FLAGS) $(CXX_RELEASE_FLAGS)
|
||||||
|
|
||||||
|
|
||||||
EASYL_FLAGS = -I../../easylogging/src/
|
EASYL_FLAGS = -I../../easylogging/src/
|
||||||
easylogging-bench: easylogging-bench.cpp
|
easylogging-bench: easylogging-bench.cpp
|
||||||
$(CXX) easylogging-bench.cpp -o easylogging-bench $(CXXFLAGS) $(EASYL_FLAGS) $(CXX_RELEASE_FLAGS)
|
$(CXX) easylogging-bench.cpp -o easylogging-bench $(CXXFLAGS) $(EASYL_FLAGS) $(CXX_RELEASE_FLAGS)
|
||||||
easylogging-bench-mt: easylogging-bench-mt.cpp
|
easylogging-bench-mt: easylogging-bench-mt.cpp
|
||||||
$(CXX) easylogging-bench-mt.cpp -o easylogging-bench-mt $(CXXFLAGS) $(EASYL_FLAGS) $(CXX_RELEASE_FLAGS)
|
$(CXX) easylogging-bench-mt.cpp -o easylogging-bench-mt $(CXXFLAGS) $(EASYL_FLAGS) $(CXX_RELEASE_FLAGS)
|
||||||
|
|
||||||
.PHONY: clean
|
.PHONY: clean
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -f *.o logs/* $(binaries)
|
rm -f *.o logs/* $(binaries)
|
||||||
|
|
||||||
|
|
||||||
rebuild: clean all
|
rebuild: clean all
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
152
bench/run_all.sh
152
bench/run_all.sh
@ -1,76 +1,76 @@
|
|||||||
#~/bin/bash
|
#~/bin/bash
|
||||||
#execute each bench 3 times and print the timing
|
#execute each bench 3 times and print the timing
|
||||||
|
|
||||||
exec 2>&1
|
exec 2>&1
|
||||||
|
|
||||||
#execute and time given exe 3 times
|
#execute and time given exe 3 times
|
||||||
bench_exe ()
|
bench_exe ()
|
||||||
{
|
{
|
||||||
echo "**************** $1 ****************"
|
echo "**************** $1 ****************"
|
||||||
for i in {1..3}; do
|
for i in {1..3}; do
|
||||||
time ./$1 $2;
|
time ./$1 $2;
|
||||||
rm -f logs/*
|
rm -f logs/*
|
||||||
sleep 3
|
sleep 3
|
||||||
done;
|
done;
|
||||||
}
|
}
|
||||||
|
|
||||||
#execute given async tests 3 times (timing is already builtin)
|
#execute given async tests 3 times (timing is already builtin)
|
||||||
bench_async ()
|
bench_async ()
|
||||||
{
|
{
|
||||||
echo "**************** $1 ****************"
|
echo "**************** $1 ****************"
|
||||||
for i in {1..3}; do
|
for i in {1..3}; do
|
||||||
./$1 $2;
|
./$1 $2;
|
||||||
echo
|
echo
|
||||||
rm -f logs/*
|
rm -f logs/*
|
||||||
sleep 3
|
sleep 3
|
||||||
done;
|
done;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
echo "----------------------------------------------------------"
|
echo "----------------------------------------------------------"
|
||||||
echo "Single threaded benchmarks.. (1 thread, 1,000,000 lines)"
|
echo "Single threaded benchmarks.. (1 thread, 1,000,000 lines)"
|
||||||
echo "----------------------------------------------------------"
|
echo "----------------------------------------------------------"
|
||||||
for exe in boost-bench glog-bench easylogging-bench zf_log-bench spdlog-bench;
|
for exe in boost-bench glog-bench easylogging-bench zf_log-bench spdlog-bench;
|
||||||
do
|
do
|
||||||
bench_exe $exe 1
|
bench_exe $exe 1
|
||||||
done;
|
done;
|
||||||
|
|
||||||
echo "----------------------------------------------------------"
|
echo "----------------------------------------------------------"
|
||||||
echo "Multi threaded benchmarks.. (10 threads, 1,000,000 lines)"
|
echo "Multi threaded benchmarks.. (10 threads, 1,000,000 lines)"
|
||||||
echo "----------------------------------------------------------"
|
echo "----------------------------------------------------------"
|
||||||
for exe in boost-bench-mt glog-bench-mt easylogging-bench-mt zf_log-bench-mt spdlog-bench-mt;
|
for exe in boost-bench-mt glog-bench-mt easylogging-bench-mt zf_log-bench-mt spdlog-bench-mt;
|
||||||
do
|
do
|
||||||
bench_exe $exe 10
|
bench_exe $exe 10
|
||||||
done;
|
done;
|
||||||
|
|
||||||
echo "----------------------------------------------------------"
|
echo "----------------------------------------------------------"
|
||||||
echo "Multi threaded benchmarks.. (100 threads, 1,000,000 lines)"
|
echo "Multi threaded benchmarks.. (100 threads, 1,000,000 lines)"
|
||||||
echo "----------------------------------------------------------"
|
echo "----------------------------------------------------------"
|
||||||
for exe in boost-bench-mt glog-bench-mt easylogging-bench-mt zf_log-bench-mt spdlog-bench-mt;
|
for exe in boost-bench-mt glog-bench-mt easylogging-bench-mt zf_log-bench-mt spdlog-bench-mt;
|
||||||
do
|
do
|
||||||
bench_exe $exe 100
|
bench_exe $exe 100
|
||||||
done;
|
done;
|
||||||
|
|
||||||
echo "---------------------------------------------------------------"
|
echo "---------------------------------------------------------------"
|
||||||
echo "Async, single threaded benchmark.. (1 thread, 1,000,000 lines)"
|
echo "Async, single threaded benchmark.. (1 thread, 1,000,000 lines)"
|
||||||
echo "---------------------------------------------------------------"
|
echo "---------------------------------------------------------------"
|
||||||
for exe in spdlog-async g2log-async
|
for exe in spdlog-async g2log-async
|
||||||
do
|
do
|
||||||
bench_async $exe 1
|
bench_async $exe 1
|
||||||
done;
|
done;
|
||||||
|
|
||||||
echo "---------------------------------------------------------------"
|
echo "---------------------------------------------------------------"
|
||||||
echo "Async, multi threaded benchmark.. (10 threads, 1,000,000 lines)"
|
echo "Async, multi threaded benchmark.. (10 threads, 1,000,000 lines)"
|
||||||
echo "---------------------------------------------------------------"
|
echo "---------------------------------------------------------------"
|
||||||
for exe in spdlog-async g2log-async
|
for exe in spdlog-async g2log-async
|
||||||
do
|
do
|
||||||
bench_async $exe 10
|
bench_async $exe 10
|
||||||
done;
|
done;
|
||||||
|
|
||||||
echo "---------------------------------------------------------------"
|
echo "---------------------------------------------------------------"
|
||||||
echo "Async, multi threaded benchmark.. (100 threads, 1,000,000 lines)"
|
echo "Async, multi threaded benchmark.. (100 threads, 1,000,000 lines)"
|
||||||
echo "---------------------------------------------------------------"
|
echo "---------------------------------------------------------------"
|
||||||
for exe in spdlog-async g2log-async
|
for exe in spdlog-async g2log-async
|
||||||
do
|
do
|
||||||
bench_async $exe 100
|
bench_async $exe 100
|
||||||
done;
|
done;
|
||||||
|
@ -1,62 +1,62 @@
|
|||||||
//
|
//
|
||||||
// Copyright(c) 2015 Gabi Melman.
|
// Copyright(c) 2015 Gabi Melman.
|
||||||
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||||
//
|
//
|
||||||
|
|
||||||
#include <thread>
|
#include <thread>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include "spdlog/spdlog.h"
|
#include "spdlog/spdlog.h"
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
int main(int argc, char* argv[])
|
int main(int argc, char* argv[])
|
||||||
{
|
{
|
||||||
|
|
||||||
using namespace std::chrono;
|
using namespace std::chrono;
|
||||||
using clock=steady_clock;
|
using clock=steady_clock;
|
||||||
namespace spd = spdlog;
|
namespace spd = spdlog;
|
||||||
|
|
||||||
int thread_count = 10;
|
int thread_count = 10;
|
||||||
if(argc > 1)
|
if(argc > 1)
|
||||||
thread_count = ::atoi(argv[1]);
|
thread_count = ::atoi(argv[1]);
|
||||||
int howmany = 1000000;
|
int howmany = 1000000;
|
||||||
|
|
||||||
spd::set_async_mode(1048576);
|
spd::set_async_mode(1048576);
|
||||||
auto logger = spdlog::create<spd::sinks::simple_file_sink_mt>("file_logger", "logs/spd-bench-async.txt", false);
|
auto logger = spdlog::create<spd::sinks::simple_file_sink_mt>("file_logger", "logs/spd-bench-async.txt", false);
|
||||||
logger->set_pattern("[%Y-%b-%d %T.%e]: %v");
|
logger->set_pattern("[%Y-%b-%d %T.%e]: %v");
|
||||||
|
|
||||||
|
|
||||||
std::atomic<int > msg_counter {0};
|
std::atomic<int > msg_counter {0};
|
||||||
vector<thread> threads;
|
vector<thread> threads;
|
||||||
auto start = clock::now();
|
auto start = clock::now();
|
||||||
for (int t = 0; t < thread_count; ++t)
|
for (int t = 0; t < thread_count; ++t)
|
||||||
{
|
{
|
||||||
threads.push_back(std::thread([&]()
|
threads.push_back(std::thread([&]()
|
||||||
{
|
{
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
int counter = ++msg_counter;
|
int counter = ++msg_counter;
|
||||||
if (counter > howmany) break;
|
if (counter > howmany) break;
|
||||||
logger->info() << "spdlog message #" << counter << ": This is some text for your pleasure";
|
logger->info() << "spdlog message #" << counter << ": This is some text for your pleasure";
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
for(auto &t:threads)
|
for(auto &t:threads)
|
||||||
{
|
{
|
||||||
t.join();
|
t.join();
|
||||||
};
|
};
|
||||||
|
|
||||||
duration<float> delta = clock::now() - start;
|
duration<float> delta = clock::now() - start;
|
||||||
float deltaf = delta.count();
|
float deltaf = delta.count();
|
||||||
auto rate = howmany/deltaf;
|
auto rate = howmany/deltaf;
|
||||||
|
|
||||||
cout << "Total: " << howmany << std::endl;
|
cout << "Total: " << howmany << std::endl;
|
||||||
cout << "Threads: " << thread_count << std::endl;
|
cout << "Threads: " << thread_count << std::endl;
|
||||||
std::cout << "Delta = " << deltaf << " seconds" << std::endl;
|
std::cout << "Delta = " << deltaf << " seconds" << std::endl;
|
||||||
std::cout << "Rate = " << rate << "/sec" << std::endl;
|
std::cout << "Rate = " << rate << "/sec" << std::endl;
|
||||||
}
|
}
|
||||||
|
@ -1,56 +1,56 @@
|
|||||||
#include <thread>
|
#include <thread>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <zf_log.c>
|
#include <zf_log.c>
|
||||||
|
|
||||||
const char g_path[] = "logs/zf_log.txt";
|
const char g_path[] = "logs/zf_log.txt";
|
||||||
int g_fd;
|
int g_fd;
|
||||||
|
|
||||||
static void output_callback(zf_log_message *msg)
|
static void output_callback(zf_log_message *msg)
|
||||||
{
|
{
|
||||||
*msg->p = '\n';
|
*msg->p = '\n';
|
||||||
write(g_fd, msg->buf, msg->p - msg->buf + 1);
|
write(g_fd, msg->buf, msg->p - msg->buf + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
int main(int argc, char* argv[])
|
int main(int argc, char* argv[])
|
||||||
{
|
{
|
||||||
g_fd = open(g_path, O_APPEND|O_CREAT|O_WRONLY);
|
g_fd = open(g_path, O_APPEND|O_CREAT|O_WRONLY);
|
||||||
if (0 > g_fd)
|
if (0 > g_fd)
|
||||||
{
|
{
|
||||||
ZF_LOGE_AUX(ZF_LOG_STDERR, "Failed to open log file: %s", g_path);
|
ZF_LOGE_AUX(ZF_LOG_STDERR, "Failed to open log file: %s", g_path);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
zf_log_set_output_callback(ZF_LOG_PUT_STD, output_callback);
|
zf_log_set_output_callback(ZF_LOG_PUT_STD, output_callback);
|
||||||
|
|
||||||
int thread_count = 10;
|
int thread_count = 10;
|
||||||
if(argc > 1)
|
if(argc > 1)
|
||||||
thread_count = std::atoi(argv[1]);
|
thread_count = std::atoi(argv[1]);
|
||||||
int howmany = 1000000;
|
int howmany = 1000000;
|
||||||
std::atomic<int > msg_counter {0};
|
std::atomic<int > msg_counter {0};
|
||||||
vector<thread> threads;
|
vector<thread> threads;
|
||||||
|
|
||||||
for (int t = 0; t < thread_count; ++t)
|
for (int t = 0; t < thread_count; ++t)
|
||||||
{
|
{
|
||||||
threads.push_back(std::thread([&]()
|
threads.push_back(std::thread([&]()
|
||||||
{
|
{
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
int counter = ++msg_counter;
|
int counter = ++msg_counter;
|
||||||
if (counter > howmany) break;
|
if (counter > howmany) break;
|
||||||
ZF_LOGI("zf_log message #%i: This is some text for your pleasure", counter);
|
ZF_LOGI("zf_log message #%i: This is some text for your pleasure", counter);
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto &t:threads)
|
for (auto &t:threads)
|
||||||
{
|
{
|
||||||
t.join();
|
t.join();
|
||||||
};
|
};
|
||||||
close(g_fd);
|
close(g_fd);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -1,27 +1,28 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <zf_log.c>
|
#include <zf_log.c>
|
||||||
|
|
||||||
const char g_path[] = "logs/zf_log.txt";
|
const char g_path[] = "logs/zf_log.txt";
|
||||||
static FILE *g_f;
|
static FILE *g_f;
|
||||||
|
|
||||||
static void output_callback(zf_log_message *msg)
|
static void output_callback(zf_log_message *msg)
|
||||||
{
|
{
|
||||||
*msg->p = '\n';
|
*msg->p = '\n';
|
||||||
fwrite(msg->buf, msg->p - msg->buf + 1, 1, g_f);
|
fwrite(msg->buf, msg->p - msg->buf + 1, 1, g_f);
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int, char* [])
|
int main(int, char* [])
|
||||||
{
|
{
|
||||||
g_f = fopen(g_path, "wb");
|
g_f = fopen(g_path, "wb");
|
||||||
if (!g_f) {
|
if (!g_f)
|
||||||
ZF_LOGE_AUX(ZF_LOG_STDERR, "Failed to open log file: %s", g_path);
|
{
|
||||||
return -1;
|
ZF_LOGE_AUX(ZF_LOG_STDERR, "Failed to open log file: %s", g_path);
|
||||||
}
|
return -1;
|
||||||
zf_log_set_output_callback(ZF_LOG_PUT_STD, output_callback);
|
}
|
||||||
|
zf_log_set_output_callback(ZF_LOG_PUT_STD, output_callback);
|
||||||
const int howmany = 1000000;
|
|
||||||
for(int i = 0 ; i < howmany; ++i)
|
const int howmany = 1000000;
|
||||||
ZF_LOGI("zf_log message #%i: This is some text for your pleasure", i);
|
for(int i = 0 ; i < howmany; ++i)
|
||||||
fclose(g_f);
|
ZF_LOGI("zf_log message #%i: This is some text for your pleasure", i);
|
||||||
return 0;
|
fclose(g_f);
|
||||||
}
|
return 0;
|
||||||
|
}
|
||||||
|
@ -1,118 +1,118 @@
|
|||||||
//
|
//
|
||||||
// Copyright(c) 2015 Gabi Melman.
|
// Copyright(c) 2015 Gabi Melman.
|
||||||
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||||
//
|
//
|
||||||
//
|
//
|
||||||
// spdlog usage example
|
// spdlog usage example
|
||||||
//
|
//
|
||||||
#include "spdlog/spdlog.h"
|
#include "spdlog/spdlog.h"
|
||||||
|
|
||||||
#include <cstdlib> // EXIT_FAILURE
|
#include <cstdlib> // EXIT_FAILURE
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
void async_example();
|
void async_example();
|
||||||
void syslog_example();
|
void syslog_example();
|
||||||
|
|
||||||
namespace spd = spdlog;
|
namespace spd = spdlog;
|
||||||
int main(int, char*[])
|
int main(int, char*[])
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// Multithreaded color console
|
// Multithreaded color console
|
||||||
auto console = spd::stdout_logger_mt("console", true);
|
auto console = spd::stdout_logger_mt("console", true);
|
||||||
console->info("Welcome to spdlog!");
|
console->info("Welcome to spdlog!");
|
||||||
console->info("An info message example {}..", 1);
|
console->info("An info message example {}..", 1);
|
||||||
console->info() << "Streams are supported too " << 1;
|
console->info() << "Streams are supported too " << 1;
|
||||||
|
|
||||||
// Formatting examples
|
// Formatting examples
|
||||||
console->info("Easy padding in numbers like {:08d}", 12);
|
console->info("Easy padding in numbers like {:08d}", 12);
|
||||||
console->info("Support for int: {0:d}; hex: {0:x}; oct: {0:o}; bin: {0:b}", 42);
|
console->info("Support for int: {0:d}; hex: {0:x}; oct: {0:o}; bin: {0:b}", 42);
|
||||||
console->info("Support for floats {:03.2f}", 1.23456);
|
console->info("Support for floats {:03.2f}", 1.23456);
|
||||||
console->info("Positional args are {1} {0}..", "too", "supported");
|
console->info("Positional args are {1} {0}..", "too", "supported");
|
||||||
|
|
||||||
console->info("{:<30}", "left aligned");
|
console->info("{:<30}", "left aligned");
|
||||||
console->info("{:>30}", "right aligned");
|
console->info("{:>30}", "right aligned");
|
||||||
console->info("{:^30}", "centered");
|
console->info("{:^30}", "centered");
|
||||||
|
|
||||||
spd::get("console")->info("loggers can be retrieved from a global registry using the spdlog::get(logger_name) function");
|
spd::get("console")->info("loggers can be retrieved from a global registry using the spdlog::get(logger_name) function");
|
||||||
|
|
||||||
// Runtime log levels
|
// Runtime log levels
|
||||||
spd::set_level(spd::level::info); //Set global log level to info
|
spd::set_level(spd::level::info); //Set global log level to info
|
||||||
console->debug("This message shold not be displayed!");
|
console->debug("This message shold not be displayed!");
|
||||||
console->set_level(spd::level::debug); // Set specific logger's log level
|
console->set_level(spd::level::debug); // Set specific logger's log level
|
||||||
console->debug("This message shold be displayed..");
|
console->debug("This message shold be displayed..");
|
||||||
|
|
||||||
// Create a file rotating logger with 5mb size max and 3 rotated files
|
// Create a file rotating logger with 5mb size max and 3 rotated files
|
||||||
auto file_logger = spd::rotating_logger_mt("file_logger", "logs/mylogfile", 1048576 * 5, 3);
|
auto file_logger = spd::rotating_logger_mt("file_logger", "logs/mylogfile", 1048576 * 5, 3);
|
||||||
for (int i = 0; i < 10; ++i)
|
for (int i = 0; i < 10; ++i)
|
||||||
file_logger->info("{} * {} equals {:>10}", i, i, i*i);
|
file_logger->info("{} * {} equals {:>10}", i, i, i*i);
|
||||||
|
|
||||||
// Create a daily logger - a new file is created every day on 2:30am
|
// 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", 2, 30);
|
auto daily_logger = spd::daily_logger_mt("daily_logger", "logs/daily", 2, 30);
|
||||||
|
|
||||||
// Customize msg format for all messages
|
// Customize msg format for all messages
|
||||||
spd::set_pattern("*** [%H:%M:%S %z] [thread %t] %v ***");
|
spd::set_pattern("*** [%H:%M:%S %z] [thread %t] %v ***");
|
||||||
file_logger->info("This is another message with custom format");
|
file_logger->info("This is another message with custom format");
|
||||||
|
|
||||||
|
|
||||||
// Compile time debug or trace macros.
|
// Compile time debug or trace macros.
|
||||||
// Enabled #ifdef SPDLOG_DEBUG_ON or #ifdef SPDLOG_TRACE_ON
|
// Enabled #ifdef SPDLOG_DEBUG_ON or #ifdef SPDLOG_TRACE_ON
|
||||||
SPDLOG_TRACE(console, "Enabled only #ifdef SPDLOG_TRACE_ON..{} ,{}", 1, 3.23);
|
SPDLOG_TRACE(console, "Enabled only #ifdef SPDLOG_TRACE_ON..{} ,{}", 1, 3.23);
|
||||||
SPDLOG_DEBUG(console, "Enabled only #ifdef SPDLOG_DEBUG_ON.. {} ,{}", 1, 3.23);
|
SPDLOG_DEBUG(console, "Enabled only #ifdef SPDLOG_DEBUG_ON.. {} ,{}", 1, 3.23);
|
||||||
|
|
||||||
// Asynchronous logging is very fast..
|
// Asynchronous logging is very fast..
|
||||||
// Just call spdlog::set_async_mode(q_size) and all created loggers from now on will be asynchronous..
|
// Just call spdlog::set_async_mode(q_size) and all created loggers from now on will be asynchronous..
|
||||||
async_example();
|
async_example();
|
||||||
|
|
||||||
// syslog example. linux/osx only..
|
// syslog example. linux/osx only..
|
||||||
syslog_example();
|
syslog_example();
|
||||||
|
|
||||||
|
|
||||||
// Release and close all loggers
|
// Release and close all loggers
|
||||||
spdlog::drop_all();
|
spdlog::drop_all();
|
||||||
}
|
}
|
||||||
|
|
||||||
catch (const spd::spdlog_ex& ex)
|
catch (const spd::spdlog_ex& ex)
|
||||||
{
|
{
|
||||||
std::cout << "Log failed: " << ex.what() << std::endl;
|
std::cout << "Log failed: " << ex.what() << std::endl;
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void async_example()
|
void async_example()
|
||||||
{
|
{
|
||||||
size_t q_size = 4096; //queue size must be power of 2
|
size_t q_size = 4096; //queue size must be power of 2
|
||||||
spdlog::set_async_mode(q_size);
|
spdlog::set_async_mode(q_size);
|
||||||
auto async_file = spd::daily_logger_st("async_file_logger", "logs/async_log.txt");
|
auto async_file = spd::daily_logger_st("async_file_logger", "logs/async_log.txt");
|
||||||
for (int i = 0; i < 100; ++i)
|
for (int i = 0; i < 100; ++i)
|
||||||
async_file->info("Async message #{}", i);
|
async_file->info("Async message #{}", i);
|
||||||
}
|
}
|
||||||
|
|
||||||
//syslog example (linux/osx only)
|
//syslog example (linux/osx only)
|
||||||
void syslog_example()
|
void syslog_example()
|
||||||
{
|
{
|
||||||
#if defined (__linux__) || defined(__APPLE__)
|
#if defined (__linux__) || defined(__APPLE__)
|
||||||
std::string ident = "spdlog-example";
|
std::string ident = "spdlog-example";
|
||||||
auto syslog_logger = spd::syslog_logger("syslog", ident, LOG_PID);
|
auto syslog_logger = spd::syslog_logger("syslog", ident, LOG_PID);
|
||||||
syslog_logger->warn("This is warning that will end up in syslog. This is Linux only!");
|
syslog_logger->warn("This is warning that will end up in syslog. This is Linux only!");
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Example of user defined class with operator<<
|
// Example of user defined class with operator<<
|
||||||
class some_class {};
|
class some_class {};
|
||||||
std::ostream& operator<<(std::ostream& os, const some_class&)
|
std::ostream& operator<<(std::ostream& os, const some_class&)
|
||||||
{
|
{
|
||||||
return os << "some_class";
|
return os << "some_class";
|
||||||
}
|
}
|
||||||
|
|
||||||
void custom_class_example()
|
void custom_class_example()
|
||||||
{
|
{
|
||||||
some_class c;
|
some_class c;
|
||||||
spdlog::get("console")->info("custom class with operator<<: {}..", c);
|
spdlog::get("console")->info("custom class with operator<<: {}..", c);
|
||||||
spdlog::get("console")->info() << "custom class with operator<<: " << c << "..";
|
spdlog::get("console")->info() << "custom class with operator<<: " << c << "..";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,90 +1,90 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
<ItemGroup Label="ProjectConfigurations">
|
<ItemGroup Label="ProjectConfigurations">
|
||||||
<ProjectConfiguration Include="Debug|Win32">
|
<ProjectConfiguration Include="Debug|Win32">
|
||||||
<Configuration>Debug</Configuration>
|
<Configuration>Debug</Configuration>
|
||||||
<Platform>Win32</Platform>
|
<Platform>Win32</Platform>
|
||||||
</ProjectConfiguration>
|
</ProjectConfiguration>
|
||||||
<ProjectConfiguration Include="Release|Win32">
|
<ProjectConfiguration Include="Release|Win32">
|
||||||
<Configuration>Release</Configuration>
|
<Configuration>Release</Configuration>
|
||||||
<Platform>Win32</Platform>
|
<Platform>Win32</Platform>
|
||||||
</ProjectConfiguration>
|
</ProjectConfiguration>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClCompile Include="example.cpp" />
|
<ClCompile Include="example.cpp" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<PropertyGroup Label="Globals">
|
<PropertyGroup Label="Globals">
|
||||||
<ProjectGuid>{9E5AB93A-0CCE-4BAC-9FCB-0FC9CB5EB8D2}</ProjectGuid>
|
<ProjectGuid>{9E5AB93A-0CCE-4BAC-9FCB-0FC9CB5EB8D2}</ProjectGuid>
|
||||||
<Keyword>Win32Proj</Keyword>
|
<Keyword>Win32Proj</Keyword>
|
||||||
<RootNamespace>.</RootNamespace>
|
<RootNamespace>.</RootNamespace>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||||
<ConfigurationType>Application</ConfigurationType>
|
<ConfigurationType>Application</ConfigurationType>
|
||||||
<UseDebugLibraries>true</UseDebugLibraries>
|
<UseDebugLibraries>true</UseDebugLibraries>
|
||||||
<PlatformToolset>v140</PlatformToolset>
|
<PlatformToolset>v140</PlatformToolset>
|
||||||
<CharacterSet>Unicode</CharacterSet>
|
<CharacterSet>Unicode</CharacterSet>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||||
<ConfigurationType>Application</ConfigurationType>
|
<ConfigurationType>Application</ConfigurationType>
|
||||||
<UseDebugLibraries>false</UseDebugLibraries>
|
<UseDebugLibraries>false</UseDebugLibraries>
|
||||||
<PlatformToolset>v140</PlatformToolset>
|
<PlatformToolset>v140</PlatformToolset>
|
||||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||||
<CharacterSet>Unicode</CharacterSet>
|
<CharacterSet>Unicode</CharacterSet>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||||
<ImportGroup Label="ExtensionSettings">
|
<ImportGroup Label="ExtensionSettings">
|
||||||
</ImportGroup>
|
</ImportGroup>
|
||||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
</ImportGroup>
|
</ImportGroup>
|
||||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
</ImportGroup>
|
</ImportGroup>
|
||||||
<PropertyGroup Label="UserMacros" />
|
<PropertyGroup Label="UserMacros" />
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||||
<LinkIncremental>true</LinkIncremental>
|
<LinkIncremental>true</LinkIncremental>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||||
<LinkIncremental>false</LinkIncremental>
|
<LinkIncremental>false</LinkIncremental>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||||
<ClCompile>
|
<ClCompile>
|
||||||
<PrecompiledHeader>
|
<PrecompiledHeader>
|
||||||
</PrecompiledHeader>
|
</PrecompiledHeader>
|
||||||
<WarningLevel>Level3</WarningLevel>
|
<WarningLevel>Level3</WarningLevel>
|
||||||
<Optimization>Disabled</Optimization>
|
<Optimization>Disabled</Optimization>
|
||||||
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
<AdditionalIncludeDirectories>..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
<AdditionalIncludeDirectories>..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||||
<PrecompiledHeaderFile />
|
<PrecompiledHeaderFile />
|
||||||
<PrecompiledHeaderOutputFile />
|
<PrecompiledHeaderOutputFile />
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<Link>
|
<Link>
|
||||||
<SubSystem>Console</SubSystem>
|
<SubSystem>Console</SubSystem>
|
||||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
</Link>
|
</Link>
|
||||||
</ItemDefinitionGroup>
|
</ItemDefinitionGroup>
|
||||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||||
<ClCompile>
|
<ClCompile>
|
||||||
<WarningLevel>Level3</WarningLevel>
|
<WarningLevel>Level3</WarningLevel>
|
||||||
<PrecompiledHeader>
|
<PrecompiledHeader>
|
||||||
</PrecompiledHeader>
|
</PrecompiledHeader>
|
||||||
<Optimization>MaxSpeed</Optimization>
|
<Optimization>MaxSpeed</Optimization>
|
||||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||||
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
<AdditionalIncludeDirectories>..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
<AdditionalIncludeDirectories>..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||||
<PrecompiledHeaderFile />
|
<PrecompiledHeaderFile />
|
||||||
<PrecompiledHeaderOutputFile />
|
<PrecompiledHeaderOutputFile />
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<Link>
|
<Link>
|
||||||
<SubSystem>Console</SubSystem>
|
<SubSystem>Console</SubSystem>
|
||||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||||
<OptimizeReferences>true</OptimizeReferences>
|
<OptimizeReferences>true</OptimizeReferences>
|
||||||
</Link>
|
</Link>
|
||||||
</ItemDefinitionGroup>
|
</ItemDefinitionGroup>
|
||||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||||
<ImportGroup Label="ExtensionTargets">
|
<ImportGroup Label="ExtensionTargets">
|
||||||
</ImportGroup>
|
</ImportGroup>
|
||||||
</Project>
|
</Project>
|
@ -1,74 +1,74 @@
|
|||||||
//
|
//
|
||||||
// Copyright(c) 2015 Gabi Melman.
|
// Copyright(c) 2015 Gabi Melman.
|
||||||
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||||
//
|
//
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
// Very fast asynchronous logger (millions of logs per second on an average desktop)
|
// Very fast asynchronous logger (millions of logs per second on an average desktop)
|
||||||
// Uses pre allocated lockfree queue for maximum throughput even under large number of threads.
|
// Uses pre allocated lockfree queue for maximum throughput even under large number of threads.
|
||||||
// Creates a single back thread to pop messages from the queue and log them.
|
// Creates a single back thread to pop messages from the queue and log them.
|
||||||
//
|
//
|
||||||
// Upon each log write the logger:
|
// Upon each log write the logger:
|
||||||
// 1. Checks if its log level is enough to log the message
|
// 1. Checks if its log level is enough to log the message
|
||||||
// 2. Push a new copy of the message to a queue (or block the caller until space is available in the queue)
|
// 2. Push a new copy of the message to a queue (or block the caller until space is available in the queue)
|
||||||
// 3. will throw spdlog_ex upon log exceptions
|
// 3. will throw spdlog_ex upon log exceptions
|
||||||
// Upong destruction, logs all remaining messages in the queue before destructing..
|
// Upong destruction, logs all remaining messages in the queue before destructing..
|
||||||
|
|
||||||
#include <spdlog/common.h>
|
#include <spdlog/common.h>
|
||||||
#include <spdlog/logger.h>
|
#include <spdlog/logger.h>
|
||||||
|
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
namespace spdlog
|
namespace spdlog
|
||||||
{
|
{
|
||||||
|
|
||||||
namespace details
|
namespace details
|
||||||
{
|
{
|
||||||
class async_log_helper;
|
class async_log_helper;
|
||||||
}
|
}
|
||||||
|
|
||||||
class async_logger :public logger
|
class async_logger :public logger
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
template<class It>
|
template<class It>
|
||||||
async_logger(const std::string& name,
|
async_logger(const std::string& name,
|
||||||
const It& begin,
|
const It& begin,
|
||||||
const It& end,
|
const It& end,
|
||||||
size_t queue_size,
|
size_t queue_size,
|
||||||
const async_overflow_policy overflow_policy = async_overflow_policy::block_retry,
|
const async_overflow_policy overflow_policy = async_overflow_policy::block_retry,
|
||||||
const std::function<void()>& worker_warmup_cb = nullptr,
|
const std::function<void()>& worker_warmup_cb = nullptr,
|
||||||
const std::chrono::milliseconds& flush_interval_ms = std::chrono::milliseconds::zero());
|
const std::chrono::milliseconds& flush_interval_ms = std::chrono::milliseconds::zero());
|
||||||
|
|
||||||
async_logger(const std::string& logger_name,
|
async_logger(const std::string& logger_name,
|
||||||
sinks_init_list sinks,
|
sinks_init_list sinks,
|
||||||
size_t queue_size,
|
size_t queue_size,
|
||||||
const async_overflow_policy overflow_policy = async_overflow_policy::block_retry,
|
const async_overflow_policy overflow_policy = async_overflow_policy::block_retry,
|
||||||
const std::function<void()>& worker_warmup_cb = nullptr,
|
const std::function<void()>& worker_warmup_cb = nullptr,
|
||||||
const std::chrono::milliseconds& flush_interval_ms = std::chrono::milliseconds::zero());
|
const std::chrono::milliseconds& flush_interval_ms = std::chrono::milliseconds::zero());
|
||||||
|
|
||||||
async_logger(const std::string& logger_name,
|
async_logger(const std::string& logger_name,
|
||||||
sink_ptr single_sink,
|
sink_ptr single_sink,
|
||||||
size_t queue_size,
|
size_t queue_size,
|
||||||
const async_overflow_policy overflow_policy = async_overflow_policy::block_retry,
|
const async_overflow_policy overflow_policy = async_overflow_policy::block_retry,
|
||||||
const std::function<void()>& worker_warmup_cb = nullptr,
|
const std::function<void()>& worker_warmup_cb = nullptr,
|
||||||
const std::chrono::milliseconds& flush_interval_ms = std::chrono::milliseconds::zero());
|
const std::chrono::milliseconds& flush_interval_ms = std::chrono::milliseconds::zero());
|
||||||
|
|
||||||
|
|
||||||
void flush() override;
|
void flush() override;
|
||||||
protected:
|
protected:
|
||||||
void _log_msg(details::log_msg& msg) override;
|
void _log_msg(details::log_msg& msg) override;
|
||||||
void _set_formatter(spdlog::formatter_ptr msg_formatter) override;
|
void _set_formatter(spdlog::formatter_ptr msg_formatter) override;
|
||||||
void _set_pattern(const std::string& pattern) override;
|
void _set_pattern(const std::string& pattern) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::unique_ptr<details::async_log_helper> _async_log_helper;
|
std::unique_ptr<details::async_log_helper> _async_log_helper;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#include <spdlog/details/async_logger_impl.h>
|
#include <spdlog/details/async_logger_impl.h>
|
||||||
|
|
||||||
|
@ -1,98 +1,98 @@
|
|||||||
//
|
//
|
||||||
// Copyright(c) 2015 Gabi Melman.
|
// Copyright(c) 2015 Gabi Melman.
|
||||||
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||||
//
|
//
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <initializer_list>
|
#include <initializer_list>
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <exception>
|
#include <exception>
|
||||||
|
|
||||||
//visual studio does not support noexcept yet
|
//visual studio does not support noexcept yet
|
||||||
#ifndef _MSC_VER
|
#ifndef _MSC_VER
|
||||||
#define SPDLOG_NOEXCEPT noexcept
|
#define SPDLOG_NOEXCEPT noexcept
|
||||||
#else
|
#else
|
||||||
#define SPDLOG_NOEXCEPT throw()
|
#define SPDLOG_NOEXCEPT throw()
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
namespace spdlog
|
namespace spdlog
|
||||||
{
|
{
|
||||||
|
|
||||||
class formatter;
|
class formatter;
|
||||||
|
|
||||||
namespace sinks
|
namespace sinks
|
||||||
{
|
{
|
||||||
class sink;
|
class sink;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Common types across the lib
|
// Common types across the lib
|
||||||
using log_clock = std::chrono::system_clock;
|
using log_clock = std::chrono::system_clock;
|
||||||
using sink_ptr = std::shared_ptr < sinks::sink >;
|
using sink_ptr = std::shared_ptr < sinks::sink >;
|
||||||
using sinks_init_list = std::initializer_list < sink_ptr >;
|
using sinks_init_list = std::initializer_list < sink_ptr >;
|
||||||
using formatter_ptr = std::shared_ptr<spdlog::formatter>;
|
using formatter_ptr = std::shared_ptr<spdlog::formatter>;
|
||||||
|
|
||||||
|
|
||||||
//Log level enum
|
//Log level enum
|
||||||
namespace level
|
namespace level
|
||||||
{
|
{
|
||||||
typedef enum
|
typedef enum
|
||||||
{
|
{
|
||||||
trace = 0,
|
trace = 0,
|
||||||
debug = 1,
|
debug = 1,
|
||||||
info = 2,
|
info = 2,
|
||||||
notice = 3,
|
notice = 3,
|
||||||
warn = 4,
|
warn = 4,
|
||||||
err = 5,
|
err = 5,
|
||||||
critical = 6,
|
critical = 6,
|
||||||
alert = 7,
|
alert = 7,
|
||||||
emerg = 8,
|
emerg = 8,
|
||||||
off = 9
|
off = 9
|
||||||
} level_enum;
|
} level_enum;
|
||||||
|
|
||||||
static const char* level_names[] { "trace", "debug", "info", "notice", "warning", "error", "critical", "alert", "emerg", "off"};
|
static const char* level_names[] { "trace", "debug", "info", "notice", "warning", "error", "critical", "alert", "emerg", "off"};
|
||||||
|
|
||||||
static const char* short_level_names[] { "T", "D", "I", "N", "W", "E", "C", "A", "M", "O"};
|
static const char* short_level_names[] { "T", "D", "I", "N", "W", "E", "C", "A", "M", "O"};
|
||||||
|
|
||||||
inline const char* to_str(spdlog::level::level_enum l)
|
inline const char* to_str(spdlog::level::level_enum l)
|
||||||
{
|
{
|
||||||
return level_names[l];
|
return level_names[l];
|
||||||
}
|
}
|
||||||
|
|
||||||
inline const char* to_short_str(spdlog::level::level_enum l)
|
inline const char* to_short_str(spdlog::level::level_enum l)
|
||||||
{
|
{
|
||||||
return short_level_names[l];
|
return short_level_names[l];
|
||||||
}
|
}
|
||||||
} //level
|
} //level
|
||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// Async overflow policy - block by default.
|
// Async overflow policy - block by default.
|
||||||
//
|
//
|
||||||
enum class async_overflow_policy
|
enum class async_overflow_policy
|
||||||
{
|
{
|
||||||
block_retry, // Block / yield / sleep until message can be enqueued
|
block_retry, // Block / yield / sleep until message can be enqueued
|
||||||
discard_log_msg // Discard the message it enqueue fails
|
discard_log_msg // Discard the message it enqueue fails
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// Log exception
|
// Log exception
|
||||||
//
|
//
|
||||||
class spdlog_ex : public std::exception
|
class spdlog_ex : public std::exception
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
spdlog_ex(const std::string& msg) :_msg(msg) {}
|
spdlog_ex(const std::string& msg) :_msg(msg) {}
|
||||||
const char* what() const SPDLOG_NOEXCEPT override
|
const char* what() const SPDLOG_NOEXCEPT override
|
||||||
{
|
{
|
||||||
return _msg.c_str();
|
return _msg.c_str();
|
||||||
}
|
}
|
||||||
private:
|
private:
|
||||||
std::string _msg;
|
std::string _msg;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} //spdlog
|
} //spdlog
|
||||||
|
@ -1,368 +1,368 @@
|
|||||||
//
|
//
|
||||||
// Copyright(c) 2015 Gabi Melman.
|
// Copyright(c) 2015 Gabi Melman.
|
||||||
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||||
//
|
//
|
||||||
|
|
||||||
// async log helper :
|
// async log helper :
|
||||||
// Process logs asynchronously using a back thread.
|
// Process logs asynchronously using a back thread.
|
||||||
//
|
//
|
||||||
// If the internal queue of log messages reaches its max size,
|
// If the internal queue of log messages reaches its max size,
|
||||||
// then the client call will block until there is more room.
|
// then the client call will block until there is more room.
|
||||||
//
|
//
|
||||||
// If the back thread throws during logging, a spdlog::spdlog_ex exception
|
// If the back thread throws during logging, a spdlog::spdlog_ex exception
|
||||||
// will be thrown in client's thread when tries to log the next message
|
// will be thrown in client's thread when tries to log the next message
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <spdlog/common.h>
|
#include <spdlog/common.h>
|
||||||
#include <spdlog/sinks/sink.h>
|
#include <spdlog/sinks/sink.h>
|
||||||
#include <spdlog/details/mpmc_bounded_q.h>
|
#include <spdlog/details/mpmc_bounded_q.h>
|
||||||
#include <spdlog/details/log_msg.h>
|
#include <spdlog/details/log_msg.h>
|
||||||
#include <spdlog/details/os.h>
|
#include <spdlog/details/os.h>
|
||||||
#include <spdlog/formatter.h>
|
#include <spdlog/formatter.h>
|
||||||
|
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <exception>
|
#include <exception>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
namespace spdlog
|
namespace spdlog
|
||||||
{
|
{
|
||||||
namespace details
|
namespace details
|
||||||
{
|
{
|
||||||
|
|
||||||
class async_log_helper
|
class async_log_helper
|
||||||
{
|
{
|
||||||
// Async msg to move to/from the queue
|
// Async msg to move to/from the queue
|
||||||
// Movable only. should never be copied
|
// Movable only. should never be copied
|
||||||
enum class async_msg_type
|
enum class async_msg_type
|
||||||
{
|
{
|
||||||
log,
|
log,
|
||||||
flush,
|
flush,
|
||||||
terminate
|
terminate
|
||||||
};
|
};
|
||||||
struct async_msg
|
struct async_msg
|
||||||
{
|
{
|
||||||
std::string logger_name;
|
std::string logger_name;
|
||||||
level::level_enum level;
|
level::level_enum level;
|
||||||
log_clock::time_point time;
|
log_clock::time_point time;
|
||||||
size_t thread_id;
|
size_t thread_id;
|
||||||
std::string txt;
|
std::string txt;
|
||||||
async_msg_type msg_type;
|
async_msg_type msg_type;
|
||||||
|
|
||||||
async_msg() = default;
|
async_msg() = default;
|
||||||
~async_msg() = default;
|
~async_msg() = default;
|
||||||
|
|
||||||
|
|
||||||
async_msg(async_msg&& other) SPDLOG_NOEXCEPT:
|
async_msg(async_msg&& other) SPDLOG_NOEXCEPT:
|
||||||
logger_name(std::move(other.logger_name)),
|
logger_name(std::move(other.logger_name)),
|
||||||
level(std::move(other.level)),
|
level(std::move(other.level)),
|
||||||
time(std::move(other.time)),
|
time(std::move(other.time)),
|
||||||
txt(std::move(other.txt)),
|
txt(std::move(other.txt)),
|
||||||
msg_type(std::move(other.msg_type))
|
msg_type(std::move(other.msg_type))
|
||||||
{}
|
{}
|
||||||
|
|
||||||
async_msg(async_msg_type m_type) :msg_type(m_type)
|
async_msg(async_msg_type m_type) :msg_type(m_type)
|
||||||
{};
|
{};
|
||||||
|
|
||||||
async_msg& operator=(async_msg&& other) SPDLOG_NOEXCEPT
|
async_msg& operator=(async_msg&& other) SPDLOG_NOEXCEPT
|
||||||
{
|
{
|
||||||
logger_name = std::move(other.logger_name);
|
logger_name = std::move(other.logger_name);
|
||||||
level = other.level;
|
level = other.level;
|
||||||
time = std::move(other.time);
|
time = std::move(other.time);
|
||||||
thread_id = other.thread_id;
|
thread_id = other.thread_id;
|
||||||
txt = std::move(other.txt);
|
txt = std::move(other.txt);
|
||||||
msg_type = other.msg_type;
|
msg_type = other.msg_type;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
// never copy or assign. should only be moved..
|
// never copy or assign. should only be moved..
|
||||||
async_msg(const async_msg&) = delete;
|
async_msg(const async_msg&) = delete;
|
||||||
async_msg& operator=(async_msg& other) = delete;
|
async_msg& operator=(async_msg& other) = delete;
|
||||||
|
|
||||||
// construct from log_msg
|
// construct from log_msg
|
||||||
async_msg(const details::log_msg& m) :
|
async_msg(const details::log_msg& m) :
|
||||||
logger_name(m.logger_name),
|
logger_name(m.logger_name),
|
||||||
level(m.level),
|
level(m.level),
|
||||||
time(m.time),
|
time(m.time),
|
||||||
thread_id(m.thread_id),
|
thread_id(m.thread_id),
|
||||||
txt(m.raw.data(), m.raw.size()),
|
txt(m.raw.data(), m.raw.size()),
|
||||||
msg_type(async_msg_type::log)
|
msg_type(async_msg_type::log)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// copy into log_msg
|
// copy into log_msg
|
||||||
void fill_log_msg(log_msg &msg)
|
void fill_log_msg(log_msg &msg)
|
||||||
{
|
{
|
||||||
msg.clear();
|
msg.clear();
|
||||||
msg.logger_name = logger_name;
|
msg.logger_name = logger_name;
|
||||||
msg.level = level;
|
msg.level = level;
|
||||||
msg.time = time;
|
msg.time = time;
|
||||||
msg.thread_id = thread_id;
|
msg.thread_id = thread_id;
|
||||||
msg.raw << txt;
|
msg.raw << txt;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
using item_type = async_msg;
|
using item_type = async_msg;
|
||||||
using q_type = details::mpmc_bounded_queue<item_type>;
|
using q_type = details::mpmc_bounded_queue<item_type>;
|
||||||
|
|
||||||
using clock = std::chrono::steady_clock;
|
using clock = std::chrono::steady_clock;
|
||||||
|
|
||||||
|
|
||||||
async_log_helper(formatter_ptr formatter,
|
async_log_helper(formatter_ptr formatter,
|
||||||
const std::vector<sink_ptr>& sinks,
|
const std::vector<sink_ptr>& sinks,
|
||||||
size_t queue_size,
|
size_t queue_size,
|
||||||
const async_overflow_policy overflow_policy = async_overflow_policy::block_retry,
|
const async_overflow_policy overflow_policy = async_overflow_policy::block_retry,
|
||||||
const std::function<void()>& worker_warmup_cb = nullptr,
|
const std::function<void()>& worker_warmup_cb = nullptr,
|
||||||
const std::chrono::milliseconds& flush_interval_ms = std::chrono::milliseconds::zero());
|
const std::chrono::milliseconds& flush_interval_ms = std::chrono::milliseconds::zero());
|
||||||
|
|
||||||
void log(const details::log_msg& msg);
|
void log(const details::log_msg& msg);
|
||||||
|
|
||||||
// stop logging and join the back thread
|
// stop logging and join the back thread
|
||||||
~async_log_helper();
|
~async_log_helper();
|
||||||
|
|
||||||
void set_formatter(formatter_ptr);
|
void set_formatter(formatter_ptr);
|
||||||
|
|
||||||
void flush();
|
void flush();
|
||||||
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
formatter_ptr _formatter;
|
formatter_ptr _formatter;
|
||||||
std::vector<std::shared_ptr<sinks::sink>> _sinks;
|
std::vector<std::shared_ptr<sinks::sink>> _sinks;
|
||||||
|
|
||||||
// queue of messages to log
|
// queue of messages to log
|
||||||
q_type _q;
|
q_type _q;
|
||||||
|
|
||||||
bool _flush_requested;
|
bool _flush_requested;
|
||||||
|
|
||||||
bool _terminate_requested;
|
bool _terminate_requested;
|
||||||
|
|
||||||
|
|
||||||
// last exception thrown from the worker thread
|
// last exception thrown from the worker thread
|
||||||
std::shared_ptr<spdlog_ex> _last_workerthread_ex;
|
std::shared_ptr<spdlog_ex> _last_workerthread_ex;
|
||||||
|
|
||||||
// overflow policy
|
// overflow policy
|
||||||
const async_overflow_policy _overflow_policy;
|
const async_overflow_policy _overflow_policy;
|
||||||
|
|
||||||
// worker thread warmup callback - one can set thread priority, affinity, etc
|
// worker thread warmup callback - one can set thread priority, affinity, etc
|
||||||
const std::function<void()> _worker_warmup_cb;
|
const std::function<void()> _worker_warmup_cb;
|
||||||
|
|
||||||
// auto periodic sink flush parameter
|
// auto periodic sink flush parameter
|
||||||
const std::chrono::milliseconds _flush_interval_ms;
|
const std::chrono::milliseconds _flush_interval_ms;
|
||||||
|
|
||||||
// worker thread
|
// worker thread
|
||||||
std::thread _worker_thread;
|
std::thread _worker_thread;
|
||||||
|
|
||||||
void push_msg(async_msg&& new_msg);
|
void push_msg(async_msg&& new_msg);
|
||||||
// throw last worker thread exception or if worker thread is not active
|
// throw last worker thread exception or if worker thread is not active
|
||||||
|
|
||||||
void throw_if_bad_worker();
|
void throw_if_bad_worker();
|
||||||
|
|
||||||
// worker thread main loop
|
// worker thread main loop
|
||||||
void worker_loop();
|
void worker_loop();
|
||||||
|
|
||||||
// pop next message from the queue and process it. will set the last_pop to the pop time
|
// pop next message from the queue and process it. will set the last_pop to the pop time
|
||||||
// return false if termination of the queue is required
|
// return false if termination of the queue is required
|
||||||
bool process_next_msg(log_clock::time_point& last_pop, log_clock::time_point& last_flush);
|
bool process_next_msg(log_clock::time_point& last_pop, log_clock::time_point& last_flush);
|
||||||
|
|
||||||
void handle_flush_interval(log_clock::time_point& now, log_clock::time_point& last_flush);
|
void handle_flush_interval(log_clock::time_point& now, log_clock::time_point& last_flush);
|
||||||
|
|
||||||
// sleep,yield or return immediatly using the time passed since last message as a hint
|
// sleep,yield or return immediatly using the time passed since last message as a hint
|
||||||
static void sleep_or_yield(const spdlog::log_clock::time_point& now, const log_clock::time_point& last_op_time);
|
static void sleep_or_yield(const spdlog::log_clock::time_point& now, const log_clock::time_point& last_op_time);
|
||||||
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
// async_sink class implementation
|
// async_sink class implementation
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
inline spdlog::details::async_log_helper::async_log_helper(
|
inline spdlog::details::async_log_helper::async_log_helper(
|
||||||
formatter_ptr formatter,
|
formatter_ptr formatter,
|
||||||
const std::vector<sink_ptr>& sinks,
|
const std::vector<sink_ptr>& sinks,
|
||||||
size_t queue_size,
|
size_t queue_size,
|
||||||
const async_overflow_policy overflow_policy,
|
const async_overflow_policy overflow_policy,
|
||||||
const std::function<void()>& worker_warmup_cb,
|
const std::function<void()>& worker_warmup_cb,
|
||||||
const std::chrono::milliseconds& flush_interval_ms):
|
const std::chrono::milliseconds& flush_interval_ms):
|
||||||
_formatter(formatter),
|
_formatter(formatter),
|
||||||
_sinks(sinks),
|
_sinks(sinks),
|
||||||
_q(queue_size),
|
_q(queue_size),
|
||||||
_flush_requested(false),
|
_flush_requested(false),
|
||||||
_terminate_requested(false),
|
_terminate_requested(false),
|
||||||
_overflow_policy(overflow_policy),
|
_overflow_policy(overflow_policy),
|
||||||
_worker_warmup_cb(worker_warmup_cb),
|
_worker_warmup_cb(worker_warmup_cb),
|
||||||
_flush_interval_ms(flush_interval_ms),
|
_flush_interval_ms(flush_interval_ms),
|
||||||
_worker_thread(&async_log_helper::worker_loop, this)
|
_worker_thread(&async_log_helper::worker_loop, this)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
// Send to the worker thread termination message(level=off)
|
// Send to the worker thread termination message(level=off)
|
||||||
// and wait for it to finish gracefully
|
// and wait for it to finish gracefully
|
||||||
inline spdlog::details::async_log_helper::~async_log_helper()
|
inline spdlog::details::async_log_helper::~async_log_helper()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
push_msg(async_msg(async_msg_type::terminate));
|
push_msg(async_msg(async_msg_type::terminate));
|
||||||
_worker_thread.join();
|
_worker_thread.join();
|
||||||
}
|
}
|
||||||
catch (...) // don't crash in destructor
|
catch (...) // don't crash in destructor
|
||||||
{}
|
{}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//Try to push and block until succeeded
|
//Try to push and block until succeeded
|
||||||
inline void spdlog::details::async_log_helper::log(const details::log_msg& msg)
|
inline void spdlog::details::async_log_helper::log(const details::log_msg& msg)
|
||||||
{
|
{
|
||||||
push_msg(async_msg(msg));
|
push_msg(async_msg(msg));
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//Try to push and block until succeeded
|
//Try to push and block until succeeded
|
||||||
inline void spdlog::details::async_log_helper::push_msg(details::async_log_helper::async_msg&& new_msg)
|
inline void spdlog::details::async_log_helper::push_msg(details::async_log_helper::async_msg&& new_msg)
|
||||||
{
|
{
|
||||||
throw_if_bad_worker();
|
throw_if_bad_worker();
|
||||||
if (!_q.enqueue(std::move(new_msg)) && _overflow_policy != async_overflow_policy::discard_log_msg)
|
if (!_q.enqueue(std::move(new_msg)) && _overflow_policy != async_overflow_policy::discard_log_msg)
|
||||||
{
|
{
|
||||||
auto last_op_time = details::os::now();
|
auto last_op_time = details::os::now();
|
||||||
auto now = last_op_time;
|
auto now = last_op_time;
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
now = details::os::now();
|
now = details::os::now();
|
||||||
sleep_or_yield(now, last_op_time);
|
sleep_or_yield(now, last_op_time);
|
||||||
}
|
}
|
||||||
while (!_q.enqueue(std::move(new_msg)));
|
while (!_q.enqueue(std::move(new_msg)));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void spdlog::details::async_log_helper::flush()
|
inline void spdlog::details::async_log_helper::flush()
|
||||||
{
|
{
|
||||||
push_msg(async_msg(async_msg_type::flush));
|
push_msg(async_msg(async_msg_type::flush));
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void spdlog::details::async_log_helper::worker_loop()
|
inline void spdlog::details::async_log_helper::worker_loop()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (_worker_warmup_cb) _worker_warmup_cb();
|
if (_worker_warmup_cb) _worker_warmup_cb();
|
||||||
auto last_pop = details::os::now();
|
auto last_pop = details::os::now();
|
||||||
auto last_flush = last_pop;
|
auto last_flush = last_pop;
|
||||||
while(process_next_msg(last_pop, last_flush));
|
while(process_next_msg(last_pop, last_flush));
|
||||||
}
|
}
|
||||||
catch (const std::exception& ex)
|
catch (const std::exception& ex)
|
||||||
{
|
{
|
||||||
_last_workerthread_ex = std::make_shared<spdlog_ex>(std::string("async_logger worker thread exception: ") + ex.what());
|
_last_workerthread_ex = std::make_shared<spdlog_ex>(std::string("async_logger worker thread exception: ") + ex.what());
|
||||||
}
|
}
|
||||||
catch (...)
|
catch (...)
|
||||||
{
|
{
|
||||||
_last_workerthread_ex = std::make_shared<spdlog_ex>("async_logger worker thread exception");
|
_last_workerthread_ex = std::make_shared<spdlog_ex>("async_logger worker thread exception");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// process next message in the queue
|
// process next message in the queue
|
||||||
// return true if this thread should still be active (no msg with level::off was received)
|
// return true if this thread should still be active (no msg with level::off was received)
|
||||||
inline bool spdlog::details::async_log_helper::process_next_msg(log_clock::time_point& last_pop, log_clock::time_point& last_flush)
|
inline bool spdlog::details::async_log_helper::process_next_msg(log_clock::time_point& last_pop, log_clock::time_point& last_flush)
|
||||||
{
|
{
|
||||||
|
|
||||||
async_msg incoming_async_msg;
|
async_msg incoming_async_msg;
|
||||||
log_msg incoming_log_msg;
|
log_msg incoming_log_msg;
|
||||||
|
|
||||||
if (_q.dequeue(incoming_async_msg))
|
if (_q.dequeue(incoming_async_msg))
|
||||||
{
|
{
|
||||||
last_pop = details::os::now();
|
last_pop = details::os::now();
|
||||||
switch (incoming_async_msg.msg_type)
|
switch (incoming_async_msg.msg_type)
|
||||||
{
|
{
|
||||||
case async_msg_type::flush:
|
case async_msg_type::flush:
|
||||||
_flush_requested = true;
|
_flush_requested = true;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case async_msg_type::terminate:
|
case async_msg_type::terminate:
|
||||||
_flush_requested = true;
|
_flush_requested = true;
|
||||||
_terminate_requested = true;
|
_terminate_requested = true;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
incoming_async_msg.fill_log_msg(incoming_log_msg);
|
incoming_async_msg.fill_log_msg(incoming_log_msg);
|
||||||
_formatter->format(incoming_log_msg);
|
_formatter->format(incoming_log_msg);
|
||||||
for (auto &s : _sinks)
|
for (auto &s : _sinks)
|
||||||
s->log(incoming_log_msg);
|
s->log(incoming_log_msg);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle empty queue..
|
// Handle empty queue..
|
||||||
// This is the only place where the queue can terminate or flush to avoid losing messages already in the queue
|
// This is the only place where the queue can terminate or flush to avoid losing messages already in the queue
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
auto now = details::os::now();
|
auto now = details::os::now();
|
||||||
handle_flush_interval(now, last_flush);
|
handle_flush_interval(now, last_flush);
|
||||||
sleep_or_yield(now, last_pop);
|
sleep_or_yield(now, last_pop);
|
||||||
return !_terminate_requested;
|
return !_terminate_requested;
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void spdlog::details::async_log_helper::handle_flush_interval(log_clock::time_point& now, log_clock::time_point& last_flush)
|
inline void spdlog::details::async_log_helper::handle_flush_interval(log_clock::time_point& now, log_clock::time_point& last_flush)
|
||||||
{
|
{
|
||||||
auto should_flush = _flush_requested || (_flush_interval_ms != std::chrono::milliseconds::zero() && now - last_flush >= _flush_interval_ms);
|
auto should_flush = _flush_requested || (_flush_interval_ms != std::chrono::milliseconds::zero() && now - last_flush >= _flush_interval_ms);
|
||||||
if (should_flush)
|
if (should_flush)
|
||||||
{
|
{
|
||||||
for (auto &s : _sinks)
|
for (auto &s : _sinks)
|
||||||
s->flush();
|
s->flush();
|
||||||
now = last_flush = details::os::now();
|
now = last_flush = details::os::now();
|
||||||
_flush_requested = false;
|
_flush_requested = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
inline void spdlog::details::async_log_helper::set_formatter(formatter_ptr msg_formatter)
|
inline void spdlog::details::async_log_helper::set_formatter(formatter_ptr msg_formatter)
|
||||||
{
|
{
|
||||||
_formatter = msg_formatter;
|
_formatter = msg_formatter;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// sleep,yield or return immediatly using the time passed since last message as a hint
|
// sleep,yield or return immediatly using the time passed since last message as a hint
|
||||||
inline void spdlog::details::async_log_helper::sleep_or_yield(const spdlog::log_clock::time_point& now, const spdlog::log_clock::time_point& last_op_time)
|
inline void spdlog::details::async_log_helper::sleep_or_yield(const spdlog::log_clock::time_point& now, const spdlog::log_clock::time_point& last_op_time)
|
||||||
{
|
{
|
||||||
using std::chrono::milliseconds;
|
using std::chrono::milliseconds;
|
||||||
using namespace std::this_thread;
|
using namespace std::this_thread;
|
||||||
|
|
||||||
auto time_since_op = now - last_op_time;
|
auto time_since_op = now - last_op_time;
|
||||||
|
|
||||||
// spin upto 1 ms
|
// spin upto 1 ms
|
||||||
if (time_since_op <= milliseconds(1))
|
if (time_since_op <= milliseconds(1))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// yield upto 10ms
|
// yield upto 10ms
|
||||||
if (time_since_op <= milliseconds(10))
|
if (time_since_op <= milliseconds(10))
|
||||||
return yield();
|
return yield();
|
||||||
|
|
||||||
|
|
||||||
// sleep for half of duration since last op
|
// sleep for half of duration since last op
|
||||||
if (time_since_op <= milliseconds(100))
|
if (time_since_op <= milliseconds(100))
|
||||||
return sleep_for(time_since_op / 2);
|
return sleep_for(time_since_op / 2);
|
||||||
|
|
||||||
return sleep_for(milliseconds(100));
|
return sleep_for(milliseconds(100));
|
||||||
}
|
}
|
||||||
|
|
||||||
// throw if the worker thread threw an exception or not active
|
// throw if the worker thread threw an exception or not active
|
||||||
inline void spdlog::details::async_log_helper::throw_if_bad_worker()
|
inline void spdlog::details::async_log_helper::throw_if_bad_worker()
|
||||||
{
|
{
|
||||||
if (_last_workerthread_ex)
|
if (_last_workerthread_ex)
|
||||||
{
|
{
|
||||||
auto ex = std::move(_last_workerthread_ex);
|
auto ex = std::move(_last_workerthread_ex);
|
||||||
throw *ex;
|
throw *ex;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,74 +1,74 @@
|
|||||||
//
|
//
|
||||||
// Copyright(c) 2015 Gabi Melman.
|
// Copyright(c) 2015 Gabi Melman.
|
||||||
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||||
//
|
//
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
// Async Logger implementation
|
// Async Logger implementation
|
||||||
// Use an async_sink (queue per logger) to perform the logging in a worker thread
|
// Use an async_sink (queue per logger) to perform the logging in a worker thread
|
||||||
|
|
||||||
#include <spdlog/details/async_log_helper.h>
|
#include <spdlog/details/async_log_helper.h>
|
||||||
#include <spdlog/async_logger.h>
|
#include <spdlog/async_logger.h>
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
template<class It>
|
template<class It>
|
||||||
inline spdlog::async_logger::async_logger(const std::string& logger_name,
|
inline spdlog::async_logger::async_logger(const std::string& logger_name,
|
||||||
const It& begin,
|
const It& begin,
|
||||||
const It& end,
|
const It& end,
|
||||||
size_t queue_size,
|
size_t queue_size,
|
||||||
const async_overflow_policy overflow_policy,
|
const async_overflow_policy overflow_policy,
|
||||||
const std::function<void()>& worker_warmup_cb,
|
const std::function<void()>& worker_warmup_cb,
|
||||||
const std::chrono::milliseconds& flush_interval_ms) :
|
const std::chrono::milliseconds& flush_interval_ms) :
|
||||||
logger(logger_name, begin, end),
|
logger(logger_name, begin, end),
|
||||||
_async_log_helper(new details::async_log_helper(_formatter, _sinks, queue_size, overflow_policy, worker_warmup_cb, flush_interval_ms))
|
_async_log_helper(new details::async_log_helper(_formatter, _sinks, queue_size, overflow_policy, worker_warmup_cb, flush_interval_ms))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
inline spdlog::async_logger::async_logger(const std::string& logger_name,
|
inline spdlog::async_logger::async_logger(const std::string& logger_name,
|
||||||
sinks_init_list sinks,
|
sinks_init_list sinks,
|
||||||
size_t queue_size,
|
size_t queue_size,
|
||||||
const async_overflow_policy overflow_policy,
|
const async_overflow_policy overflow_policy,
|
||||||
const std::function<void()>& worker_warmup_cb,
|
const std::function<void()>& worker_warmup_cb,
|
||||||
const std::chrono::milliseconds& flush_interval_ms) :
|
const std::chrono::milliseconds& flush_interval_ms) :
|
||||||
async_logger(logger_name, sinks.begin(), sinks.end(), queue_size, overflow_policy, worker_warmup_cb, flush_interval_ms) {}
|
async_logger(logger_name, sinks.begin(), sinks.end(), queue_size, overflow_policy, worker_warmup_cb, flush_interval_ms) {}
|
||||||
|
|
||||||
inline spdlog::async_logger::async_logger(const std::string& logger_name,
|
inline spdlog::async_logger::async_logger(const std::string& logger_name,
|
||||||
sink_ptr single_sink,
|
sink_ptr single_sink,
|
||||||
size_t queue_size,
|
size_t queue_size,
|
||||||
const async_overflow_policy overflow_policy,
|
const async_overflow_policy overflow_policy,
|
||||||
const std::function<void()>& worker_warmup_cb,
|
const std::function<void()>& worker_warmup_cb,
|
||||||
const std::chrono::milliseconds& flush_interval_ms) :
|
const std::chrono::milliseconds& flush_interval_ms) :
|
||||||
async_logger(logger_name,
|
async_logger(logger_name,
|
||||||
{
|
{
|
||||||
single_sink
|
single_sink
|
||||||
}, queue_size, overflow_policy, worker_warmup_cb, flush_interval_ms) {}
|
}, queue_size, overflow_policy, worker_warmup_cb, flush_interval_ms) {}
|
||||||
|
|
||||||
|
|
||||||
inline void spdlog::async_logger::flush()
|
inline void spdlog::async_logger::flush()
|
||||||
{
|
{
|
||||||
|
|
||||||
_async_log_helper->flush();
|
_async_log_helper->flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void spdlog::async_logger::_set_formatter(spdlog::formatter_ptr msg_formatter)
|
inline void spdlog::async_logger::_set_formatter(spdlog::formatter_ptr msg_formatter)
|
||||||
{
|
{
|
||||||
_formatter = msg_formatter;
|
_formatter = msg_formatter;
|
||||||
_async_log_helper->set_formatter(_formatter);
|
_async_log_helper->set_formatter(_formatter);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void spdlog::async_logger::_set_pattern(const std::string& pattern)
|
inline void spdlog::async_logger::_set_pattern(const std::string& pattern)
|
||||||
{
|
{
|
||||||
_formatter = std::make_shared<pattern_formatter>(pattern);
|
_formatter = std::make_shared<pattern_formatter>(pattern);
|
||||||
_async_log_helper->set_formatter(_formatter);
|
_async_log_helper->set_formatter(_formatter);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
inline void spdlog::async_logger::_log_msg(details::log_msg& msg)
|
inline void spdlog::async_logger::_log_msg(details::log_msg& msg)
|
||||||
{
|
{
|
||||||
_async_log_helper->log(msg);
|
_async_log_helper->log(msg);
|
||||||
}
|
}
|
||||||
|
@ -1,142 +1,142 @@
|
|||||||
//
|
//
|
||||||
// Copyright(c) 2015 Gabi Melman.
|
// Copyright(c) 2015 Gabi Melman.
|
||||||
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||||
//
|
//
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
// Helper class for file sink
|
// Helper class for file sink
|
||||||
// When failing to open a file, retry several times(5) with small delay between the tries(10 ms)
|
// When failing to open a file, retry several times(5) with small delay between the tries(10 ms)
|
||||||
// Can be set to auto flush on every line
|
// Can be set to auto flush on every line
|
||||||
// Throw spdlog_ex exception on errors
|
// Throw spdlog_ex exception on errors
|
||||||
|
|
||||||
#include <spdlog/details/os.h>
|
#include <spdlog/details/os.h>
|
||||||
#include <spdlog/details/log_msg.h>
|
#include <spdlog/details/log_msg.h>
|
||||||
|
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
|
|
||||||
namespace spdlog
|
namespace spdlog
|
||||||
{
|
{
|
||||||
namespace details
|
namespace details
|
||||||
{
|
{
|
||||||
|
|
||||||
class file_helper
|
class file_helper
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
const int open_tries = 5;
|
const int open_tries = 5;
|
||||||
const int open_interval = 10;
|
const int open_interval = 10;
|
||||||
|
|
||||||
explicit file_helper(bool force_flush) :
|
explicit file_helper(bool force_flush) :
|
||||||
_fd(nullptr),
|
_fd(nullptr),
|
||||||
_force_flush(force_flush)
|
_force_flush(force_flush)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
file_helper(const file_helper&) = delete;
|
file_helper(const file_helper&) = delete;
|
||||||
file_helper& operator=(const file_helper&) = delete;
|
file_helper& operator=(const file_helper&) = delete;
|
||||||
|
|
||||||
~file_helper()
|
~file_helper()
|
||||||
{
|
{
|
||||||
close();
|
close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void open(const std::string& fname, bool truncate = false)
|
void open(const std::string& fname, bool truncate = false)
|
||||||
{
|
{
|
||||||
|
|
||||||
close();
|
close();
|
||||||
const char* mode = truncate ? "wb" : "ab";
|
const char* mode = truncate ? "wb" : "ab";
|
||||||
_filename = fname;
|
_filename = fname;
|
||||||
for (int tries = 0; tries < open_tries; ++tries)
|
for (int tries = 0; tries < open_tries; ++tries)
|
||||||
{
|
{
|
||||||
if (!os::fopen_s(&_fd, fname, mode))
|
if (!os::fopen_s(&_fd, fname, mode))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
std::this_thread::sleep_for(std::chrono::milliseconds(open_interval));
|
std::this_thread::sleep_for(std::chrono::milliseconds(open_interval));
|
||||||
}
|
}
|
||||||
|
|
||||||
throw spdlog_ex("Failed opening file " + fname + " for writing");
|
throw spdlog_ex("Failed opening file " + fname + " for writing");
|
||||||
}
|
}
|
||||||
|
|
||||||
void reopen(bool truncate)
|
void reopen(bool truncate)
|
||||||
{
|
{
|
||||||
if (_filename.empty())
|
if (_filename.empty())
|
||||||
throw spdlog_ex("Failed re opening file - was not opened before");
|
throw spdlog_ex("Failed re opening file - was not opened before");
|
||||||
open(_filename, truncate);
|
open(_filename, truncate);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void flush()
|
void flush()
|
||||||
{
|
{
|
||||||
std::fflush(_fd);
|
std::fflush(_fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
void close()
|
void close()
|
||||||
{
|
{
|
||||||
if (_fd)
|
if (_fd)
|
||||||
{
|
{
|
||||||
std::fclose(_fd);
|
std::fclose(_fd);
|
||||||
_fd = nullptr;
|
_fd = nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void write(const log_msg& msg)
|
void write(const log_msg& msg)
|
||||||
{
|
{
|
||||||
|
|
||||||
size_t msg_size = msg.formatted.size();
|
size_t msg_size = msg.formatted.size();
|
||||||
auto data = msg.formatted.data();
|
auto data = msg.formatted.data();
|
||||||
if (std::fwrite(data, 1, msg_size, _fd) != msg_size)
|
if (std::fwrite(data, 1, msg_size, _fd) != msg_size)
|
||||||
throw spdlog_ex("Failed writing to file " + _filename);
|
throw spdlog_ex("Failed writing to file " + _filename);
|
||||||
|
|
||||||
if (_force_flush)
|
if (_force_flush)
|
||||||
std::fflush(_fd);
|
std::fflush(_fd);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
long size()
|
long size()
|
||||||
{
|
{
|
||||||
if (!_fd)
|
if (!_fd)
|
||||||
throw spdlog_ex("Cannot use size() on closed file " + _filename);
|
throw spdlog_ex("Cannot use size() on closed file " + _filename);
|
||||||
|
|
||||||
auto pos = ftell(_fd);
|
auto pos = ftell(_fd);
|
||||||
if (fseek(_fd, 0, SEEK_END) != 0)
|
if (fseek(_fd, 0, SEEK_END) != 0)
|
||||||
throw spdlog_ex("fseek failed on file " + _filename);
|
throw spdlog_ex("fseek failed on file " + _filename);
|
||||||
|
|
||||||
auto file_size = ftell(_fd);
|
auto file_size = ftell(_fd);
|
||||||
|
|
||||||
if(fseek(_fd, pos, SEEK_SET) !=0)
|
if(fseek(_fd, pos, SEEK_SET) !=0)
|
||||||
throw spdlog_ex("fseek failed on file " + _filename);
|
throw spdlog_ex("fseek failed on file " + _filename);
|
||||||
|
|
||||||
if (file_size == -1)
|
if (file_size == -1)
|
||||||
throw spdlog_ex("ftell failed on file " + _filename);
|
throw spdlog_ex("ftell failed on file " + _filename);
|
||||||
|
|
||||||
|
|
||||||
return file_size;
|
return file_size;
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::string& filename() const
|
const std::string& filename() const
|
||||||
{
|
{
|
||||||
return _filename;
|
return _filename;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool file_exists(const std::string& name)
|
static bool file_exists(const std::string& name)
|
||||||
{
|
{
|
||||||
|
|
||||||
return os::file_exists(name);
|
return os::file_exists(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
FILE* _fd;
|
FILE* _fd;
|
||||||
std::string _filename;
|
std::string _filename;
|
||||||
bool _force_flush;
|
bool _force_flush;
|
||||||
|
|
||||||
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,78 +1,78 @@
|
|||||||
//
|
//
|
||||||
// Copyright(c) 2015 Gabi Melman.
|
// Copyright(c) 2015 Gabi Melman.
|
||||||
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||||
//
|
//
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <spdlog/common.h>
|
#include <spdlog/common.h>
|
||||||
#include <spdlog/details/log_msg.h>
|
#include <spdlog/details/log_msg.h>
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
// Line logger class - aggregates operator<< calls to fast ostream
|
// Line logger class - aggregates operator<< calls to fast ostream
|
||||||
// and logs upon destruction
|
// and logs upon destruction
|
||||||
|
|
||||||
namespace spdlog
|
namespace spdlog
|
||||||
{
|
{
|
||||||
|
|
||||||
// Forward declaration
|
// Forward declaration
|
||||||
class logger;
|
class logger;
|
||||||
|
|
||||||
namespace details
|
namespace details
|
||||||
{
|
{
|
||||||
class line_logger
|
class line_logger
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
line_logger(logger* callback_logger, level::level_enum msg_level, bool enabled);
|
line_logger(logger* callback_logger, level::level_enum msg_level, bool enabled);
|
||||||
|
|
||||||
// No copy intended. Only move
|
// No copy intended. Only move
|
||||||
line_logger(const line_logger& other) = delete;
|
line_logger(const line_logger& other) = delete;
|
||||||
line_logger& operator=(const line_logger&) = delete;
|
line_logger& operator=(const line_logger&) = delete;
|
||||||
line_logger& operator=(line_logger&&) = delete;
|
line_logger& operator=(line_logger&&) = delete;
|
||||||
|
|
||||||
|
|
||||||
line_logger(line_logger&& other);
|
line_logger(line_logger&& other);
|
||||||
|
|
||||||
//Log the log message using the callback logger
|
//Log the log message using the callback logger
|
||||||
~line_logger();
|
~line_logger();
|
||||||
|
|
||||||
//
|
//
|
||||||
// Support for format string with variadic args
|
// Support for format string with variadic args
|
||||||
//
|
//
|
||||||
|
|
||||||
|
|
||||||
void write(const char* what);
|
void write(const char* what);
|
||||||
|
|
||||||
template <typename... Args>
|
template <typename... Args>
|
||||||
void write(const char* fmt, const Args&... args);
|
void write(const char* fmt, const Args&... args);
|
||||||
|
|
||||||
//
|
//
|
||||||
// Support for operator<<
|
// Support for operator<<
|
||||||
//
|
//
|
||||||
line_logger& operator<<(const char* what);
|
line_logger& operator<<(const char* what);
|
||||||
line_logger& operator<<(const std::string& what);
|
line_logger& operator<<(const std::string& what);
|
||||||
line_logger& operator<<(int what);
|
line_logger& operator<<(int what);
|
||||||
line_logger& operator<<(unsigned int what);
|
line_logger& operator<<(unsigned int what);
|
||||||
line_logger& operator<<(long what);
|
line_logger& operator<<(long what);
|
||||||
line_logger& operator<<(unsigned long what);
|
line_logger& operator<<(unsigned long what);
|
||||||
line_logger& operator<<(long long what);
|
line_logger& operator<<(long long what);
|
||||||
line_logger& operator<<(unsigned long long what);
|
line_logger& operator<<(unsigned long long what);
|
||||||
line_logger& operator<<(double what);
|
line_logger& operator<<(double what);
|
||||||
line_logger& operator<<(long double what);
|
line_logger& operator<<(long double what);
|
||||||
line_logger& operator<<(float what);
|
line_logger& operator<<(float what);
|
||||||
line_logger& operator<<(char what);
|
line_logger& operator<<(char what);
|
||||||
//Support user types which implements operator<<
|
//Support user types which implements operator<<
|
||||||
template<typename T>
|
template<typename T>
|
||||||
line_logger& operator<<(const T& what);
|
line_logger& operator<<(const T& what);
|
||||||
|
|
||||||
void disable();
|
void disable();
|
||||||
bool is_enabled() const;
|
bool is_enabled() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
logger* _callback_logger;
|
logger* _callback_logger;
|
||||||
log_msg _log_msg;
|
log_msg _log_msg;
|
||||||
bool _enabled;
|
bool _enabled;
|
||||||
};
|
};
|
||||||
} //Namespace details
|
} //Namespace details
|
||||||
} // Namespace spdlog
|
} // Namespace spdlog
|
||||||
|
|
||||||
|
@ -1,185 +1,185 @@
|
|||||||
//
|
//
|
||||||
// Copyright(c) 2015 Gabi Melman.
|
// Copyright(c) 2015 Gabi Melman.
|
||||||
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||||
//
|
//
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
|
|
||||||
#include <spdlog/details/line_logger_fwd.h>
|
#include <spdlog/details/line_logger_fwd.h>
|
||||||
#include <spdlog/common.h>
|
#include <spdlog/common.h>
|
||||||
#include <spdlog/logger.h>
|
#include <spdlog/logger.h>
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
// Line logger class - aggregates operator<< calls to fast ostream
|
// Line logger class - aggregates operator<< calls to fast ostream
|
||||||
// and logs upon destruction
|
// and logs upon destruction
|
||||||
|
|
||||||
inline spdlog::details::line_logger::line_logger(logger* callback_logger, level::level_enum msg_level, bool enabled):
|
inline spdlog::details::line_logger::line_logger(logger* callback_logger, level::level_enum msg_level, bool enabled):
|
||||||
_callback_logger(callback_logger),
|
_callback_logger(callback_logger),
|
||||||
_log_msg(msg_level),
|
_log_msg(msg_level),
|
||||||
_enabled(enabled)
|
_enabled(enabled)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
inline spdlog::details::line_logger::line_logger(line_logger&& other) :
|
inline spdlog::details::line_logger::line_logger(line_logger&& other) :
|
||||||
_callback_logger(other._callback_logger),
|
_callback_logger(other._callback_logger),
|
||||||
_log_msg(std::move(other._log_msg)),
|
_log_msg(std::move(other._log_msg)),
|
||||||
_enabled(other._enabled)
|
_enabled(other._enabled)
|
||||||
{
|
{
|
||||||
other.disable();
|
other.disable();
|
||||||
}
|
}
|
||||||
|
|
||||||
//Log the log message using the callback logger
|
//Log the log message using the callback logger
|
||||||
inline spdlog::details::line_logger::~line_logger()
|
inline spdlog::details::line_logger::~line_logger()
|
||||||
{
|
{
|
||||||
if (_enabled)
|
if (_enabled)
|
||||||
{
|
{
|
||||||
#ifndef SPDLOG_NO_NAME
|
#ifndef SPDLOG_NO_NAME
|
||||||
_log_msg.logger_name = _callback_logger->name();
|
_log_msg.logger_name = _callback_logger->name();
|
||||||
#endif
|
#endif
|
||||||
#ifndef SPDLOG_NO_DATETIME
|
#ifndef SPDLOG_NO_DATETIME
|
||||||
_log_msg.time = os::now();
|
_log_msg.time = os::now();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef SPDLOG_NO_THREAD_ID
|
#ifndef SPDLOG_NO_THREAD_ID
|
||||||
_log_msg.thread_id = os::thread_id();
|
_log_msg.thread_id = os::thread_id();
|
||||||
#endif
|
#endif
|
||||||
_callback_logger->_log_msg(_log_msg);
|
_callback_logger->_log_msg(_log_msg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// Support for format string with variadic args
|
// Support for format string with variadic args
|
||||||
//
|
//
|
||||||
|
|
||||||
|
|
||||||
inline void spdlog::details::line_logger::write(const char* what)
|
inline void spdlog::details::line_logger::write(const char* what)
|
||||||
{
|
{
|
||||||
if (_enabled)
|
if (_enabled)
|
||||||
_log_msg.raw << what;
|
_log_msg.raw << what;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename... Args>
|
template <typename... Args>
|
||||||
inline void spdlog::details::line_logger::write(const char* fmt, const Args&... args)
|
inline void spdlog::details::line_logger::write(const char* fmt, const Args&... args)
|
||||||
{
|
{
|
||||||
if (!_enabled)
|
if (!_enabled)
|
||||||
return;
|
return;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
_log_msg.raw.write(fmt, args...);
|
_log_msg.raw.write(fmt, args...);
|
||||||
}
|
}
|
||||||
catch (const fmt::FormatError& e)
|
catch (const fmt::FormatError& e)
|
||||||
{
|
{
|
||||||
throw spdlog_ex(fmt::format("formatting error while processing format string '{}': {}", fmt, e.what()));
|
throw spdlog_ex(fmt::format("formatting error while processing format string '{}': {}", fmt, e.what()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// Support for operator<<
|
// Support for operator<<
|
||||||
//
|
//
|
||||||
inline spdlog::details::line_logger& spdlog::details::line_logger::operator<<(const char* what)
|
inline spdlog::details::line_logger& spdlog::details::line_logger::operator<<(const char* what)
|
||||||
{
|
{
|
||||||
if (_enabled)
|
if (_enabled)
|
||||||
_log_msg.raw << what;
|
_log_msg.raw << what;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline spdlog::details::line_logger& spdlog::details::line_logger::operator<<(const std::string& what)
|
inline spdlog::details::line_logger& spdlog::details::line_logger::operator<<(const std::string& what)
|
||||||
{
|
{
|
||||||
if (_enabled)
|
if (_enabled)
|
||||||
_log_msg.raw << what;
|
_log_msg.raw << what;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline spdlog::details::line_logger& spdlog::details::line_logger::operator<<(int what)
|
inline spdlog::details::line_logger& spdlog::details::line_logger::operator<<(int what)
|
||||||
{
|
{
|
||||||
if (_enabled)
|
if (_enabled)
|
||||||
_log_msg.raw << what;
|
_log_msg.raw << what;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline spdlog::details::line_logger& spdlog::details::line_logger::operator<<(unsigned int what)
|
inline spdlog::details::line_logger& spdlog::details::line_logger::operator<<(unsigned int what)
|
||||||
{
|
{
|
||||||
if (_enabled)
|
if (_enabled)
|
||||||
_log_msg.raw << what;
|
_log_msg.raw << what;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
inline spdlog::details::line_logger& spdlog::details::line_logger::operator<<(long what)
|
inline spdlog::details::line_logger& spdlog::details::line_logger::operator<<(long what)
|
||||||
{
|
{
|
||||||
if (_enabled)
|
if (_enabled)
|
||||||
_log_msg.raw << what;
|
_log_msg.raw << what;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline spdlog::details::line_logger& spdlog::details::line_logger::operator<<(unsigned long what)
|
inline spdlog::details::line_logger& spdlog::details::line_logger::operator<<(unsigned long what)
|
||||||
{
|
{
|
||||||
if (_enabled)
|
if (_enabled)
|
||||||
_log_msg.raw << what;
|
_log_msg.raw << what;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline spdlog::details::line_logger& spdlog::details::line_logger::operator<<(long long what)
|
inline spdlog::details::line_logger& spdlog::details::line_logger::operator<<(long long what)
|
||||||
{
|
{
|
||||||
if (_enabled)
|
if (_enabled)
|
||||||
_log_msg.raw << what;
|
_log_msg.raw << what;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline spdlog::details::line_logger& spdlog::details::line_logger::operator<<(unsigned long long what)
|
inline spdlog::details::line_logger& spdlog::details::line_logger::operator<<(unsigned long long what)
|
||||||
{
|
{
|
||||||
if (_enabled)
|
if (_enabled)
|
||||||
_log_msg.raw << what;
|
_log_msg.raw << what;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline spdlog::details::line_logger& spdlog::details::line_logger::operator<<(double what)
|
inline spdlog::details::line_logger& spdlog::details::line_logger::operator<<(double what)
|
||||||
{
|
{
|
||||||
if (_enabled)
|
if (_enabled)
|
||||||
_log_msg.raw << what;
|
_log_msg.raw << what;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline spdlog::details::line_logger& spdlog::details::line_logger::operator<<(long double what)
|
inline spdlog::details::line_logger& spdlog::details::line_logger::operator<<(long double what)
|
||||||
{
|
{
|
||||||
if (_enabled)
|
if (_enabled)
|
||||||
_log_msg.raw << what;
|
_log_msg.raw << what;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline spdlog::details::line_logger& spdlog::details::line_logger::operator<<(float what)
|
inline spdlog::details::line_logger& spdlog::details::line_logger::operator<<(float what)
|
||||||
{
|
{
|
||||||
if (_enabled)
|
if (_enabled)
|
||||||
_log_msg.raw << what;
|
_log_msg.raw << what;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline spdlog::details::line_logger& spdlog::details::line_logger::operator<<(char what)
|
inline spdlog::details::line_logger& spdlog::details::line_logger::operator<<(char what)
|
||||||
{
|
{
|
||||||
if (_enabled)
|
if (_enabled)
|
||||||
_log_msg.raw << what;
|
_log_msg.raw << what;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
//Support user types which implements operator<<
|
//Support user types which implements operator<<
|
||||||
template<typename T>
|
template<typename T>
|
||||||
inline spdlog::details::line_logger& spdlog::details::line_logger::operator<<(const T& what)
|
inline spdlog::details::line_logger& spdlog::details::line_logger::operator<<(const T& what)
|
||||||
{
|
{
|
||||||
if (_enabled)
|
if (_enabled)
|
||||||
_log_msg.raw.write("{}", what);
|
_log_msg.raw.write("{}", what);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
inline void spdlog::details::line_logger::disable()
|
inline void spdlog::details::line_logger::disable()
|
||||||
{
|
{
|
||||||
_enabled = false;
|
_enabled = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool spdlog::details::line_logger::is_enabled() const
|
inline bool spdlog::details::line_logger::is_enabled() const
|
||||||
{
|
{
|
||||||
return _enabled;
|
return _enabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,81 +1,81 @@
|
|||||||
//
|
//
|
||||||
// Copyright(c) 2015 Gabi Melman.
|
// Copyright(c) 2015 Gabi Melman.
|
||||||
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||||
//
|
//
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <spdlog/common.h>
|
#include <spdlog/common.h>
|
||||||
#include <spdlog/details/format.h>
|
#include <spdlog/details/format.h>
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
namespace spdlog
|
namespace spdlog
|
||||||
{
|
{
|
||||||
namespace details
|
namespace details
|
||||||
{
|
{
|
||||||
struct log_msg
|
struct log_msg
|
||||||
{
|
{
|
||||||
log_msg() = default;
|
log_msg() = default;
|
||||||
log_msg(level::level_enum l):
|
log_msg(level::level_enum l):
|
||||||
logger_name(),
|
logger_name(),
|
||||||
level(l),
|
level(l),
|
||||||
raw(),
|
raw(),
|
||||||
formatted() {}
|
formatted() {}
|
||||||
|
|
||||||
|
|
||||||
log_msg(const log_msg& other) :
|
log_msg(const log_msg& other) :
|
||||||
logger_name(other.logger_name),
|
logger_name(other.logger_name),
|
||||||
level(other.level),
|
level(other.level),
|
||||||
time(other.time),
|
time(other.time),
|
||||||
thread_id(other.thread_id)
|
thread_id(other.thread_id)
|
||||||
{
|
{
|
||||||
if (other.raw.size())
|
if (other.raw.size())
|
||||||
raw << fmt::BasicStringRef<char>(other.raw.data(), other.raw.size());
|
raw << fmt::BasicStringRef<char>(other.raw.data(), other.raw.size());
|
||||||
if (other.formatted.size())
|
if (other.formatted.size())
|
||||||
formatted << fmt::BasicStringRef<char>(other.formatted.data(), other.formatted.size());
|
formatted << fmt::BasicStringRef<char>(other.formatted.data(), other.formatted.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
log_msg(log_msg&& other) :
|
log_msg(log_msg&& other) :
|
||||||
logger_name(std::move(other.logger_name)),
|
logger_name(std::move(other.logger_name)),
|
||||||
level(other.level),
|
level(other.level),
|
||||||
time(std::move(other.time)),
|
time(std::move(other.time)),
|
||||||
thread_id(other.thread_id),
|
thread_id(other.thread_id),
|
||||||
raw(std::move(other.raw)),
|
raw(std::move(other.raw)),
|
||||||
formatted(std::move(other.formatted))
|
formatted(std::move(other.formatted))
|
||||||
{
|
{
|
||||||
other.clear();
|
other.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
log_msg& operator=(log_msg&& other)
|
log_msg& operator=(log_msg&& other)
|
||||||
{
|
{
|
||||||
if (this == &other)
|
if (this == &other)
|
||||||
return *this;
|
return *this;
|
||||||
|
|
||||||
logger_name = std::move(other.logger_name);
|
logger_name = std::move(other.logger_name);
|
||||||
level = other.level;
|
level = other.level;
|
||||||
time = std::move(other.time);
|
time = std::move(other.time);
|
||||||
thread_id = other.thread_id;
|
thread_id = other.thread_id;
|
||||||
raw = std::move(other.raw);
|
raw = std::move(other.raw);
|
||||||
formatted = std::move(other.formatted);
|
formatted = std::move(other.formatted);
|
||||||
other.clear();
|
other.clear();
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
void clear()
|
void clear()
|
||||||
{
|
{
|
||||||
level = level::off;
|
level = level::off;
|
||||||
raw.clear();
|
raw.clear();
|
||||||
formatted.clear();
|
formatted.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string logger_name;
|
std::string logger_name;
|
||||||
level::level_enum level;
|
level::level_enum level;
|
||||||
log_clock::time_point time;
|
log_clock::time_point time;
|
||||||
size_t thread_id;
|
size_t thread_id;
|
||||||
fmt::MemoryWriter raw;
|
fmt::MemoryWriter raw;
|
||||||
fmt::MemoryWriter formatted;
|
fmt::MemoryWriter formatted;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,303 +1,303 @@
|
|||||||
//
|
//
|
||||||
// Copyright(c) 2015 Gabi Melman.
|
// Copyright(c) 2015 Gabi Melman.
|
||||||
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||||
//
|
//
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <spdlog/logger.h>
|
#include <spdlog/logger.h>
|
||||||
|
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
// create logger with given name, sinks and the default pattern formatter
|
// create logger with given name, sinks and the default pattern formatter
|
||||||
// all other ctors will call this one
|
// all other ctors will call this one
|
||||||
template<class It>
|
template<class It>
|
||||||
inline spdlog::logger::logger(const std::string& logger_name, const It& begin, const It& end) :
|
inline spdlog::logger::logger(const std::string& logger_name, const It& begin, const It& end) :
|
||||||
_name(logger_name),
|
_name(logger_name),
|
||||||
_sinks(begin, end),
|
_sinks(begin, end),
|
||||||
_formatter(std::make_shared<pattern_formatter>("%+"))
|
_formatter(std::make_shared<pattern_formatter>("%+"))
|
||||||
{
|
{
|
||||||
|
|
||||||
// no support under vs2013 for member initialization for std::atomic
|
// no support under vs2013 for member initialization for std::atomic
|
||||||
_level = level::info;
|
_level = level::info;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ctor with sinks as init list
|
// ctor with sinks as init list
|
||||||
inline spdlog::logger::logger(const std::string& logger_name, sinks_init_list sinks_list) :
|
inline spdlog::logger::logger(const std::string& logger_name, sinks_init_list sinks_list) :
|
||||||
logger(logger_name, sinks_list.begin(), sinks_list.end()) {}
|
logger(logger_name, sinks_list.begin(), sinks_list.end()) {}
|
||||||
|
|
||||||
|
|
||||||
// ctor with single sink
|
// ctor with single sink
|
||||||
inline spdlog::logger::logger(const std::string& logger_name, spdlog::sink_ptr single_sink) :
|
inline spdlog::logger::logger(const std::string& logger_name, spdlog::sink_ptr single_sink) :
|
||||||
logger(logger_name,
|
logger(logger_name,
|
||||||
{
|
{
|
||||||
single_sink
|
single_sink
|
||||||
}) {}
|
}) {}
|
||||||
|
|
||||||
|
|
||||||
inline spdlog::logger::~logger() = default;
|
inline spdlog::logger::~logger() = default;
|
||||||
|
|
||||||
|
|
||||||
inline void spdlog::logger::set_formatter(spdlog::formatter_ptr msg_formatter)
|
inline void spdlog::logger::set_formatter(spdlog::formatter_ptr msg_formatter)
|
||||||
{
|
{
|
||||||
_set_formatter(msg_formatter);
|
_set_formatter(msg_formatter);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void spdlog::logger::set_pattern(const std::string& pattern)
|
inline void spdlog::logger::set_pattern(const std::string& pattern)
|
||||||
{
|
{
|
||||||
_set_pattern(pattern);
|
_set_pattern(pattern);
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// log only if given level>=logger's log level
|
// log only if given level>=logger's log level
|
||||||
//
|
//
|
||||||
|
|
||||||
|
|
||||||
template <typename... Args>
|
template <typename... Args>
|
||||||
inline spdlog::details::line_logger spdlog::logger::_log_if_enabled(level::level_enum lvl, const char* fmt, const Args&... args)
|
inline spdlog::details::line_logger spdlog::logger::_log_if_enabled(level::level_enum lvl, const char* fmt, const Args&... args)
|
||||||
{
|
{
|
||||||
bool msg_enabled = should_log(lvl);
|
bool msg_enabled = should_log(lvl);
|
||||||
details::line_logger l(this, lvl, msg_enabled);
|
details::line_logger l(this, lvl, msg_enabled);
|
||||||
l.write(fmt, args...);
|
l.write(fmt, args...);
|
||||||
return l;
|
return l;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline spdlog::details::line_logger spdlog::logger::_log_if_enabled(level::level_enum lvl)
|
inline spdlog::details::line_logger spdlog::logger::_log_if_enabled(level::level_enum lvl)
|
||||||
{
|
{
|
||||||
return details::line_logger(this, lvl, should_log(lvl));
|
return details::line_logger(this, lvl, should_log(lvl));
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
inline spdlog::details::line_logger spdlog::logger::_log_if_enabled(level::level_enum lvl, const T& msg)
|
inline spdlog::details::line_logger spdlog::logger::_log_if_enabled(level::level_enum lvl, const T& msg)
|
||||||
{
|
{
|
||||||
bool msg_enabled = should_log(lvl);
|
bool msg_enabled = should_log(lvl);
|
||||||
details::line_logger l(this, lvl, msg_enabled);
|
details::line_logger l(this, lvl, msg_enabled);
|
||||||
l << msg;
|
l << msg;
|
||||||
return l;
|
return l;
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// logger.info(cppformat_string, arg1, arg2, arg3, ...) call style
|
// logger.info(cppformat_string, arg1, arg2, arg3, ...) call style
|
||||||
//
|
//
|
||||||
template <typename... Args>
|
template <typename... Args>
|
||||||
inline spdlog::details::line_logger spdlog::logger::trace(const char* fmt, const Args&... args)
|
inline spdlog::details::line_logger spdlog::logger::trace(const char* fmt, const Args&... args)
|
||||||
{
|
{
|
||||||
return _log_if_enabled(level::trace, fmt, args...);
|
return _log_if_enabled(level::trace, fmt, args...);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename... Args>
|
template <typename... Args>
|
||||||
inline spdlog::details::line_logger spdlog::logger::debug(const char* fmt, const Args&... args)
|
inline spdlog::details::line_logger spdlog::logger::debug(const char* fmt, const Args&... args)
|
||||||
{
|
{
|
||||||
return _log_if_enabled(level::debug, fmt, args...);
|
return _log_if_enabled(level::debug, fmt, args...);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename... Args>
|
template <typename... Args>
|
||||||
inline spdlog::details::line_logger spdlog::logger::info(const char* fmt, const Args&... args)
|
inline spdlog::details::line_logger spdlog::logger::info(const char* fmt, const Args&... args)
|
||||||
{
|
{
|
||||||
return _log_if_enabled(level::info, fmt, args...);
|
return _log_if_enabled(level::info, fmt, args...);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename... Args>
|
template <typename... Args>
|
||||||
inline spdlog::details::line_logger spdlog::logger::notice(const char* fmt, const Args&... args)
|
inline spdlog::details::line_logger spdlog::logger::notice(const char* fmt, const Args&... args)
|
||||||
{
|
{
|
||||||
return _log_if_enabled(level::notice, fmt, args...);
|
return _log_if_enabled(level::notice, fmt, args...);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename... Args>
|
template <typename... Args>
|
||||||
inline spdlog::details::line_logger spdlog::logger::warn(const char* fmt, const Args&... args)
|
inline spdlog::details::line_logger spdlog::logger::warn(const char* fmt, const Args&... args)
|
||||||
{
|
{
|
||||||
return _log_if_enabled(level::warn, fmt, args...);
|
return _log_if_enabled(level::warn, fmt, args...);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename... Args>
|
template <typename... Args>
|
||||||
inline spdlog::details::line_logger spdlog::logger::error(const char* fmt, const Args&... args)
|
inline spdlog::details::line_logger spdlog::logger::error(const char* fmt, const Args&... args)
|
||||||
{
|
{
|
||||||
return _log_if_enabled(level::err, fmt, args...);
|
return _log_if_enabled(level::err, fmt, args...);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename... Args>
|
template <typename... Args>
|
||||||
inline spdlog::details::line_logger spdlog::logger::critical(const char* fmt, const Args&... args)
|
inline spdlog::details::line_logger spdlog::logger::critical(const char* fmt, const Args&... args)
|
||||||
{
|
{
|
||||||
return _log_if_enabled(level::critical, fmt, args...);
|
return _log_if_enabled(level::critical, fmt, args...);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename... Args>
|
template <typename... Args>
|
||||||
inline spdlog::details::line_logger spdlog::logger::alert(const char* fmt, const Args&... args)
|
inline spdlog::details::line_logger spdlog::logger::alert(const char* fmt, const Args&... args)
|
||||||
{
|
{
|
||||||
return _log_if_enabled(level::alert, fmt, args...);
|
return _log_if_enabled(level::alert, fmt, args...);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename... Args>
|
template <typename... Args>
|
||||||
inline spdlog::details::line_logger spdlog::logger::emerg(const char* fmt, const Args&... args)
|
inline spdlog::details::line_logger spdlog::logger::emerg(const char* fmt, const Args&... args)
|
||||||
{
|
{
|
||||||
return _log_if_enabled(level::emerg, fmt, args...);
|
return _log_if_enabled(level::emerg, fmt, args...);
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// logger.info(msg) << ".." call style
|
// logger.info(msg) << ".." call style
|
||||||
//
|
//
|
||||||
template<typename T>
|
template<typename T>
|
||||||
inline spdlog::details::line_logger spdlog::logger::trace(const T& msg)
|
inline spdlog::details::line_logger spdlog::logger::trace(const T& msg)
|
||||||
{
|
{
|
||||||
return _log_if_enabled(level::trace, msg);
|
return _log_if_enabled(level::trace, msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
inline spdlog::details::line_logger spdlog::logger::debug(const T& msg)
|
inline spdlog::details::line_logger spdlog::logger::debug(const T& msg)
|
||||||
{
|
{
|
||||||
return _log_if_enabled(level::debug, msg);
|
return _log_if_enabled(level::debug, msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
inline spdlog::details::line_logger spdlog::logger::info(const T& msg)
|
inline spdlog::details::line_logger spdlog::logger::info(const T& msg)
|
||||||
{
|
{
|
||||||
return _log_if_enabled(level::info, msg);
|
return _log_if_enabled(level::info, msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
inline spdlog::details::line_logger spdlog::logger::notice(const T& msg)
|
inline spdlog::details::line_logger spdlog::logger::notice(const T& msg)
|
||||||
{
|
{
|
||||||
return _log_if_enabled(level::notice, msg);
|
return _log_if_enabled(level::notice, msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
inline spdlog::details::line_logger spdlog::logger::warn(const T& msg)
|
inline spdlog::details::line_logger spdlog::logger::warn(const T& msg)
|
||||||
{
|
{
|
||||||
return _log_if_enabled(level::warn, msg);
|
return _log_if_enabled(level::warn, msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
inline spdlog::details::line_logger spdlog::logger::error(const T& msg)
|
inline spdlog::details::line_logger spdlog::logger::error(const T& msg)
|
||||||
{
|
{
|
||||||
return _log_if_enabled(level::err, msg);
|
return _log_if_enabled(level::err, msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
inline spdlog::details::line_logger spdlog::logger::critical(const T& msg)
|
inline spdlog::details::line_logger spdlog::logger::critical(const T& msg)
|
||||||
{
|
{
|
||||||
return _log_if_enabled(level::critical, msg);
|
return _log_if_enabled(level::critical, msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
inline spdlog::details::line_logger spdlog::logger::alert(const T& msg)
|
inline spdlog::details::line_logger spdlog::logger::alert(const T& msg)
|
||||||
{
|
{
|
||||||
return _log_if_enabled(level::alert, msg);
|
return _log_if_enabled(level::alert, msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
inline spdlog::details::line_logger spdlog::logger::emerg(const T& msg)
|
inline spdlog::details::line_logger spdlog::logger::emerg(const T& msg)
|
||||||
{
|
{
|
||||||
return _log_if_enabled(level::emerg, msg);
|
return _log_if_enabled(level::emerg, msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// logger.info() << ".." call style
|
// logger.info() << ".." call style
|
||||||
//
|
//
|
||||||
inline spdlog::details::line_logger spdlog::logger::trace()
|
inline spdlog::details::line_logger spdlog::logger::trace()
|
||||||
{
|
{
|
||||||
return _log_if_enabled(level::trace);
|
return _log_if_enabled(level::trace);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline spdlog::details::line_logger spdlog::logger::debug()
|
inline spdlog::details::line_logger spdlog::logger::debug()
|
||||||
{
|
{
|
||||||
return _log_if_enabled(level::debug);
|
return _log_if_enabled(level::debug);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline spdlog::details::line_logger spdlog::logger::info()
|
inline spdlog::details::line_logger spdlog::logger::info()
|
||||||
{
|
{
|
||||||
return _log_if_enabled(level::info);
|
return _log_if_enabled(level::info);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline spdlog::details::line_logger spdlog::logger::notice()
|
inline spdlog::details::line_logger spdlog::logger::notice()
|
||||||
{
|
{
|
||||||
return _log_if_enabled(level::notice);
|
return _log_if_enabled(level::notice);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline spdlog::details::line_logger spdlog::logger::warn()
|
inline spdlog::details::line_logger spdlog::logger::warn()
|
||||||
{
|
{
|
||||||
return _log_if_enabled(level::warn);
|
return _log_if_enabled(level::warn);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline spdlog::details::line_logger spdlog::logger::error()
|
inline spdlog::details::line_logger spdlog::logger::error()
|
||||||
{
|
{
|
||||||
return _log_if_enabled(level::err);
|
return _log_if_enabled(level::err);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline spdlog::details::line_logger spdlog::logger::critical()
|
inline spdlog::details::line_logger spdlog::logger::critical()
|
||||||
{
|
{
|
||||||
return _log_if_enabled(level::critical);
|
return _log_if_enabled(level::critical);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline spdlog::details::line_logger spdlog::logger::alert()
|
inline spdlog::details::line_logger spdlog::logger::alert()
|
||||||
{
|
{
|
||||||
return _log_if_enabled(level::alert);
|
return _log_if_enabled(level::alert);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline spdlog::details::line_logger spdlog::logger::emerg()
|
inline spdlog::details::line_logger spdlog::logger::emerg()
|
||||||
{
|
{
|
||||||
return _log_if_enabled(level::emerg);
|
return _log_if_enabled(level::emerg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// always log, no matter what is the actual logger's log level
|
// always log, no matter what is the actual logger's log level
|
||||||
template <typename... Args>
|
template <typename... Args>
|
||||||
inline spdlog::details::line_logger spdlog::logger::force_log(level::level_enum lvl, const char* fmt, const Args&... args)
|
inline spdlog::details::line_logger spdlog::logger::force_log(level::level_enum lvl, const char* fmt, const Args&... args)
|
||||||
{
|
{
|
||||||
details::line_logger l(this, lvl, true);
|
details::line_logger l(this, lvl, true);
|
||||||
l.write(fmt, args...);
|
l.write(fmt, args...);
|
||||||
return l;
|
return l;
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// name and level
|
// name and level
|
||||||
//
|
//
|
||||||
inline const std::string& spdlog::logger::name() const
|
inline const std::string& spdlog::logger::name() const
|
||||||
{
|
{
|
||||||
return _name;
|
return _name;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void spdlog::logger::set_level(spdlog::level::level_enum log_level)
|
inline void spdlog::logger::set_level(spdlog::level::level_enum log_level)
|
||||||
{
|
{
|
||||||
_level.store(log_level);
|
_level.store(log_level);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline spdlog::level::level_enum spdlog::logger::level() const
|
inline spdlog::level::level_enum spdlog::logger::level() const
|
||||||
{
|
{
|
||||||
return static_cast<spdlog::level::level_enum>(_level.load(std::memory_order_relaxed));
|
return static_cast<spdlog::level::level_enum>(_level.load(std::memory_order_relaxed));
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool spdlog::logger::should_log(spdlog::level::level_enum msg_level) const
|
inline bool spdlog::logger::should_log(spdlog::level::level_enum msg_level) const
|
||||||
{
|
{
|
||||||
return msg_level >= _level.load(std::memory_order_relaxed);
|
return msg_level >= _level.load(std::memory_order_relaxed);
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// protected virtual called at end of each user log call (if enabled) by the line_logger
|
// protected virtual called at end of each user log call (if enabled) by the line_logger
|
||||||
//
|
//
|
||||||
inline void spdlog::logger::_log_msg(details::log_msg& msg)
|
inline void spdlog::logger::_log_msg(details::log_msg& msg)
|
||||||
{
|
{
|
||||||
_formatter->format(msg);
|
_formatter->format(msg);
|
||||||
for (auto &sink : _sinks)
|
for (auto &sink : _sinks)
|
||||||
sink->log(msg);
|
sink->log(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void spdlog::logger::_set_pattern(const std::string& pattern)
|
inline void spdlog::logger::_set_pattern(const std::string& pattern)
|
||||||
{
|
{
|
||||||
_formatter = std::make_shared<pattern_formatter>(pattern);
|
_formatter = std::make_shared<pattern_formatter>(pattern);
|
||||||
}
|
}
|
||||||
inline void spdlog::logger::_set_formatter(formatter_ptr msg_formatter)
|
inline void spdlog::logger::_set_formatter(formatter_ptr msg_formatter)
|
||||||
{
|
{
|
||||||
_formatter = msg_formatter;
|
_formatter = msg_formatter;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void spdlog::logger::flush()
|
inline void spdlog::logger::flush()
|
||||||
{
|
{
|
||||||
for (auto& sink : _sinks)
|
for (auto& sink : _sinks)
|
||||||
sink->flush();
|
sink->flush();
|
||||||
}
|
}
|
||||||
|
@ -1,159 +1,159 @@
|
|||||||
/*
|
/*
|
||||||
A modified version of Bounded MPMC queue by Dmitry Vyukov.
|
A modified version of Bounded MPMC queue by Dmitry Vyukov.
|
||||||
|
|
||||||
Original code from:
|
Original code from:
|
||||||
http://www.1024cores.net/home/lock-free-algorithms/queues/bounded-mpmc-queue
|
http://www.1024cores.net/home/lock-free-algorithms/queues/bounded-mpmc-queue
|
||||||
|
|
||||||
licensed by Dmitry Vyukov under the terms below:
|
licensed by Dmitry Vyukov under the terms below:
|
||||||
|
|
||||||
Simplified BSD license
|
Simplified BSD license
|
||||||
|
|
||||||
Copyright (c) 2010-2011 Dmitry Vyukov. All rights reserved.
|
Copyright (c) 2010-2011 Dmitry Vyukov. All rights reserved.
|
||||||
Redistribution and use in source and binary forms, with or without modification,
|
Redistribution and use in source and binary forms, with or without modification,
|
||||||
are permitted provided that the following conditions are met:
|
are permitted provided that the following conditions are met:
|
||||||
1. Redistributions of source code must retain the above copyright notice, this list of
|
1. Redistributions of source code must retain the above copyright notice, this list of
|
||||||
conditions and the following disclaimer.
|
conditions and the following disclaimer.
|
||||||
|
|
||||||
2. Redistributions in binary form must reproduce the above copyright notice, this list
|
2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||||
of conditions and the following disclaimer in the documentation and/or other materials
|
of conditions and the following disclaimer in the documentation and/or other materials
|
||||||
provided with the distribution.
|
provided with the distribution.
|
||||||
|
|
||||||
THIS SOFTWARE IS PROVIDED BY DMITRY VYUKOV "AS IS" AND ANY EXPRESS OR IMPLIED
|
THIS SOFTWARE IS PROVIDED BY DMITRY VYUKOV "AS IS" AND ANY EXPRESS OR IMPLIED
|
||||||
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
||||||
SHALL DMITRY VYUKOV OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
SHALL DMITRY VYUKOV OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||||
OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
||||||
OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||||
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
The views and conclusions contained in the software and documentation are those of the authors and
|
The views and conclusions contained in the software and documentation are those of the authors and
|
||||||
should not be interpreted as representing official policies, either expressed or implied, of Dmitry Vyukov.
|
should not be interpreted as representing official policies, either expressed or implied, of Dmitry Vyukov.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
The code in its current form adds the license below:
|
The code in its current form adds the license below:
|
||||||
|
|
||||||
Copyright(c) 2015 Gabi Melman.
|
Copyright(c) 2015 Gabi Melman.
|
||||||
Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <spdlog/common.h>
|
#include <spdlog/common.h>
|
||||||
|
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
namespace spdlog
|
namespace spdlog
|
||||||
{
|
{
|
||||||
namespace details
|
namespace details
|
||||||
{
|
{
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
class mpmc_bounded_queue
|
class mpmc_bounded_queue
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
using item_type = T;
|
using item_type = T;
|
||||||
mpmc_bounded_queue(size_t buffer_size)
|
mpmc_bounded_queue(size_t buffer_size)
|
||||||
: buffer_(new cell_t [buffer_size]),
|
: buffer_(new cell_t [buffer_size]),
|
||||||
buffer_mask_(buffer_size - 1)
|
buffer_mask_(buffer_size - 1)
|
||||||
{
|
{
|
||||||
//queue size must be power of two
|
//queue size must be power of two
|
||||||
if(!((buffer_size >= 2) && ((buffer_size & (buffer_size - 1)) == 0)))
|
if(!((buffer_size >= 2) && ((buffer_size & (buffer_size - 1)) == 0)))
|
||||||
throw spdlog_ex("async logger queue size must be power of two");
|
throw spdlog_ex("async logger queue size must be power of two");
|
||||||
|
|
||||||
for (size_t i = 0; i != buffer_size; i += 1)
|
for (size_t i = 0; i != buffer_size; i += 1)
|
||||||
buffer_[i].sequence_.store(i, std::memory_order_relaxed);
|
buffer_[i].sequence_.store(i, std::memory_order_relaxed);
|
||||||
enqueue_pos_.store(0, std::memory_order_relaxed);
|
enqueue_pos_.store(0, std::memory_order_relaxed);
|
||||||
dequeue_pos_.store(0, std::memory_order_relaxed);
|
dequeue_pos_.store(0, std::memory_order_relaxed);
|
||||||
}
|
}
|
||||||
|
|
||||||
~mpmc_bounded_queue()
|
~mpmc_bounded_queue()
|
||||||
{
|
{
|
||||||
delete [] buffer_;
|
delete [] buffer_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool enqueue(T&& data)
|
bool enqueue(T&& data)
|
||||||
{
|
{
|
||||||
cell_t* cell;
|
cell_t* cell;
|
||||||
size_t pos = enqueue_pos_.load(std::memory_order_relaxed);
|
size_t pos = enqueue_pos_.load(std::memory_order_relaxed);
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
cell = &buffer_[pos & buffer_mask_];
|
cell = &buffer_[pos & buffer_mask_];
|
||||||
size_t seq = cell->sequence_.load(std::memory_order_acquire);
|
size_t seq = cell->sequence_.load(std::memory_order_acquire);
|
||||||
intptr_t dif = (intptr_t)seq - (intptr_t)pos;
|
intptr_t dif = (intptr_t)seq - (intptr_t)pos;
|
||||||
if (dif == 0)
|
if (dif == 0)
|
||||||
{
|
{
|
||||||
if (enqueue_pos_.compare_exchange_weak(pos, pos + 1, std::memory_order_relaxed))
|
if (enqueue_pos_.compare_exchange_weak(pos, pos + 1, std::memory_order_relaxed))
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
else if (dif < 0)
|
else if (dif < 0)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
pos = enqueue_pos_.load(std::memory_order_relaxed);
|
pos = enqueue_pos_.load(std::memory_order_relaxed);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
cell->data_ = std::move(data);
|
cell->data_ = std::move(data);
|
||||||
cell->sequence_.store(pos + 1, std::memory_order_release);
|
cell->sequence_.store(pos + 1, std::memory_order_release);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool dequeue(T& data)
|
bool dequeue(T& data)
|
||||||
{
|
{
|
||||||
cell_t* cell;
|
cell_t* cell;
|
||||||
size_t pos = dequeue_pos_.load(std::memory_order_relaxed);
|
size_t pos = dequeue_pos_.load(std::memory_order_relaxed);
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
cell = &buffer_[pos & buffer_mask_];
|
cell = &buffer_[pos & buffer_mask_];
|
||||||
size_t seq =
|
size_t seq =
|
||||||
cell->sequence_.load(std::memory_order_acquire);
|
cell->sequence_.load(std::memory_order_acquire);
|
||||||
intptr_t dif = (intptr_t)seq - (intptr_t)(pos + 1);
|
intptr_t dif = (intptr_t)seq - (intptr_t)(pos + 1);
|
||||||
if (dif == 0)
|
if (dif == 0)
|
||||||
{
|
{
|
||||||
if (dequeue_pos_.compare_exchange_weak(pos, pos + 1, std::memory_order_relaxed))
|
if (dequeue_pos_.compare_exchange_weak(pos, pos + 1, std::memory_order_relaxed))
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
else if (dif < 0)
|
else if (dif < 0)
|
||||||
return false;
|
return false;
|
||||||
else
|
else
|
||||||
pos = dequeue_pos_.load(std::memory_order_relaxed);
|
pos = dequeue_pos_.load(std::memory_order_relaxed);
|
||||||
}
|
}
|
||||||
data = std::move(cell->data_);
|
data = std::move(cell->data_);
|
||||||
cell->sequence_.store(pos + buffer_mask_ + 1, std::memory_order_release);
|
cell->sequence_.store(pos + buffer_mask_ + 1, std::memory_order_release);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct cell_t
|
struct cell_t
|
||||||
{
|
{
|
||||||
std::atomic<size_t> sequence_;
|
std::atomic<size_t> sequence_;
|
||||||
T data_;
|
T data_;
|
||||||
};
|
};
|
||||||
|
|
||||||
static size_t const cacheline_size = 64;
|
static size_t const cacheline_size = 64;
|
||||||
typedef char cacheline_pad_t [cacheline_size];
|
typedef char cacheline_pad_t [cacheline_size];
|
||||||
|
|
||||||
cacheline_pad_t pad0_;
|
cacheline_pad_t pad0_;
|
||||||
cell_t* const buffer_;
|
cell_t* const buffer_;
|
||||||
size_t const buffer_mask_;
|
size_t const buffer_mask_;
|
||||||
cacheline_pad_t pad1_;
|
cacheline_pad_t pad1_;
|
||||||
std::atomic<size_t> enqueue_pos_;
|
std::atomic<size_t> enqueue_pos_;
|
||||||
cacheline_pad_t pad2_;
|
cacheline_pad_t pad2_;
|
||||||
std::atomic<size_t> dequeue_pos_;
|
std::atomic<size_t> dequeue_pos_;
|
||||||
cacheline_pad_t pad3_;
|
cacheline_pad_t pad3_;
|
||||||
|
|
||||||
mpmc_bounded_queue(mpmc_bounded_queue const&);
|
mpmc_bounded_queue(mpmc_bounded_queue const&);
|
||||||
void operator = (mpmc_bounded_queue const&);
|
void operator = (mpmc_bounded_queue const&);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // ns details
|
} // ns details
|
||||||
} // ns spdlog
|
} // ns spdlog
|
||||||
|
@ -1,222 +1,222 @@
|
|||||||
//
|
//
|
||||||
// Copyright(c) 2015 Gabi Melman.
|
// Copyright(c) 2015 Gabi Melman.
|
||||||
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||||
//
|
//
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <spdlog/common.h>
|
#include <spdlog/common.h>
|
||||||
|
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <ctime>
|
#include <ctime>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
|
|
||||||
#ifndef NOMINMAX
|
#ifndef NOMINMAX
|
||||||
#define NOMINMAX //prevent windows redefining min/max
|
#define NOMINMAX //prevent windows redefining min/max
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef WIN32_LEAN_AND_MEAN
|
#ifndef WIN32_LEAN_AND_MEAN
|
||||||
#define WIN32_LEAN_AND_MEAN
|
#define WIN32_LEAN_AND_MEAN
|
||||||
#endif
|
#endif
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
|
|
||||||
#ifdef __MINGW32__
|
#ifdef __MINGW32__
|
||||||
#include <share.h>
|
#include <share.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#elif __linux__
|
#elif __linux__
|
||||||
#include <sys/syscall.h> //Use gettid() syscall under linux to get thread id
|
#include <sys/syscall.h> //Use gettid() syscall under linux to get thread id
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#else
|
#else
|
||||||
#include <thread>
|
#include <thread>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
namespace spdlog
|
namespace spdlog
|
||||||
{
|
{
|
||||||
namespace details
|
namespace details
|
||||||
{
|
{
|
||||||
namespace os
|
namespace os
|
||||||
{
|
{
|
||||||
|
|
||||||
inline spdlog::log_clock::time_point now()
|
inline spdlog::log_clock::time_point now()
|
||||||
{
|
{
|
||||||
|
|
||||||
#if defined __linux__ && defined SPDLOG_CLOCK_COARSE
|
#if defined __linux__ && defined SPDLOG_CLOCK_COARSE
|
||||||
timespec ts;
|
timespec ts;
|
||||||
::clock_gettime(CLOCK_REALTIME_COARSE, &ts);
|
::clock_gettime(CLOCK_REALTIME_COARSE, &ts);
|
||||||
return std::chrono::time_point<log_clock, typename log_clock::duration>(
|
return std::chrono::time_point<log_clock, typename log_clock::duration>(
|
||||||
std::chrono::duration_cast<typename log_clock::duration>(
|
std::chrono::duration_cast<typename log_clock::duration>(
|
||||||
std::chrono::seconds(ts.tv_sec) + std::chrono::nanoseconds(ts.tv_nsec)));
|
std::chrono::seconds(ts.tv_sec) + std::chrono::nanoseconds(ts.tv_nsec)));
|
||||||
|
|
||||||
|
|
||||||
#else
|
#else
|
||||||
return log_clock::now();
|
return log_clock::now();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
}
|
}
|
||||||
inline std::tm localtime(const std::time_t &time_tt)
|
inline std::tm localtime(const std::time_t &time_tt)
|
||||||
{
|
{
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
std::tm tm;
|
std::tm tm;
|
||||||
localtime_s(&tm, &time_tt);
|
localtime_s(&tm, &time_tt);
|
||||||
#else
|
#else
|
||||||
std::tm tm;
|
std::tm tm;
|
||||||
localtime_r(&time_tt, &tm);
|
localtime_r(&time_tt, &tm);
|
||||||
#endif
|
#endif
|
||||||
return tm;
|
return tm;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline std::tm localtime()
|
inline std::tm localtime()
|
||||||
{
|
{
|
||||||
std::time_t now_t = time(nullptr);
|
std::time_t now_t = time(nullptr);
|
||||||
return localtime(now_t);
|
return localtime(now_t);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
inline std::tm gmtime(const std::time_t &time_tt)
|
inline std::tm gmtime(const std::time_t &time_tt)
|
||||||
{
|
{
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
std::tm tm;
|
std::tm tm;
|
||||||
gmtime_s(&tm, &time_tt);
|
gmtime_s(&tm, &time_tt);
|
||||||
#else
|
#else
|
||||||
std::tm tm;
|
std::tm tm;
|
||||||
gmtime_r(&time_tt, &tm);
|
gmtime_r(&time_tt, &tm);
|
||||||
#endif
|
#endif
|
||||||
return tm;
|
return tm;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline std::tm gmtime()
|
inline std::tm gmtime()
|
||||||
{
|
{
|
||||||
std::time_t now_t = time(nullptr);
|
std::time_t now_t = time(nullptr);
|
||||||
return gmtime(now_t);
|
return gmtime(now_t);
|
||||||
}
|
}
|
||||||
inline bool operator==(const std::tm& tm1, const std::tm& tm2)
|
inline bool operator==(const std::tm& tm1, const std::tm& tm2)
|
||||||
{
|
{
|
||||||
return (tm1.tm_sec == tm2.tm_sec &&
|
return (tm1.tm_sec == tm2.tm_sec &&
|
||||||
tm1.tm_min == tm2.tm_min &&
|
tm1.tm_min == tm2.tm_min &&
|
||||||
tm1.tm_hour == tm2.tm_hour &&
|
tm1.tm_hour == tm2.tm_hour &&
|
||||||
tm1.tm_mday == tm2.tm_mday &&
|
tm1.tm_mday == tm2.tm_mday &&
|
||||||
tm1.tm_mon == tm2.tm_mon &&
|
tm1.tm_mon == tm2.tm_mon &&
|
||||||
tm1.tm_year == tm2.tm_year &&
|
tm1.tm_year == tm2.tm_year &&
|
||||||
tm1.tm_isdst == tm2.tm_isdst);
|
tm1.tm_isdst == tm2.tm_isdst);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool operator!=(const std::tm& tm1, const std::tm& tm2)
|
inline bool operator!=(const std::tm& tm1, const std::tm& tm2)
|
||||||
{
|
{
|
||||||
return !(tm1 == tm2);
|
return !(tm1 == tm2);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
inline const char* eol()
|
inline const char* eol()
|
||||||
{
|
{
|
||||||
return "\r\n";
|
return "\r\n";
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
constexpr inline const char* eol()
|
constexpr inline const char* eol()
|
||||||
{
|
{
|
||||||
return "\n";
|
return "\n";
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
inline unsigned short eol_size()
|
inline unsigned short eol_size()
|
||||||
{
|
{
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
constexpr inline unsigned short eol_size()
|
constexpr inline unsigned short eol_size()
|
||||||
{
|
{
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
//fopen_s on non windows for writing
|
//fopen_s on non windows for writing
|
||||||
inline int fopen_s(FILE** fp, const std::string& filename, const char* mode)
|
inline int fopen_s(FILE** fp, const std::string& filename, const char* mode)
|
||||||
{
|
{
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
*fp = _fsopen((filename.c_str()), mode, _SH_DENYWR);
|
*fp = _fsopen((filename.c_str()), mode, _SH_DENYWR);
|
||||||
return *fp == nullptr;
|
return *fp == nullptr;
|
||||||
#else
|
#else
|
||||||
*fp = fopen((filename.c_str()), mode);
|
*fp = fopen((filename.c_str()), mode);
|
||||||
return *fp == nullptr;
|
return *fp == nullptr;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//Return if file exists
|
//Return if file exists
|
||||||
inline bool file_exists(const std::string& filename)
|
inline bool file_exists(const std::string& filename)
|
||||||
{
|
{
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
auto attribs = GetFileAttributesA(filename.c_str());
|
auto attribs = GetFileAttributesA(filename.c_str());
|
||||||
return (attribs != INVALID_FILE_ATTRIBUTES && !(attribs & FILE_ATTRIBUTE_DIRECTORY));
|
return (attribs != INVALID_FILE_ATTRIBUTES && !(attribs & FILE_ATTRIBUTE_DIRECTORY));
|
||||||
#elif __linux__
|
#elif __linux__
|
||||||
struct stat buffer;
|
struct stat buffer;
|
||||||
return (stat (filename.c_str(), &buffer) == 0);
|
return (stat (filename.c_str(), &buffer) == 0);
|
||||||
#else
|
#else
|
||||||
auto *file = fopen(filename.c_str(), "r");
|
auto *file = fopen(filename.c_str(), "r");
|
||||||
if (file != nullptr)
|
if (file != nullptr)
|
||||||
{
|
{
|
||||||
fclose(file);
|
fclose(file);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//Return utc offset in minutes or throw spdlog_ex on failure
|
//Return utc offset in minutes or throw spdlog_ex on failure
|
||||||
inline int utc_minutes_offset(const std::tm& tm = details::os::localtime())
|
inline int utc_minutes_offset(const std::tm& tm = details::os::localtime())
|
||||||
{
|
{
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#if _WIN32_WINNT < _WIN32_WINNT_WS08
|
#if _WIN32_WINNT < _WIN32_WINNT_WS08
|
||||||
TIME_ZONE_INFORMATION tzinfo;
|
TIME_ZONE_INFORMATION tzinfo;
|
||||||
auto rv = GetTimeZoneInformation(&tzinfo);
|
auto rv = GetTimeZoneInformation(&tzinfo);
|
||||||
#else
|
#else
|
||||||
DYNAMIC_TIME_ZONE_INFORMATION tzinfo;
|
DYNAMIC_TIME_ZONE_INFORMATION tzinfo;
|
||||||
auto rv = GetDynamicTimeZoneInformation(&tzinfo);
|
auto rv = GetDynamicTimeZoneInformation(&tzinfo);
|
||||||
#endif
|
#endif
|
||||||
if (rv == TIME_ZONE_ID_INVALID)
|
if (rv == TIME_ZONE_ID_INVALID)
|
||||||
throw spdlog::spdlog_ex("Failed getting timezone info. Last error: " + GetLastError());
|
throw spdlog::spdlog_ex("Failed getting timezone info. Last error: " + GetLastError());
|
||||||
|
|
||||||
int offset = -tzinfo.Bias;
|
int offset = -tzinfo.Bias;
|
||||||
if (tm.tm_isdst)
|
if (tm.tm_isdst)
|
||||||
offset -= tzinfo.DaylightBias;
|
offset -= tzinfo.DaylightBias;
|
||||||
else
|
else
|
||||||
offset -= tzinfo.StandardBias;
|
offset -= tzinfo.StandardBias;
|
||||||
return offset;
|
return offset;
|
||||||
#else
|
#else
|
||||||
return static_cast<int>(tm.tm_gmtoff / 60);
|
return static_cast<int>(tm.tm_gmtoff / 60);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
//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(espcially under VS 2013)
|
//It exists because the std::this_thread::get_id() is much slower(espcially under VS 2013)
|
||||||
inline size_t thread_id()
|
inline size_t thread_id()
|
||||||
{
|
{
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
return static_cast<size_t>(::GetCurrentThreadId());
|
return static_cast<size_t>(::GetCurrentThreadId());
|
||||||
#elif __linux__
|
#elif __linux__
|
||||||
# if defined(__ANDROID__) && defined(__ANDROID_API__) && (__ANDROID_API__ < 21)
|
# if defined(__ANDROID__) && defined(__ANDROID_API__) && (__ANDROID_API__ < 21)
|
||||||
# define SYS_gettid __NR_gettid
|
# define SYS_gettid __NR_gettid
|
||||||
# endif
|
# endif
|
||||||
return static_cast<size_t>(syscall(SYS_gettid));
|
return static_cast<size_t>(syscall(SYS_gettid));
|
||||||
#else //Default to standard C++11 (OSX and other Unix)
|
#else //Default to standard C++11 (OSX and other Unix)
|
||||||
return static_cast<size_t>(std::hash<std::thread::id>()(std::this_thread::get_id()));
|
return static_cast<size_t>(std::hash<std::thread::id>()(std::this_thread::get_id()));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} //os
|
} //os
|
||||||
} //details
|
} //details
|
||||||
} //spdlog
|
} //spdlog
|
||||||
|
|
||||||
|
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -1,163 +1,163 @@
|
|||||||
//
|
//
|
||||||
// Copyright(c) 2015 Gabi Melman.
|
// Copyright(c) 2015 Gabi Melman.
|
||||||
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||||
//
|
//
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
// Loggers registy of unique name->logger pointer
|
// Loggers registy of unique name->logger pointer
|
||||||
// An attempt to create a logger with an already existing name will be ignored
|
// An attempt to create a logger with an already existing name will be ignored
|
||||||
// If user requests a non existing logger, nullptr will be returned
|
// If user requests a non existing logger, nullptr will be returned
|
||||||
// This class is thread safe
|
// This class is thread safe
|
||||||
|
|
||||||
#include <spdlog/details/null_mutex.h>
|
#include <spdlog/details/null_mutex.h>
|
||||||
#include <spdlog/logger.h>
|
#include <spdlog/logger.h>
|
||||||
#include <spdlog/async_logger.h>
|
#include <spdlog/async_logger.h>
|
||||||
#include <spdlog/common.h>
|
#include <spdlog/common.h>
|
||||||
|
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
|
||||||
namespace spdlog
|
namespace spdlog
|
||||||
{
|
{
|
||||||
namespace details
|
namespace details
|
||||||
{
|
{
|
||||||
template <class Mutex> class registry_t
|
template <class Mutex> class registry_t
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
void register_logger(std::shared_ptr<logger> logger)
|
void register_logger(std::shared_ptr<logger> logger)
|
||||||
{
|
{
|
||||||
std::lock_guard<Mutex> lock(_mutex);
|
std::lock_guard<Mutex> lock(_mutex);
|
||||||
auto logger_name = logger->name();
|
auto logger_name = logger->name();
|
||||||
throw_if_exists(logger_name);
|
throw_if_exists(logger_name);
|
||||||
_loggers[logger_name] = logger;
|
_loggers[logger_name] = logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
std::shared_ptr<logger> get(const std::string& logger_name)
|
std::shared_ptr<logger> get(const std::string& logger_name)
|
||||||
{
|
{
|
||||||
std::lock_guard<Mutex> lock(_mutex);
|
std::lock_guard<Mutex> lock(_mutex);
|
||||||
auto found = _loggers.find(logger_name);
|
auto found = _loggers.find(logger_name);
|
||||||
return found == _loggers.end() ? nullptr : found->second;
|
return found == _loggers.end() ? nullptr : found->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class It>
|
template<class It>
|
||||||
std::shared_ptr<logger> create(const std::string& logger_name, const It& sinks_begin, const It& sinks_end)
|
std::shared_ptr<logger> create(const std::string& logger_name, const It& sinks_begin, const It& sinks_end)
|
||||||
{
|
{
|
||||||
std::lock_guard<Mutex> lock(_mutex);
|
std::lock_guard<Mutex> lock(_mutex);
|
||||||
throw_if_exists(logger_name);
|
throw_if_exists(logger_name);
|
||||||
std::shared_ptr<logger> new_logger;
|
std::shared_ptr<logger> new_logger;
|
||||||
if (_async_mode)
|
if (_async_mode)
|
||||||
new_logger = std::make_shared<async_logger>(logger_name, sinks_begin, sinks_end, _async_q_size, _overflow_policy, _worker_warmup_cb, _flush_interval_ms);
|
new_logger = std::make_shared<async_logger>(logger_name, sinks_begin, sinks_end, _async_q_size, _overflow_policy, _worker_warmup_cb, _flush_interval_ms);
|
||||||
else
|
else
|
||||||
new_logger = std::make_shared<logger>(logger_name, sinks_begin, sinks_end);
|
new_logger = std::make_shared<logger>(logger_name, sinks_begin, sinks_end);
|
||||||
|
|
||||||
if (_formatter)
|
if (_formatter)
|
||||||
new_logger->set_formatter(_formatter);
|
new_logger->set_formatter(_formatter);
|
||||||
|
|
||||||
new_logger->set_level(_level);
|
new_logger->set_level(_level);
|
||||||
//Add to registry
|
//Add to registry
|
||||||
_loggers[logger_name] = new_logger;
|
_loggers[logger_name] = new_logger;
|
||||||
return new_logger;
|
return new_logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
void drop(const std::string& logger_name)
|
void drop(const std::string& logger_name)
|
||||||
{
|
{
|
||||||
std::lock_guard<Mutex> lock(_mutex);
|
std::lock_guard<Mutex> lock(_mutex);
|
||||||
_loggers.erase(logger_name);
|
_loggers.erase(logger_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
void drop_all()
|
void drop_all()
|
||||||
{
|
{
|
||||||
std::lock_guard<Mutex> lock(_mutex);
|
std::lock_guard<Mutex> lock(_mutex);
|
||||||
_loggers.clear();
|
_loggers.clear();
|
||||||
}
|
}
|
||||||
std::shared_ptr<logger> create(const std::string& logger_name, sinks_init_list sinks)
|
std::shared_ptr<logger> create(const std::string& logger_name, sinks_init_list sinks)
|
||||||
{
|
{
|
||||||
return create(logger_name, sinks.begin(), sinks.end());
|
return create(logger_name, sinks.begin(), sinks.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<logger> create(const std::string& logger_name, sink_ptr sink)
|
std::shared_ptr<logger> create(const std::string& logger_name, sink_ptr sink)
|
||||||
{
|
{
|
||||||
return create(logger_name, { sink });
|
return create(logger_name, { sink });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void formatter(formatter_ptr f)
|
void formatter(formatter_ptr f)
|
||||||
{
|
{
|
||||||
std::lock_guard<Mutex> lock(_mutex);
|
std::lock_guard<Mutex> lock(_mutex);
|
||||||
_formatter = f;
|
_formatter = f;
|
||||||
for (auto& l : _loggers)
|
for (auto& l : _loggers)
|
||||||
l.second->set_formatter(_formatter);
|
l.second->set_formatter(_formatter);
|
||||||
}
|
}
|
||||||
|
|
||||||
void set_pattern(const std::string& pattern)
|
void set_pattern(const std::string& pattern)
|
||||||
{
|
{
|
||||||
std::lock_guard<Mutex> lock(_mutex);
|
std::lock_guard<Mutex> lock(_mutex);
|
||||||
_formatter = std::make_shared<pattern_formatter>(pattern);
|
_formatter = std::make_shared<pattern_formatter>(pattern);
|
||||||
for (auto& l : _loggers)
|
for (auto& l : _loggers)
|
||||||
l.second->set_formatter(_formatter);
|
l.second->set_formatter(_formatter);
|
||||||
}
|
}
|
||||||
|
|
||||||
void set_level(level::level_enum log_level)
|
void set_level(level::level_enum log_level)
|
||||||
{
|
{
|
||||||
std::lock_guard<Mutex> lock(_mutex);
|
std::lock_guard<Mutex> lock(_mutex);
|
||||||
for (auto& l : _loggers)
|
for (auto& l : _loggers)
|
||||||
l.second->set_level(log_level);
|
l.second->set_level(log_level);
|
||||||
_level = log_level;
|
_level = log_level;
|
||||||
}
|
}
|
||||||
|
|
||||||
void set_async_mode(size_t q_size, const async_overflow_policy overflow_policy, const std::function<void()>& worker_warmup_cb, const std::chrono::milliseconds& flush_interval_ms)
|
void set_async_mode(size_t q_size, const async_overflow_policy overflow_policy, const std::function<void()>& worker_warmup_cb, const std::chrono::milliseconds& flush_interval_ms)
|
||||||
{
|
{
|
||||||
std::lock_guard<Mutex> lock(_mutex);
|
std::lock_guard<Mutex> lock(_mutex);
|
||||||
_async_mode = true;
|
_async_mode = true;
|
||||||
_async_q_size = q_size;
|
_async_q_size = q_size;
|
||||||
_overflow_policy = overflow_policy;
|
_overflow_policy = overflow_policy;
|
||||||
_worker_warmup_cb = worker_warmup_cb;
|
_worker_warmup_cb = worker_warmup_cb;
|
||||||
_flush_interval_ms = flush_interval_ms;
|
_flush_interval_ms = flush_interval_ms;
|
||||||
}
|
}
|
||||||
|
|
||||||
void set_sync_mode()
|
void set_sync_mode()
|
||||||
{
|
{
|
||||||
std::lock_guard<Mutex> lock(_mutex);
|
std::lock_guard<Mutex> lock(_mutex);
|
||||||
_async_mode = false;
|
_async_mode = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static registry_t<Mutex>& instance()
|
static registry_t<Mutex>& instance()
|
||||||
{
|
{
|
||||||
static registry_t<Mutex> s_instance;
|
static registry_t<Mutex> s_instance;
|
||||||
return s_instance;
|
return s_instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
registry_t<Mutex>() {}
|
registry_t<Mutex>() {}
|
||||||
registry_t<Mutex>(const registry_t<Mutex>&) = delete;
|
registry_t<Mutex>(const registry_t<Mutex>&) = delete;
|
||||||
registry_t<Mutex>& operator=(const registry_t<Mutex>&) = delete;
|
registry_t<Mutex>& operator=(const registry_t<Mutex>&) = delete;
|
||||||
|
|
||||||
void throw_if_exists(const std::string &logger_name)
|
void throw_if_exists(const std::string &logger_name)
|
||||||
{
|
{
|
||||||
if (_loggers.find(logger_name) != _loggers.end())
|
if (_loggers.find(logger_name) != _loggers.end())
|
||||||
throw spdlog_ex("logger with name '" + logger_name + "' already exists");
|
throw spdlog_ex("logger with name '" + logger_name + "' already exists");
|
||||||
}
|
}
|
||||||
Mutex _mutex;
|
Mutex _mutex;
|
||||||
std::unordered_map <std::string, std::shared_ptr<logger>> _loggers;
|
std::unordered_map <std::string, std::shared_ptr<logger>> _loggers;
|
||||||
formatter_ptr _formatter;
|
formatter_ptr _formatter;
|
||||||
level::level_enum _level = level::info;
|
level::level_enum _level = level::info;
|
||||||
bool _async_mode = false;
|
bool _async_mode = false;
|
||||||
size_t _async_q_size = 0;
|
size_t _async_q_size = 0;
|
||||||
async_overflow_policy _overflow_policy = async_overflow_policy::block_retry;
|
async_overflow_policy _overflow_policy = async_overflow_policy::block_retry;
|
||||||
std::function<void()> _worker_warmup_cb = nullptr;
|
std::function<void()> _worker_warmup_cb = nullptr;
|
||||||
std::chrono::milliseconds _flush_interval_ms;
|
std::chrono::milliseconds _flush_interval_ms;
|
||||||
};
|
};
|
||||||
#ifdef SPDLOG_NO_REGISTRY_MUTEX
|
#ifdef SPDLOG_NO_REGISTRY_MUTEX
|
||||||
typedef registry_t<spdlog::details::null_mutex> registry;
|
typedef registry_t<spdlog::details::null_mutex> registry;
|
||||||
#else
|
#else
|
||||||
typedef registry_t<std::mutex> registry;
|
typedef registry_t<std::mutex> registry;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,148 +1,148 @@
|
|||||||
//
|
//
|
||||||
// Copyright(c) 2015 Gabi Melman.
|
// Copyright(c) 2015 Gabi Melman.
|
||||||
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||||
//
|
//
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
//
|
//
|
||||||
// Global registry functions
|
// Global registry functions
|
||||||
//
|
//
|
||||||
#include <spdlog/spdlog.h>
|
#include <spdlog/spdlog.h>
|
||||||
#include <spdlog/details/registry.h>
|
#include <spdlog/details/registry.h>
|
||||||
#include <spdlog/sinks/file_sinks.h>
|
#include <spdlog/sinks/file_sinks.h>
|
||||||
#include <spdlog/sinks/stdout_sinks.h>
|
#include <spdlog/sinks/stdout_sinks.h>
|
||||||
#include <spdlog/sinks/syslog_sink.h>
|
#include <spdlog/sinks/syslog_sink.h>
|
||||||
#include <spdlog/sinks/ansicolor_sink.h>
|
#include <spdlog/sinks/ansicolor_sink.h>
|
||||||
|
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
inline void spdlog::register_logger(std::shared_ptr<logger> logger)
|
inline void spdlog::register_logger(std::shared_ptr<logger> logger)
|
||||||
{
|
{
|
||||||
return details::registry::instance().register_logger(logger);
|
return details::registry::instance().register_logger(logger);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline std::shared_ptr<spdlog::logger> spdlog::get(const std::string& name)
|
inline std::shared_ptr<spdlog::logger> spdlog::get(const std::string& name)
|
||||||
{
|
{
|
||||||
return details::registry::instance().get(name);
|
return details::registry::instance().get(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void spdlog::drop(const std::string &name)
|
inline void spdlog::drop(const std::string &name)
|
||||||
{
|
{
|
||||||
details::registry::instance().drop(name);
|
details::registry::instance().drop(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create multi/single threaded rotating file logger
|
// Create multi/single threaded rotating file logger
|
||||||
inline std::shared_ptr<spdlog::logger> spdlog::rotating_logger_mt(const std::string& logger_name, const std::string& filename, size_t max_file_size, size_t max_files, bool force_flush)
|
inline std::shared_ptr<spdlog::logger> spdlog::rotating_logger_mt(const std::string& logger_name, const std::string& filename, size_t max_file_size, size_t max_files, bool force_flush)
|
||||||
{
|
{
|
||||||
return create<spdlog::sinks::rotating_file_sink_mt>(logger_name, filename, "txt", max_file_size, max_files, force_flush);
|
return create<spdlog::sinks::rotating_file_sink_mt>(logger_name, filename, "txt", max_file_size, max_files, force_flush);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline std::shared_ptr<spdlog::logger> spdlog::rotating_logger_st(const std::string& logger_name, const std::string& filename, size_t max_file_size, size_t max_files, bool force_flush)
|
inline std::shared_ptr<spdlog::logger> spdlog::rotating_logger_st(const std::string& logger_name, const std::string& filename, size_t max_file_size, size_t max_files, bool force_flush)
|
||||||
{
|
{
|
||||||
return create<spdlog::sinks::rotating_file_sink_st>(logger_name, filename, "txt", max_file_size, max_files, force_flush);
|
return create<spdlog::sinks::rotating_file_sink_st>(logger_name, filename, "txt", max_file_size, max_files, force_flush);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create file logger which creates new file at midnight):
|
// Create file logger which creates new file at midnight):
|
||||||
inline std::shared_ptr<spdlog::logger> spdlog::daily_logger_mt(const std::string& logger_name, const std::string& filename, int hour, int minute, bool force_flush)
|
inline std::shared_ptr<spdlog::logger> spdlog::daily_logger_mt(const std::string& logger_name, const std::string& filename, int hour, int minute, bool force_flush)
|
||||||
{
|
{
|
||||||
return create<spdlog::sinks::daily_file_sink_mt>(logger_name, filename, "txt", hour, minute, force_flush);
|
return create<spdlog::sinks::daily_file_sink_mt>(logger_name, filename, "txt", hour, minute, force_flush);
|
||||||
}
|
}
|
||||||
inline std::shared_ptr<spdlog::logger> spdlog::daily_logger_st(const std::string& logger_name, const std::string& filename, int hour, int minute, bool force_flush)
|
inline std::shared_ptr<spdlog::logger> spdlog::daily_logger_st(const std::string& logger_name, const std::string& filename, int hour, int minute, bool force_flush)
|
||||||
{
|
{
|
||||||
return create<spdlog::sinks::daily_file_sink_st>(logger_name, filename, "txt", hour, minute, force_flush);
|
return create<spdlog::sinks::daily_file_sink_st>(logger_name, filename, "txt", hour, minute, force_flush);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create stdout/stderr loggers (with optinal color support)
|
// Create stdout/stderr loggers (with optinal color support)
|
||||||
inline std::shared_ptr<spdlog::logger> create_console_logger(const std::string& logger_name, spdlog::sink_ptr sink, bool color)
|
inline std::shared_ptr<spdlog::logger> create_console_logger(const std::string& logger_name, spdlog::sink_ptr sink, bool color)
|
||||||
{
|
{
|
||||||
if (color) //use color wrapper sink
|
if (color) //use color wrapper sink
|
||||||
sink = std::make_shared<spdlog::sinks::ansicolor_sink>(sink);
|
sink = std::make_shared<spdlog::sinks::ansicolor_sink>(sink);
|
||||||
return spdlog::details::registry::instance().create(logger_name, sink);
|
return spdlog::details::registry::instance().create(logger_name, sink);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline std::shared_ptr<spdlog::logger> spdlog::stdout_logger_mt(const std::string& logger_name, bool color)
|
inline std::shared_ptr<spdlog::logger> spdlog::stdout_logger_mt(const std::string& logger_name, bool color)
|
||||||
{
|
{
|
||||||
return create_console_logger(logger_name, sinks::stdout_sink_mt::instance(), color);
|
return create_console_logger(logger_name, sinks::stdout_sink_mt::instance(), color);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline std::shared_ptr<spdlog::logger> spdlog::stdout_logger_st(const std::string& logger_name, bool color)
|
inline std::shared_ptr<spdlog::logger> spdlog::stdout_logger_st(const std::string& logger_name, bool color)
|
||||||
{
|
{
|
||||||
return create_console_logger(logger_name, sinks::stdout_sink_st::instance(), color);
|
return create_console_logger(logger_name, sinks::stdout_sink_st::instance(), color);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline std::shared_ptr<spdlog::logger> spdlog::stderr_logger_mt(const std::string& logger_name, bool color)
|
inline std::shared_ptr<spdlog::logger> spdlog::stderr_logger_mt(const std::string& logger_name, bool color)
|
||||||
{
|
{
|
||||||
return create_console_logger(logger_name, sinks::stderr_sink_mt::instance(), color);
|
return create_console_logger(logger_name, sinks::stderr_sink_mt::instance(), color);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline std::shared_ptr<spdlog::logger> spdlog::stderr_logger_st(const std::string& logger_name, bool color)
|
inline std::shared_ptr<spdlog::logger> spdlog::stderr_logger_st(const std::string& logger_name, bool color)
|
||||||
{
|
{
|
||||||
return create_console_logger(logger_name, sinks::stderr_sink_st::instance(), color);
|
return create_console_logger(logger_name, sinks::stderr_sink_st::instance(), color);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(__linux__) || defined(__APPLE__)
|
#if defined(__linux__) || defined(__APPLE__)
|
||||||
// Create syslog logger
|
// Create syslog logger
|
||||||
inline std::shared_ptr<spdlog::logger> spdlog::syslog_logger(const std::string& logger_name, const std::string& syslog_ident, int syslog_option)
|
inline std::shared_ptr<spdlog::logger> spdlog::syslog_logger(const std::string& logger_name, const std::string& syslog_ident, int syslog_option)
|
||||||
{
|
{
|
||||||
return create<spdlog::sinks::syslog_sink>(logger_name, syslog_ident, syslog_option);
|
return create<spdlog::sinks::syslog_sink>(logger_name, syslog_ident, syslog_option);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
//Create logger with multiple sinks
|
//Create logger with multiple sinks
|
||||||
|
|
||||||
inline std::shared_ptr<spdlog::logger> spdlog::create(const std::string& logger_name, spdlog::sinks_init_list sinks)
|
inline std::shared_ptr<spdlog::logger> spdlog::create(const std::string& logger_name, spdlog::sinks_init_list sinks)
|
||||||
{
|
{
|
||||||
return details::registry::instance().create(logger_name, sinks);
|
return details::registry::instance().create(logger_name, sinks);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
template <typename Sink, typename... Args>
|
template <typename Sink, typename... Args>
|
||||||
inline std::shared_ptr<spdlog::logger> spdlog::create(const std::string& logger_name, Args... args)
|
inline std::shared_ptr<spdlog::logger> spdlog::create(const std::string& logger_name, Args... args)
|
||||||
{
|
{
|
||||||
sink_ptr sink = std::make_shared<Sink>(args...);
|
sink_ptr sink = std::make_shared<Sink>(args...);
|
||||||
return details::registry::instance().create(logger_name, { sink });
|
return details::registry::instance().create(logger_name, { sink });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
template<class It>
|
template<class It>
|
||||||
inline std::shared_ptr<spdlog::logger> spdlog::create(const std::string& logger_name, const It& sinks_begin, const It& sinks_end)
|
inline std::shared_ptr<spdlog::logger> spdlog::create(const std::string& logger_name, const It& sinks_begin, const It& sinks_end)
|
||||||
{
|
{
|
||||||
return details::registry::instance().create(logger_name, sinks_begin, sinks_end);
|
return details::registry::instance().create(logger_name, sinks_begin, sinks_end);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void spdlog::set_formatter(spdlog::formatter_ptr f)
|
inline void spdlog::set_formatter(spdlog::formatter_ptr f)
|
||||||
{
|
{
|
||||||
details::registry::instance().formatter(f);
|
details::registry::instance().formatter(f);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void spdlog::set_pattern(const std::string& format_string)
|
inline void spdlog::set_pattern(const std::string& format_string)
|
||||||
{
|
{
|
||||||
return details::registry::instance().set_pattern(format_string);
|
return details::registry::instance().set_pattern(format_string);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void spdlog::set_level(level::level_enum log_level)
|
inline void spdlog::set_level(level::level_enum log_level)
|
||||||
{
|
{
|
||||||
return details::registry::instance().set_level(log_level);
|
return details::registry::instance().set_level(log_level);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
inline void spdlog::set_async_mode(size_t queue_size, const async_overflow_policy overflow_policy, const std::function<void()>& worker_warmup_cb, const std::chrono::milliseconds& flush_interval_ms)
|
inline void spdlog::set_async_mode(size_t queue_size, const async_overflow_policy overflow_policy, const std::function<void()>& worker_warmup_cb, const std::chrono::milliseconds& flush_interval_ms)
|
||||||
{
|
{
|
||||||
details::registry::instance().set_async_mode(queue_size, overflow_policy, worker_warmup_cb, flush_interval_ms);
|
details::registry::instance().set_async_mode(queue_size, overflow_policy, worker_warmup_cb, flush_interval_ms);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void spdlog::set_sync_mode()
|
inline void spdlog::set_sync_mode()
|
||||||
{
|
{
|
||||||
details::registry::instance().set_sync_mode();
|
details::registry::instance().set_sync_mode();
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void spdlog::drop_all()
|
inline void spdlog::drop_all()
|
||||||
{
|
{
|
||||||
details::registry::instance().drop_all();
|
details::registry::instance().drop_all();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,45 +1,45 @@
|
|||||||
//
|
//
|
||||||
// Copyright(c) 2015 Gabi Melman.
|
// Copyright(c) 2015 Gabi Melman.
|
||||||
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||||
//
|
//
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <spdlog/details/log_msg.h>
|
#include <spdlog/details/log_msg.h>
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
namespace spdlog
|
namespace spdlog
|
||||||
{
|
{
|
||||||
namespace details
|
namespace details
|
||||||
{
|
{
|
||||||
class flag_formatter;
|
class flag_formatter;
|
||||||
}
|
}
|
||||||
|
|
||||||
class formatter
|
class formatter
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
virtual ~formatter() {}
|
virtual ~formatter() {}
|
||||||
virtual void format(details::log_msg& msg) = 0;
|
virtual void format(details::log_msg& msg) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
class pattern_formatter : public formatter
|
class pattern_formatter : public formatter
|
||||||
{
|
{
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit pattern_formatter(const std::string& pattern);
|
explicit pattern_formatter(const std::string& pattern);
|
||||||
pattern_formatter(const pattern_formatter&) = delete;
|
pattern_formatter(const pattern_formatter&) = delete;
|
||||||
pattern_formatter& operator=(const pattern_formatter&) = delete;
|
pattern_formatter& operator=(const pattern_formatter&) = delete;
|
||||||
void format(details::log_msg& msg) override;
|
void format(details::log_msg& msg) override;
|
||||||
private:
|
private:
|
||||||
const std::string _pattern;
|
const std::string _pattern;
|
||||||
std::vector<std::unique_ptr<details::flag_formatter>> _formatters;
|
std::vector<std::unique_ptr<details::flag_formatter>> _formatters;
|
||||||
void handle_flag(char flag);
|
void handle_flag(char flag);
|
||||||
void compile_pattern(const std::string& pattern);
|
void compile_pattern(const std::string& pattern);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
#include <spdlog/details/pattern_formatter_impl.h>
|
#include <spdlog/details/pattern_formatter_impl.h>
|
||||||
|
|
||||||
|
@ -1,114 +1,114 @@
|
|||||||
//
|
//
|
||||||
// Copyright(c) 2015 Gabi Melman.
|
// Copyright(c) 2015 Gabi Melman.
|
||||||
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||||
//
|
//
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
// Thread safe logger
|
// Thread safe logger
|
||||||
// Has name, log level, vector of std::shared sink pointers and formatter
|
// Has name, log level, vector of std::shared sink pointers and formatter
|
||||||
// Upon each log write the logger:
|
// Upon each log write the logger:
|
||||||
// 1. Checks if its log level is enough to log the message
|
// 1. Checks if its log level is enough to log the message
|
||||||
// 2. Format the message using the formatter function
|
// 2. Format the message using the formatter function
|
||||||
// 3. Pass the formatted message to its sinks to performa the actual logging
|
// 3. Pass the formatted message to its sinks to performa the actual logging
|
||||||
|
|
||||||
#include <spdlog/sinks/base_sink.h>
|
#include <spdlog/sinks/base_sink.h>
|
||||||
#include <spdlog/common.h>
|
#include <spdlog/common.h>
|
||||||
#include <spdlog/details/line_logger_fwd.h>
|
#include <spdlog/details/line_logger_fwd.h>
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
namespace spdlog
|
namespace spdlog
|
||||||
{
|
{
|
||||||
|
|
||||||
class logger
|
class logger
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
logger(const std::string& logger_name, sink_ptr single_sink);
|
logger(const std::string& logger_name, sink_ptr single_sink);
|
||||||
logger(const std::string& name, sinks_init_list);
|
logger(const std::string& name, sinks_init_list);
|
||||||
template<class It>
|
template<class It>
|
||||||
logger(const std::string& name, const It& begin, const It& end);
|
logger(const std::string& name, const It& begin, const It& end);
|
||||||
|
|
||||||
virtual ~logger();
|
virtual ~logger();
|
||||||
logger(const logger&) = delete;
|
logger(const logger&) = delete;
|
||||||
logger& operator=(const logger&) = delete;
|
logger& operator=(const logger&) = delete;
|
||||||
|
|
||||||
void set_level(level::level_enum);
|
void set_level(level::level_enum);
|
||||||
level::level_enum level() const;
|
level::level_enum level() const;
|
||||||
|
|
||||||
const std::string& name() const;
|
const std::string& name() const;
|
||||||
bool should_log(level::level_enum) const;
|
bool should_log(level::level_enum) const;
|
||||||
|
|
||||||
// logger.info(cppformat_string, arg1, arg2, arg3, ...) call style
|
// logger.info(cppformat_string, arg1, arg2, arg3, ...) call style
|
||||||
template <typename... Args> details::line_logger trace(const char* fmt, const Args&... args);
|
template <typename... Args> details::line_logger trace(const char* fmt, const Args&... args);
|
||||||
template <typename... Args> details::line_logger debug(const char* fmt, const Args&... args);
|
template <typename... Args> details::line_logger debug(const char* fmt, const Args&... args);
|
||||||
template <typename... Args> details::line_logger info(const char* fmt, const Args&... args);
|
template <typename... Args> details::line_logger info(const char* fmt, const Args&... args);
|
||||||
template <typename... Args> details::line_logger notice(const char* fmt, const Args&... args);
|
template <typename... Args> details::line_logger notice(const char* fmt, const Args&... args);
|
||||||
template <typename... Args> details::line_logger warn(const char* fmt, const Args&... args);
|
template <typename... Args> details::line_logger warn(const char* fmt, const Args&... args);
|
||||||
template <typename... Args> details::line_logger error(const char* fmt, const Args&... args);
|
template <typename... Args> details::line_logger error(const char* fmt, const Args&... args);
|
||||||
template <typename... Args> details::line_logger critical(const char* fmt, const Args&... args);
|
template <typename... Args> details::line_logger critical(const char* fmt, const Args&... args);
|
||||||
template <typename... Args> details::line_logger alert(const char* fmt, const Args&... args);
|
template <typename... Args> details::line_logger alert(const char* fmt, const Args&... args);
|
||||||
template <typename... Args> details::line_logger emerg(const char* fmt, const Args&... args);
|
template <typename... Args> details::line_logger emerg(const char* fmt, const Args&... args);
|
||||||
|
|
||||||
|
|
||||||
// logger.info(msg) << ".." call style
|
// logger.info(msg) << ".." call style
|
||||||
template <typename T> details::line_logger trace(const T&);
|
template <typename T> details::line_logger trace(const T&);
|
||||||
template <typename T> details::line_logger debug(const T&);
|
template <typename T> details::line_logger debug(const T&);
|
||||||
template <typename T> details::line_logger info(const T&);
|
template <typename T> details::line_logger info(const T&);
|
||||||
template <typename T> details::line_logger notice(const T&);
|
template <typename T> details::line_logger notice(const T&);
|
||||||
template <typename T> details::line_logger warn(const T&);
|
template <typename T> details::line_logger warn(const T&);
|
||||||
template <typename T> details::line_logger error(const T&);
|
template <typename T> details::line_logger error(const T&);
|
||||||
template <typename T> details::line_logger critical(const T&);
|
template <typename T> details::line_logger critical(const T&);
|
||||||
template <typename T> details::line_logger alert(const T&);
|
template <typename T> details::line_logger alert(const T&);
|
||||||
template <typename T> details::line_logger emerg(const T&);
|
template <typename T> details::line_logger emerg(const T&);
|
||||||
|
|
||||||
|
|
||||||
// logger.info() << ".." call style
|
// logger.info() << ".." call style
|
||||||
details::line_logger trace();
|
details::line_logger trace();
|
||||||
details::line_logger debug();
|
details::line_logger debug();
|
||||||
details::line_logger info();
|
details::line_logger info();
|
||||||
details::line_logger notice();
|
details::line_logger notice();
|
||||||
details::line_logger warn();
|
details::line_logger warn();
|
||||||
details::line_logger error();
|
details::line_logger error();
|
||||||
details::line_logger critical();
|
details::line_logger critical();
|
||||||
details::line_logger alert();
|
details::line_logger alert();
|
||||||
details::line_logger emerg();
|
details::line_logger emerg();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Create log message with the given level, no matter what is the actual logger's level
|
// Create log message with the given level, no matter what is the actual logger's level
|
||||||
template <typename... Args>
|
template <typename... Args>
|
||||||
details::line_logger force_log(level::level_enum lvl, const char* fmt, const Args&... args);
|
details::line_logger force_log(level::level_enum lvl, const char* fmt, const Args&... args);
|
||||||
|
|
||||||
// Set the format of the log messages from this logger
|
// Set the format of the log messages from this logger
|
||||||
void set_pattern(const std::string&);
|
void set_pattern(const std::string&);
|
||||||
void set_formatter(formatter_ptr);
|
void set_formatter(formatter_ptr);
|
||||||
|
|
||||||
virtual void flush();
|
virtual void flush();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual void _log_msg(details::log_msg&);
|
virtual void _log_msg(details::log_msg&);
|
||||||
virtual void _set_pattern(const std::string&);
|
virtual void _set_pattern(const std::string&);
|
||||||
virtual void _set_formatter(formatter_ptr);
|
virtual void _set_formatter(formatter_ptr);
|
||||||
details::line_logger _log_if_enabled(level::level_enum lvl);
|
details::line_logger _log_if_enabled(level::level_enum lvl);
|
||||||
template <typename... Args>
|
template <typename... Args>
|
||||||
details::line_logger _log_if_enabled(level::level_enum lvl, const char* fmt, const Args&... args);
|
details::line_logger _log_if_enabled(level::level_enum lvl, const char* fmt, const Args&... args);
|
||||||
template<typename T>
|
template<typename T>
|
||||||
inline details::line_logger _log_if_enabled(level::level_enum lvl, const T& msg);
|
inline details::line_logger _log_if_enabled(level::level_enum lvl, const T& msg);
|
||||||
|
|
||||||
|
|
||||||
friend details::line_logger;
|
friend details::line_logger;
|
||||||
std::string _name;
|
std::string _name;
|
||||||
std::vector<sink_ptr> _sinks;
|
std::vector<sink_ptr> _sinks;
|
||||||
formatter_ptr _formatter;
|
formatter_ptr _formatter;
|
||||||
std::atomic_int _level;
|
std::atomic_int _level;
|
||||||
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
#include <spdlog/details/logger_impl.h>
|
#include <spdlog/details/logger_impl.h>
|
||||||
#include <spdlog/details/line_logger_impl.h>
|
#include <spdlog/details/line_logger_impl.h>
|
||||||
|
|
||||||
|
@ -1,92 +1,92 @@
|
|||||||
//
|
//
|
||||||
// Copyright(c) 2015 Gabi Melman.
|
// Copyright(c) 2015 Gabi Melman.
|
||||||
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||||
//
|
//
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#if defined(__ANDROID__)
|
#if defined(__ANDROID__)
|
||||||
|
|
||||||
#include <spdlog/sinks/base_sink.h>
|
#include <spdlog/sinks/base_sink.h>
|
||||||
#include <spdlog/details/null_mutex.h>
|
#include <spdlog/details/null_mutex.h>
|
||||||
|
|
||||||
#include <android/log.h>
|
#include <android/log.h>
|
||||||
|
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
namespace spdlog
|
namespace spdlog
|
||||||
{
|
{
|
||||||
namespace sinks
|
namespace sinks
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* Android sink (logging using __android_log_write)
|
* Android sink (logging using __android_log_write)
|
||||||
*/
|
*/
|
||||||
template<class Mutex>
|
template<class Mutex>
|
||||||
class base_android_sink : public base_sink < Mutex >
|
class base_android_sink : public base_sink < Mutex >
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit base_android_sink(std::string tag="spdlog"): _tag(tag)
|
explicit base_android_sink(std::string tag="spdlog"): _tag(tag)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void flush() override
|
void flush() override
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void _sink_it(const details::log_msg& msg) override
|
void _sink_it(const details::log_msg& msg) override
|
||||||
{
|
{
|
||||||
const android_LogPriority priority = convert_to_android(msg.level);
|
const android_LogPriority priority = convert_to_android(msg.level);
|
||||||
const int expected_size = msg.formatted.size();
|
const int expected_size = msg.formatted.size();
|
||||||
const int size = __android_log_write(
|
const int size = __android_log_write(
|
||||||
priority, _tag.c_str(), msg.formatted.c_str()
|
priority, _tag.c_str(), msg.formatted.c_str()
|
||||||
);
|
);
|
||||||
if (size > expected_size)
|
if (size > expected_size)
|
||||||
{
|
{
|
||||||
// Will write a little bit more than original message
|
// Will write a little bit more than original message
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
throw spdlog_ex("Send to Android logcat failed");
|
throw spdlog_ex("Send to Android logcat failed");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static android_LogPriority convert_to_android(spdlog::level::level_enum level)
|
static android_LogPriority convert_to_android(spdlog::level::level_enum level)
|
||||||
{
|
{
|
||||||
switch(level)
|
switch(level)
|
||||||
{
|
{
|
||||||
case spdlog::level::trace:
|
case spdlog::level::trace:
|
||||||
return ANDROID_LOG_VERBOSE;
|
return ANDROID_LOG_VERBOSE;
|
||||||
case spdlog::level::debug:
|
case spdlog::level::debug:
|
||||||
return ANDROID_LOG_DEBUG;
|
return ANDROID_LOG_DEBUG;
|
||||||
case spdlog::level::info:
|
case spdlog::level::info:
|
||||||
return ANDROID_LOG_INFO;
|
return ANDROID_LOG_INFO;
|
||||||
case spdlog::level::notice:
|
case spdlog::level::notice:
|
||||||
return ANDROID_LOG_INFO;
|
return ANDROID_LOG_INFO;
|
||||||
case spdlog::level::warn:
|
case spdlog::level::warn:
|
||||||
return ANDROID_LOG_WARN;
|
return ANDROID_LOG_WARN;
|
||||||
case spdlog::level::err:
|
case spdlog::level::err:
|
||||||
return ANDROID_LOG_ERROR;
|
return ANDROID_LOG_ERROR;
|
||||||
case spdlog::level::critical:
|
case spdlog::level::critical:
|
||||||
return ANDROID_LOG_FATAL;
|
return ANDROID_LOG_FATAL;
|
||||||
case spdlog::level::alert:
|
case spdlog::level::alert:
|
||||||
return ANDROID_LOG_FATAL;
|
return ANDROID_LOG_FATAL;
|
||||||
case spdlog::level::emerg:
|
case spdlog::level::emerg:
|
||||||
return ANDROID_LOG_FATAL;
|
return ANDROID_LOG_FATAL;
|
||||||
default:
|
default:
|
||||||
throw spdlog_ex("Incorrect level value");
|
throw spdlog_ex("Incorrect level value");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string _tag;
|
std::string _tag;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef base_android_sink<std::mutex> android_sink_mt;
|
typedef base_android_sink<std::mutex> android_sink_mt;
|
||||||
typedef base_android_sink<details::null_mutex> android_sink_st;
|
typedef base_android_sink<details::null_mutex> android_sink_st;
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -1,112 +1,115 @@
|
|||||||
//
|
//
|
||||||
// Copyright(c) 2016 Kevin M. Godby (a modified version by spdlog).
|
// Copyright(c) 2016 Kevin M. Godby (a modified version by spdlog).
|
||||||
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||||
//
|
//
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <spdlog/sinks/base_sink.h>
|
#include <spdlog/sinks/base_sink.h>
|
||||||
#include <spdlog/common.h>
|
#include <spdlog/common.h>
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <map>
|
#include <map>
|
||||||
|
|
||||||
namespace spdlog {
|
namespace spdlog
|
||||||
namespace sinks {
|
{
|
||||||
|
namespace sinks
|
||||||
/**
|
{
|
||||||
* @brief The ansi_color_sink is a decorator around another sink and prefixes
|
|
||||||
* the output with an ANSI escape sequence color code depending on the severity
|
/**
|
||||||
* of the message.
|
* @brief The ansi_color_sink is a decorator around another sink and prefixes
|
||||||
*/
|
* the output with an ANSI escape sequence color code depending on the severity
|
||||||
class ansicolor_sink : public sink {
|
* of the message.
|
||||||
public:
|
*/
|
||||||
ansicolor_sink(sink_ptr wrapped_sink);
|
class ansicolor_sink : public sink
|
||||||
virtual ~ansicolor_sink();
|
{
|
||||||
|
public:
|
||||||
ansicolor_sink(const ansicolor_sink& other) = delete;
|
ansicolor_sink(sink_ptr wrapped_sink);
|
||||||
ansicolor_sink& operator=(const ansicolor_sink& other) = delete;
|
virtual ~ansicolor_sink();
|
||||||
|
|
||||||
virtual void log(const details::log_msg& msg) override;
|
ansicolor_sink(const ansicolor_sink& other) = delete;
|
||||||
virtual void flush() override;
|
ansicolor_sink& operator=(const ansicolor_sink& other) = delete;
|
||||||
|
|
||||||
void set_color(level::level_enum level, const std::string& color);
|
virtual void log(const details::log_msg& msg) override;
|
||||||
|
virtual void flush() override;
|
||||||
/// Formatting codes
|
|
||||||
const std::string reset = "\033[00m";
|
void set_color(level::level_enum level, const std::string& color);
|
||||||
const std::string bold = "\033[1m";
|
|
||||||
const std::string dark = "\033[2m";
|
/// Formatting codes
|
||||||
const std::string underline = "\033[4m";
|
const std::string reset = "\033[00m";
|
||||||
const std::string blink = "\033[5m";
|
const std::string bold = "\033[1m";
|
||||||
const std::string reverse = "\033[7m";
|
const std::string dark = "\033[2m";
|
||||||
const std::string concealed = "\033[8m";
|
const std::string underline = "\033[4m";
|
||||||
|
const std::string blink = "\033[5m";
|
||||||
// Foreground colors
|
const std::string reverse = "\033[7m";
|
||||||
const std::string grey = "\033[30m";
|
const std::string concealed = "\033[8m";
|
||||||
const std::string red = "\033[31m";
|
|
||||||
const std::string green = "\033[32m";
|
// Foreground colors
|
||||||
const std::string yellow = "\033[33m";
|
const std::string grey = "\033[30m";
|
||||||
const std::string blue = "\033[34m";
|
const std::string red = "\033[31m";
|
||||||
const std::string magenta = "\033[35m";
|
const std::string green = "\033[32m";
|
||||||
const std::string cyan = "\033[36m";
|
const std::string yellow = "\033[33m";
|
||||||
const std::string white = "\033[37m";
|
const std::string blue = "\033[34m";
|
||||||
|
const std::string magenta = "\033[35m";
|
||||||
/// Background colors
|
const std::string cyan = "\033[36m";
|
||||||
const std::string on_grey = "\033[40m";
|
const std::string white = "\033[37m";
|
||||||
const std::string on_red = "\033[41m";
|
|
||||||
const std::string on_green = "\033[42m";
|
/// Background colors
|
||||||
const std::string on_yellow = "\033[43m";
|
const std::string on_grey = "\033[40m";
|
||||||
const std::string on_blue = "\033[44m";
|
const std::string on_red = "\033[41m";
|
||||||
const std::string on_magenta = "\033[45m";
|
const std::string on_green = "\033[42m";
|
||||||
const std::string on_cyan = "\033[46m";
|
const std::string on_yellow = "\033[43m";
|
||||||
const std::string on_white = "\033[47m";
|
const std::string on_blue = "\033[44m";
|
||||||
|
const std::string on_magenta = "\033[45m";
|
||||||
|
const std::string on_cyan = "\033[46m";
|
||||||
protected:
|
const std::string on_white = "\033[47m";
|
||||||
sink_ptr sink_;
|
|
||||||
std::map<level::level_enum, std::string> colors_;
|
|
||||||
};
|
protected:
|
||||||
|
sink_ptr sink_;
|
||||||
inline ansicolor_sink::ansicolor_sink(sink_ptr wrapped_sink) : sink_(wrapped_sink)
|
std::map<level::level_enum, std::string> colors_;
|
||||||
{
|
};
|
||||||
colors_[level::trace] = cyan;
|
|
||||||
colors_[level::debug] = cyan;
|
inline ansicolor_sink::ansicolor_sink(sink_ptr wrapped_sink) : sink_(wrapped_sink)
|
||||||
colors_[level::info] = white;
|
{
|
||||||
colors_[level::notice] = bold + white;
|
colors_[level::trace] = cyan;
|
||||||
colors_[level::warn] = bold + yellow;
|
colors_[level::debug] = cyan;
|
||||||
colors_[level::err] = red;
|
colors_[level::info] = white;
|
||||||
colors_[level::critical] = bold + red;
|
colors_[level::notice] = bold + white;
|
||||||
colors_[level::alert] = bold + white + on_red;
|
colors_[level::warn] = bold + yellow;
|
||||||
colors_[level::emerg] = bold + yellow + on_red;
|
colors_[level::err] = red;
|
||||||
colors_[level::off] = reset;
|
colors_[level::critical] = bold + red;
|
||||||
}
|
colors_[level::alert] = bold + white + on_red;
|
||||||
|
colors_[level::emerg] = bold + yellow + on_red;
|
||||||
inline void ansicolor_sink::log(const details::log_msg& msg)
|
colors_[level::off] = reset;
|
||||||
{
|
}
|
||||||
// Wrap the originally formatted message in color codes
|
|
||||||
const std::string& prefix = colors_[msg.level];
|
inline void ansicolor_sink::log(const details::log_msg& msg)
|
||||||
const std::string& s = msg.formatted.str();
|
{
|
||||||
const std::string& suffix = reset;
|
// Wrap the originally formatted message in color codes
|
||||||
details::log_msg m;
|
const std::string& prefix = colors_[msg.level];
|
||||||
m.formatted << prefix << s << suffix;
|
const std::string& s = msg.formatted.str();
|
||||||
sink_->log(m);
|
const std::string& suffix = reset;
|
||||||
}
|
details::log_msg m;
|
||||||
|
m.formatted << prefix << s << suffix;
|
||||||
inline void ansicolor_sink::flush()
|
sink_->log(m);
|
||||||
{
|
}
|
||||||
sink_->flush();
|
|
||||||
}
|
inline void ansicolor_sink::flush()
|
||||||
|
{
|
||||||
inline void ansicolor_sink::set_color(level::level_enum level, const std::string& color)
|
sink_->flush();
|
||||||
{
|
}
|
||||||
colors_[level] = color;
|
|
||||||
}
|
inline void ansicolor_sink::set_color(level::level_enum level, const std::string& color)
|
||||||
|
{
|
||||||
inline ansicolor_sink::~ansicolor_sink()
|
colors_[level] = color;
|
||||||
{
|
}
|
||||||
flush();
|
|
||||||
}
|
inline ansicolor_sink::~ansicolor_sink()
|
||||||
|
{
|
||||||
} // namespace sinks
|
flush();
|
||||||
} // namespace spdlog
|
}
|
||||||
|
|
||||||
|
} // namespace sinks
|
||||||
|
} // namespace spdlog
|
||||||
|
|
||||||
|
@ -1,45 +1,45 @@
|
|||||||
//
|
//
|
||||||
// Copyright(c) 2015 Gabi Melman.
|
// Copyright(c) 2015 Gabi Melman.
|
||||||
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||||
//
|
//
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
//
|
//
|
||||||
// base sink templated over a mutex (either dummy or realy)
|
// base sink templated over a mutex (either dummy or realy)
|
||||||
// concrete implementation should only overrid the _sink_it method.
|
// concrete implementation should only overrid the _sink_it method.
|
||||||
// all locking is taken care of here so no locking needed by the implementors..
|
// all locking is taken care of here so no locking needed by the implementors..
|
||||||
//
|
//
|
||||||
|
|
||||||
#include <spdlog/sinks/sink.h>
|
#include <spdlog/sinks/sink.h>
|
||||||
#include <spdlog/formatter.h>
|
#include <spdlog/formatter.h>
|
||||||
#include <spdlog/common.h>
|
#include <spdlog/common.h>
|
||||||
#include <spdlog/details/log_msg.h>
|
#include <spdlog/details/log_msg.h>
|
||||||
|
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
|
|
||||||
namespace spdlog
|
namespace spdlog
|
||||||
{
|
{
|
||||||
namespace sinks
|
namespace sinks
|
||||||
{
|
{
|
||||||
template<class Mutex>
|
template<class Mutex>
|
||||||
class base_sink:public sink
|
class base_sink:public sink
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
base_sink():_mutex() {}
|
base_sink():_mutex() {}
|
||||||
virtual ~base_sink() = default;
|
virtual ~base_sink() = default;
|
||||||
|
|
||||||
base_sink(const base_sink&) = delete;
|
base_sink(const base_sink&) = delete;
|
||||||
base_sink& operator=(const base_sink&) = delete;
|
base_sink& operator=(const base_sink&) = delete;
|
||||||
|
|
||||||
void log(const details::log_msg& msg) override
|
void log(const details::log_msg& msg) override
|
||||||
{
|
{
|
||||||
std::lock_guard<Mutex> lock(_mutex);
|
std::lock_guard<Mutex> lock(_mutex);
|
||||||
_sink_it(msg);
|
_sink_it(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual void _sink_it(const details::log_msg& msg) = 0;
|
virtual void _sink_it(const details::log_msg& msg) = 0;
|
||||||
Mutex _mutex;
|
Mutex _mutex;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,72 +1,72 @@
|
|||||||
//
|
//
|
||||||
// Copyright (c) 2015 David Schury, Gabi Melman
|
// Copyright (c) 2015 David Schury, Gabi Melman
|
||||||
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||||
//
|
//
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#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/sinks/base_sink.h>
|
#include <spdlog/sinks/base_sink.h>
|
||||||
#include <spdlog/sinks/sink.h>
|
#include <spdlog/sinks/sink.h>
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
namespace spdlog
|
namespace spdlog
|
||||||
{
|
{
|
||||||
namespace sinks
|
namespace sinks
|
||||||
{
|
{
|
||||||
template<class Mutex>
|
template<class Mutex>
|
||||||
class dist_sink: public base_sink<Mutex>
|
class dist_sink: public base_sink<Mutex>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit dist_sink() :_sinks() {}
|
explicit dist_sink() :_sinks() {}
|
||||||
dist_sink(const dist_sink&) = delete;
|
dist_sink(const dist_sink&) = delete;
|
||||||
dist_sink& operator=(const dist_sink&) = delete;
|
dist_sink& operator=(const dist_sink&) = delete;
|
||||||
virtual ~dist_sink() = default;
|
virtual ~dist_sink() = default;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void _sink_it(const details::log_msg& msg) override
|
void _sink_it(const details::log_msg& msg) override
|
||||||
{
|
{
|
||||||
for (auto iter = _sinks.begin(); iter != _sinks.end(); iter++)
|
for (auto iter = _sinks.begin(); iter != _sinks.end(); iter++)
|
||||||
(*iter)->log(msg);
|
(*iter)->log(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::shared_ptr<sink>> _sinks;
|
std::vector<std::shared_ptr<sink>> _sinks;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void flush() override
|
void flush() override
|
||||||
{
|
{
|
||||||
std::lock_guard<Mutex> lock(base_sink<Mutex>::_mutex);
|
std::lock_guard<Mutex> lock(base_sink<Mutex>::_mutex);
|
||||||
for (auto iter = _sinks.begin(); iter != _sinks.end(); iter++)
|
for (auto iter = _sinks.begin(); iter != _sinks.end(); iter++)
|
||||||
(*iter)->flush();
|
(*iter)->flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
void add_sink(std::shared_ptr<sink> sink)
|
void add_sink(std::shared_ptr<sink> sink)
|
||||||
{
|
{
|
||||||
std::lock_guard<Mutex> lock(base_sink<Mutex>::_mutex);
|
std::lock_guard<Mutex> lock(base_sink<Mutex>::_mutex);
|
||||||
if (sink &&
|
if (sink &&
|
||||||
_sinks.end() == std::find(_sinks.begin(), _sinks.end(), sink))
|
_sinks.end() == std::find(_sinks.begin(), _sinks.end(), sink))
|
||||||
{
|
{
|
||||||
_sinks.push_back(sink);
|
_sinks.push_back(sink);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void remove_sink(std::shared_ptr<sink> sink)
|
void remove_sink(std::shared_ptr<sink> sink)
|
||||||
{
|
{
|
||||||
std::lock_guard<Mutex> lock(base_sink<Mutex>::_mutex);
|
std::lock_guard<Mutex> lock(base_sink<Mutex>::_mutex);
|
||||||
auto pos = std::find(_sinks.begin(), _sinks.end(), sink);
|
auto pos = std::find(_sinks.begin(), _sinks.end(), sink);
|
||||||
if (pos != _sinks.end())
|
if (pos != _sinks.end())
|
||||||
{
|
{
|
||||||
_sinks.erase(pos);
|
_sinks.erase(pos);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef dist_sink<std::mutex> dist_sink_mt;
|
typedef dist_sink<std::mutex> dist_sink_mt;
|
||||||
typedef dist_sink<details::null_mutex> dist_sink_st;
|
typedef dist_sink<details::null_mutex> dist_sink_st;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,220 +1,220 @@
|
|||||||
//
|
//
|
||||||
// Copyright(c) 2015 Gabi Melman.
|
// Copyright(c) 2015 Gabi Melman.
|
||||||
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||||
//
|
//
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <spdlog/sinks/base_sink.h>
|
#include <spdlog/sinks/base_sink.h>
|
||||||
#include <spdlog/details/null_mutex.h>
|
#include <spdlog/details/null_mutex.h>
|
||||||
#include <spdlog/details/file_helper.h>
|
#include <spdlog/details/file_helper.h>
|
||||||
#include <spdlog/details/format.h>
|
#include <spdlog/details/format.h>
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <ctime>
|
#include <ctime>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
namespace spdlog
|
namespace spdlog
|
||||||
{
|
{
|
||||||
namespace sinks
|
namespace sinks
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* Trivial file sink with single file as target
|
* Trivial file sink with single file as target
|
||||||
*/
|
*/
|
||||||
template<class Mutex>
|
template<class Mutex>
|
||||||
class simple_file_sink : public base_sink < Mutex >
|
class simple_file_sink : public base_sink < Mutex >
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit simple_file_sink(const std::string &filename,
|
explicit simple_file_sink(const std::string &filename,
|
||||||
bool force_flush = false) :
|
bool force_flush = false) :
|
||||||
_file_helper(force_flush)
|
_file_helper(force_flush)
|
||||||
{
|
{
|
||||||
_file_helper.open(filename);
|
_file_helper.open(filename);
|
||||||
}
|
}
|
||||||
void flush() override
|
void flush() override
|
||||||
{
|
{
|
||||||
_file_helper.flush();
|
_file_helper.flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void _sink_it(const details::log_msg& msg) override
|
void _sink_it(const details::log_msg& msg) override
|
||||||
{
|
{
|
||||||
_file_helper.write(msg);
|
_file_helper.write(msg);
|
||||||
}
|
}
|
||||||
private:
|
private:
|
||||||
details::file_helper _file_helper;
|
details::file_helper _file_helper;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef simple_file_sink<std::mutex> simple_file_sink_mt;
|
typedef simple_file_sink<std::mutex> simple_file_sink_mt;
|
||||||
typedef simple_file_sink<details::null_mutex> simple_file_sink_st;
|
typedef simple_file_sink<details::null_mutex> simple_file_sink_st;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Rotating file sink based on size
|
* Rotating file sink based on size
|
||||||
*/
|
*/
|
||||||
template<class Mutex>
|
template<class Mutex>
|
||||||
class rotating_file_sink : public base_sink < Mutex >
|
class rotating_file_sink : public base_sink < Mutex >
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
rotating_file_sink(const std::string &base_filename, const std::string &extension,
|
rotating_file_sink(const std::string &base_filename, const std::string &extension,
|
||||||
std::size_t max_size, std::size_t max_files,
|
std::size_t max_size, std::size_t max_files,
|
||||||
bool force_flush = false) :
|
bool force_flush = false) :
|
||||||
_base_filename(base_filename),
|
_base_filename(base_filename),
|
||||||
_extension(extension),
|
_extension(extension),
|
||||||
_max_size(max_size),
|
_max_size(max_size),
|
||||||
_max_files(max_files),
|
_max_files(max_files),
|
||||||
_current_size(0),
|
_current_size(0),
|
||||||
_file_helper(force_flush)
|
_file_helper(force_flush)
|
||||||
{
|
{
|
||||||
_file_helper.open(calc_filename(_base_filename, 0, _extension));
|
_file_helper.open(calc_filename(_base_filename, 0, _extension));
|
||||||
_current_size = _file_helper.size(); //expensive. called only once
|
_current_size = _file_helper.size(); //expensive. called only once
|
||||||
}
|
}
|
||||||
|
|
||||||
void flush() override
|
void flush() override
|
||||||
{
|
{
|
||||||
_file_helper.flush();
|
_file_helper.flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void _sink_it(const details::log_msg& msg) override
|
void _sink_it(const details::log_msg& msg) override
|
||||||
{
|
{
|
||||||
_current_size += msg.formatted.size();
|
_current_size += msg.formatted.size();
|
||||||
if (_current_size > _max_size)
|
if (_current_size > _max_size)
|
||||||
{
|
{
|
||||||
_rotate();
|
_rotate();
|
||||||
_current_size = msg.formatted.size();
|
_current_size = msg.formatted.size();
|
||||||
}
|
}
|
||||||
_file_helper.write(msg);
|
_file_helper.write(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static std::string calc_filename(const std::string& filename, std::size_t index, const std::string& extension)
|
static std::string calc_filename(const std::string& filename, std::size_t index, const std::string& extension)
|
||||||
{
|
{
|
||||||
fmt::MemoryWriter w;
|
fmt::MemoryWriter w;
|
||||||
if (index)
|
if (index)
|
||||||
w.write("{}.{}.{}", filename, index, extension);
|
w.write("{}.{}.{}", filename, index, extension);
|
||||||
else
|
else
|
||||||
w.write("{}.{}", filename, extension);
|
w.write("{}.{}", filename, extension);
|
||||||
return w.str();
|
return w.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Rotate files:
|
// Rotate files:
|
||||||
// log.txt -> log.1.txt
|
// log.txt -> log.1.txt
|
||||||
// log.1.txt -> log2.txt
|
// log.1.txt -> log2.txt
|
||||||
// log.2.txt -> log3.txt
|
// log.2.txt -> log3.txt
|
||||||
// log.3.txt -> delete
|
// log.3.txt -> delete
|
||||||
|
|
||||||
void _rotate()
|
void _rotate()
|
||||||
{
|
{
|
||||||
_file_helper.close();
|
_file_helper.close();
|
||||||
for (auto i = _max_files; i > 0; --i)
|
for (auto i = _max_files; i > 0; --i)
|
||||||
{
|
{
|
||||||
std::string src = calc_filename(_base_filename, i - 1, _extension);
|
std::string src = calc_filename(_base_filename, i - 1, _extension);
|
||||||
std::string target = calc_filename(_base_filename, i, _extension);
|
std::string target = calc_filename(_base_filename, i, _extension);
|
||||||
|
|
||||||
if (details::file_helper::file_exists(target))
|
if (details::file_helper::file_exists(target))
|
||||||
{
|
{
|
||||||
if (std::remove(target.c_str()) != 0)
|
if (std::remove(target.c_str()) != 0)
|
||||||
{
|
{
|
||||||
throw spdlog_ex("rotating_file_sink: failed removing " + target);
|
throw spdlog_ex("rotating_file_sink: failed removing " + target);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (details::file_helper::file_exists(src) && std::rename(src.c_str(), target.c_str()))
|
if (details::file_helper::file_exists(src) && std::rename(src.c_str(), target.c_str()))
|
||||||
{
|
{
|
||||||
throw spdlog_ex("rotating_file_sink: failed renaming " + src + " to " + target);
|
throw spdlog_ex("rotating_file_sink: failed renaming " + src + " to " + target);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_file_helper.reopen(true);
|
_file_helper.reopen(true);
|
||||||
}
|
}
|
||||||
std::string _base_filename;
|
std::string _base_filename;
|
||||||
std::string _extension;
|
std::string _extension;
|
||||||
std::size_t _max_size;
|
std::size_t _max_size;
|
||||||
std::size_t _max_files;
|
std::size_t _max_files;
|
||||||
std::size_t _current_size;
|
std::size_t _current_size;
|
||||||
details::file_helper _file_helper;
|
details::file_helper _file_helper;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef rotating_file_sink<std::mutex> rotating_file_sink_mt;
|
typedef rotating_file_sink<std::mutex> rotating_file_sink_mt;
|
||||||
typedef rotating_file_sink<details::null_mutex>rotating_file_sink_st;
|
typedef rotating_file_sink<details::null_mutex>rotating_file_sink_st;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Rotating file sink based on date. rotates at midnight
|
* Rotating file sink based on date. rotates at midnight
|
||||||
*/
|
*/
|
||||||
template<class Mutex>
|
template<class Mutex>
|
||||||
class daily_file_sink :public base_sink < Mutex >
|
class daily_file_sink :public base_sink < Mutex >
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
//create daily file sink which rotates on given time
|
//create daily file sink which rotates on given time
|
||||||
daily_file_sink(
|
daily_file_sink(
|
||||||
const std::string& base_filename,
|
const std::string& base_filename,
|
||||||
const std::string& extension,
|
const std::string& extension,
|
||||||
int rotation_hour,
|
int rotation_hour,
|
||||||
int rotation_minute,
|
int rotation_minute,
|
||||||
bool force_flush = false) : _base_filename(base_filename),
|
bool force_flush = false) : _base_filename(base_filename),
|
||||||
_extension(extension),
|
_extension(extension),
|
||||||
_rotation_h(rotation_hour),
|
_rotation_h(rotation_hour),
|
||||||
_rotation_m(rotation_minute),
|
_rotation_m(rotation_minute),
|
||||||
_file_helper(force_flush)
|
_file_helper(force_flush)
|
||||||
{
|
{
|
||||||
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)
|
||||||
throw spdlog_ex("daily_file_sink: Invalid rotation time in ctor");
|
throw spdlog_ex("daily_file_sink: Invalid rotation time in ctor");
|
||||||
_rotation_tp = _next_rotation_tp();
|
_rotation_tp = _next_rotation_tp();
|
||||||
_file_helper.open(calc_filename(_base_filename, _extension));
|
_file_helper.open(calc_filename(_base_filename, _extension));
|
||||||
}
|
}
|
||||||
|
|
||||||
void flush() override
|
void flush() override
|
||||||
{
|
{
|
||||||
_file_helper.flush();
|
_file_helper.flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void _sink_it(const details::log_msg& msg) override
|
void _sink_it(const details::log_msg& msg) override
|
||||||
{
|
{
|
||||||
if (std::chrono::system_clock::now() >= _rotation_tp)
|
if (std::chrono::system_clock::now() >= _rotation_tp)
|
||||||
{
|
{
|
||||||
_file_helper.open(calc_filename(_base_filename, _extension));
|
_file_helper.open(calc_filename(_base_filename, _extension));
|
||||||
_rotation_tp = _next_rotation_tp();
|
_rotation_tp = _next_rotation_tp();
|
||||||
}
|
}
|
||||||
_file_helper.write(msg);
|
_file_helper.write(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::chrono::system_clock::time_point _next_rotation_tp()
|
std::chrono::system_clock::time_point _next_rotation_tp()
|
||||||
{
|
{
|
||||||
using namespace std::chrono;
|
using namespace std::chrono;
|
||||||
auto now = system_clock::now();
|
auto now = system_clock::now();
|
||||||
time_t tnow = std::chrono::system_clock::to_time_t(now);
|
time_t tnow = std::chrono::system_clock::to_time_t(now);
|
||||||
tm date = spdlog::details::os::localtime(tnow);
|
tm date = spdlog::details::os::localtime(tnow);
|
||||||
date.tm_hour = _rotation_h;
|
date.tm_hour = _rotation_h;
|
||||||
date.tm_min = _rotation_m;
|
date.tm_min = _rotation_m;
|
||||||
date.tm_sec = 0;
|
date.tm_sec = 0;
|
||||||
auto rotation_time = std::chrono::system_clock::from_time_t(std::mktime(&date));
|
auto rotation_time = std::chrono::system_clock::from_time_t(std::mktime(&date));
|
||||||
if (rotation_time > now)
|
if (rotation_time > now)
|
||||||
return rotation_time;
|
return rotation_time;
|
||||||
else
|
else
|
||||||
return system_clock::time_point(rotation_time + hours(24));
|
return system_clock::time_point(rotation_time + hours(24));
|
||||||
}
|
}
|
||||||
|
|
||||||
//Create filename for the form basename.YYYY-MM-DD.extension
|
//Create filename for the form basename.YYYY-MM-DD.extension
|
||||||
static std::string calc_filename(const std::string& basename, const std::string& extension)
|
static std::string calc_filename(const std::string& basename, const std::string& extension)
|
||||||
{
|
{
|
||||||
std::tm tm = spdlog::details::os::localtime();
|
std::tm tm = spdlog::details::os::localtime();
|
||||||
fmt::MemoryWriter w;
|
fmt::MemoryWriter w;
|
||||||
w.write("{}_{:04d}-{:02d}-{:02d}_{:02d}-{:02d}.{}", basename, tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, extension);
|
w.write("{}_{:04d}-{:02d}-{:02d}_{:02d}-{:02d}.{}", basename, tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, extension);
|
||||||
return w.str();
|
return w.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string _base_filename;
|
std::string _base_filename;
|
||||||
std::string _extension;
|
std::string _extension;
|
||||||
int _rotation_h;
|
int _rotation_h;
|
||||||
int _rotation_m;
|
int _rotation_m;
|
||||||
std::chrono::system_clock::time_point _rotation_tp;
|
std::chrono::system_clock::time_point _rotation_tp;
|
||||||
details::file_helper _file_helper;
|
details::file_helper _file_helper;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef daily_file_sink<std::mutex> daily_file_sink_mt;
|
typedef daily_file_sink<std::mutex> daily_file_sink_mt;
|
||||||
typedef daily_file_sink<details::null_mutex> daily_file_sink_st;
|
typedef daily_file_sink<details::null_mutex> daily_file_sink_st;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,50 +1,50 @@
|
|||||||
//
|
//
|
||||||
// Copyright(c) 2016 Alexander Dalshov.
|
// Copyright(c) 2016 Alexander Dalshov.
|
||||||
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||||
//
|
//
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#if defined(_MSC_VER)
|
#if defined(_MSC_VER)
|
||||||
|
|
||||||
#include <spdlog/sinks/base_sink.h>
|
#include <spdlog/sinks/base_sink.h>
|
||||||
#include <spdlog/details/null_mutex.h>
|
#include <spdlog/details/null_mutex.h>
|
||||||
|
|
||||||
#include <WinBase.h>
|
#include <WinBase.h>
|
||||||
|
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
namespace spdlog
|
namespace spdlog
|
||||||
{
|
{
|
||||||
namespace sinks
|
namespace sinks
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* MSVC sink (logging using OutputDebugStringA)
|
* MSVC sink (logging using OutputDebugStringA)
|
||||||
*/
|
*/
|
||||||
template<class Mutex>
|
template<class Mutex>
|
||||||
class msvc_sink : public base_sink < Mutex >
|
class msvc_sink : public base_sink < Mutex >
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit msvc_sink()
|
explicit msvc_sink()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void flush() override
|
void flush() override
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void _sink_it(const details::log_msg& msg) override
|
void _sink_it(const details::log_msg& msg) override
|
||||||
{
|
{
|
||||||
OutputDebugStringA(msg.formatted.c_str());
|
OutputDebugStringA(msg.formatted.c_str());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef msvc_sink<std::mutex> msvc_sink_mt;
|
typedef msvc_sink<std::mutex> msvc_sink_mt;
|
||||||
typedef msvc_sink<details::null_mutex> msvc_sink_st;
|
typedef msvc_sink<details::null_mutex> msvc_sink_st;
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -1,34 +1,34 @@
|
|||||||
//
|
//
|
||||||
// Copyright(c) 2015 Gabi Melman.
|
// Copyright(c) 2015 Gabi Melman.
|
||||||
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||||
//
|
//
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <spdlog/sinks/base_sink.h>
|
#include <spdlog/sinks/base_sink.h>
|
||||||
#include <spdlog/details/null_mutex.h>
|
#include <spdlog/details/null_mutex.h>
|
||||||
|
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
|
|
||||||
namespace spdlog
|
namespace spdlog
|
||||||
{
|
{
|
||||||
namespace sinks
|
namespace sinks
|
||||||
{
|
{
|
||||||
|
|
||||||
template <class Mutex>
|
template <class Mutex>
|
||||||
class null_sink : public base_sink < Mutex >
|
class null_sink : public base_sink < Mutex >
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
void _sink_it(const details::log_msg&) override
|
void _sink_it(const details::log_msg&) override
|
||||||
{}
|
{}
|
||||||
|
|
||||||
void flush() override
|
void flush() override
|
||||||
{}
|
{}
|
||||||
|
|
||||||
};
|
};
|
||||||
typedef null_sink<details::null_mutex> null_sink_st;
|
typedef null_sink<details::null_mutex> null_sink_st;
|
||||||
typedef null_sink<std::mutex> null_sink_mt;
|
typedef null_sink<std::mutex> null_sink_mt;
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,47 +1,47 @@
|
|||||||
//
|
//
|
||||||
// Copyright(c) 2015 Gabi Melman.
|
// Copyright(c) 2015 Gabi Melman.
|
||||||
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||||
//
|
//
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#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 <ostream>
|
#include <ostream>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
|
|
||||||
namespace spdlog
|
namespace spdlog
|
||||||
{
|
{
|
||||||
namespace sinks
|
namespace sinks
|
||||||
{
|
{
|
||||||
template<class Mutex>
|
template<class Mutex>
|
||||||
class ostream_sink: public base_sink<Mutex>
|
class ostream_sink: public base_sink<Mutex>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit ostream_sink(std::ostream& os, bool force_flush=false) :_ostream(os), _force_flush(force_flush) {}
|
explicit ostream_sink(std::ostream& os, bool force_flush=false) :_ostream(os), _force_flush(force_flush) {}
|
||||||
ostream_sink(const ostream_sink&) = delete;
|
ostream_sink(const ostream_sink&) = delete;
|
||||||
ostream_sink& operator=(const ostream_sink&) = delete;
|
ostream_sink& operator=(const ostream_sink&) = delete;
|
||||||
virtual ~ostream_sink() = default;
|
virtual ~ostream_sink() = default;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void _sink_it(const details::log_msg& msg) override
|
void _sink_it(const details::log_msg& msg) override
|
||||||
{
|
{
|
||||||
_ostream.write(msg.formatted.data(), msg.formatted.size());
|
_ostream.write(msg.formatted.data(), msg.formatted.size());
|
||||||
if (_force_flush)
|
if (_force_flush)
|
||||||
_ostream.flush();
|
_ostream.flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
void flush() override
|
void flush() override
|
||||||
{
|
{
|
||||||
_ostream.flush();
|
_ostream.flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::ostream& _ostream;
|
std::ostream& _ostream;
|
||||||
bool _force_flush;
|
bool _force_flush;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef ostream_sink<std::mutex> ostream_sink_mt;
|
typedef ostream_sink<std::mutex> ostream_sink_mt;
|
||||||
typedef ostream_sink<details::null_mutex> ostream_sink_st;
|
typedef ostream_sink<details::null_mutex> ostream_sink_st;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,24 +1,24 @@
|
|||||||
//
|
//
|
||||||
// Copyright(c) 2015 Gabi Melman.
|
// Copyright(c) 2015 Gabi Melman.
|
||||||
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||||
//
|
//
|
||||||
|
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <spdlog/details/log_msg.h>
|
#include <spdlog/details/log_msg.h>
|
||||||
|
|
||||||
namespace spdlog
|
namespace spdlog
|
||||||
{
|
{
|
||||||
namespace sinks
|
namespace sinks
|
||||||
{
|
{
|
||||||
class sink
|
class sink
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
virtual ~sink() {}
|
virtual ~sink() {}
|
||||||
virtual void log(const details::log_msg& msg) = 0;
|
virtual void log(const details::log_msg& msg) = 0;
|
||||||
virtual void flush() = 0;
|
virtual void flush() = 0;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,54 +1,54 @@
|
|||||||
//
|
//
|
||||||
// Copyright(c) 2015 Gabi Melman.
|
// Copyright(c) 2015 Gabi Melman.
|
||||||
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||||
//
|
//
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <spdlog/sinks/ostream_sink.h>
|
#include <spdlog/sinks/ostream_sink.h>
|
||||||
#include <spdlog/details/null_mutex.h>
|
#include <spdlog/details/null_mutex.h>
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
|
|
||||||
namespace spdlog
|
namespace spdlog
|
||||||
{
|
{
|
||||||
namespace sinks
|
namespace sinks
|
||||||
{
|
{
|
||||||
|
|
||||||
template <class Mutex>
|
template <class Mutex>
|
||||||
class stdout_sink : public ostream_sink<Mutex>
|
class stdout_sink : public ostream_sink<Mutex>
|
||||||
{
|
{
|
||||||
using MyType = stdout_sink<Mutex>;
|
using MyType = stdout_sink<Mutex>;
|
||||||
public:
|
public:
|
||||||
stdout_sink() : ostream_sink<Mutex>(std::cout, true) {}
|
stdout_sink() : ostream_sink<Mutex>(std::cout, true) {}
|
||||||
static std::shared_ptr<MyType> instance()
|
static std::shared_ptr<MyType> instance()
|
||||||
{
|
{
|
||||||
static std::shared_ptr<MyType> instance = std::make_shared<MyType>();
|
static std::shared_ptr<MyType> instance = std::make_shared<MyType>();
|
||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef stdout_sink<details::null_mutex> stdout_sink_st;
|
typedef stdout_sink<details::null_mutex> stdout_sink_st;
|
||||||
typedef stdout_sink<std::mutex> stdout_sink_mt;
|
typedef stdout_sink<std::mutex> stdout_sink_mt;
|
||||||
|
|
||||||
|
|
||||||
template <class Mutex>
|
template <class Mutex>
|
||||||
class stderr_sink : public ostream_sink<Mutex>
|
class stderr_sink : public ostream_sink<Mutex>
|
||||||
{
|
{
|
||||||
using MyType = stderr_sink<Mutex>;
|
using MyType = stderr_sink<Mutex>;
|
||||||
public:
|
public:
|
||||||
stderr_sink() : ostream_sink<Mutex>(std::cerr, true) {}
|
stderr_sink() : ostream_sink<Mutex>(std::cerr, true) {}
|
||||||
static std::shared_ptr<MyType> instance()
|
static std::shared_ptr<MyType> instance()
|
||||||
{
|
{
|
||||||
static std::shared_ptr<MyType> instance = std::make_shared<MyType>();
|
static std::shared_ptr<MyType> instance = std::make_shared<MyType>();
|
||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef stderr_sink<std::mutex> stderr_sink_mt;
|
typedef stderr_sink<std::mutex> stderr_sink_mt;
|
||||||
typedef stderr_sink<details::null_mutex> stderr_sink_st;
|
typedef stderr_sink<details::null_mutex> stderr_sink_st;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,83 +1,83 @@
|
|||||||
//
|
//
|
||||||
// Copyright(c) 2015 Gabi Melman.
|
// Copyright(c) 2015 Gabi Melman.
|
||||||
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||||
//
|
//
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#if defined(__linux__) || defined(__APPLE__)
|
#if defined(__linux__) || defined(__APPLE__)
|
||||||
|
|
||||||
#include <spdlog/sinks/sink.h>
|
#include <spdlog/sinks/sink.h>
|
||||||
#include <spdlog/common.h>
|
#include <spdlog/common.h>
|
||||||
#include <spdlog/details/log_msg.h>
|
#include <spdlog/details/log_msg.h>
|
||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <syslog.h>
|
#include <syslog.h>
|
||||||
|
|
||||||
|
|
||||||
namespace spdlog
|
namespace spdlog
|
||||||
{
|
{
|
||||||
namespace sinks
|
namespace sinks
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Sink that write to syslog using the `syscall()` library call.
|
* Sink that write to syslog using the `syscall()` library call.
|
||||||
*
|
*
|
||||||
* Locking is not needed, as `syslog()` itself is thread-safe.
|
* Locking is not needed, as `syslog()` itself is thread-safe.
|
||||||
*/
|
*/
|
||||||
class syslog_sink : public sink
|
class syslog_sink : public sink
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
//
|
//
|
||||||
syslog_sink(const std::string& ident = "", int syslog_option=0, int syslog_facility=LOG_USER):
|
syslog_sink(const std::string& ident = "", int syslog_option=0, int syslog_facility=LOG_USER):
|
||||||
_ident(ident)
|
_ident(ident)
|
||||||
{
|
{
|
||||||
_priorities[static_cast<int>(level::trace)] = LOG_DEBUG;
|
_priorities[static_cast<int>(level::trace)] = LOG_DEBUG;
|
||||||
_priorities[static_cast<int>(level::debug)] = LOG_DEBUG;
|
_priorities[static_cast<int>(level::debug)] = LOG_DEBUG;
|
||||||
_priorities[static_cast<int>(level::info)] = LOG_INFO;
|
_priorities[static_cast<int>(level::info)] = LOG_INFO;
|
||||||
_priorities[static_cast<int>(level::notice)] = LOG_NOTICE;
|
_priorities[static_cast<int>(level::notice)] = LOG_NOTICE;
|
||||||
_priorities[static_cast<int>(level::warn)] = LOG_WARNING;
|
_priorities[static_cast<int>(level::warn)] = LOG_WARNING;
|
||||||
_priorities[static_cast<int>(level::err)] = LOG_ERR;
|
_priorities[static_cast<int>(level::err)] = LOG_ERR;
|
||||||
_priorities[static_cast<int>(level::critical)] = LOG_CRIT;
|
_priorities[static_cast<int>(level::critical)] = LOG_CRIT;
|
||||||
_priorities[static_cast<int>(level::alert)] = LOG_ALERT;
|
_priorities[static_cast<int>(level::alert)] = LOG_ALERT;
|
||||||
_priorities[static_cast<int>(level::emerg)] = LOG_EMERG;
|
_priorities[static_cast<int>(level::emerg)] = LOG_EMERG;
|
||||||
_priorities[static_cast<int>(level::off)] = LOG_INFO;
|
_priorities[static_cast<int>(level::off)] = LOG_INFO;
|
||||||
|
|
||||||
//set ident to be program name if empty
|
//set ident to be program name if empty
|
||||||
::openlog(_ident.empty()? nullptr:_ident.c_str(), syslog_option, syslog_facility);
|
::openlog(_ident.empty()? nullptr:_ident.c_str(), syslog_option, syslog_facility);
|
||||||
}
|
}
|
||||||
~syslog_sink()
|
~syslog_sink()
|
||||||
{
|
{
|
||||||
::closelog();
|
::closelog();
|
||||||
}
|
}
|
||||||
|
|
||||||
syslog_sink(const syslog_sink&) = delete;
|
syslog_sink(const syslog_sink&) = delete;
|
||||||
syslog_sink& operator=(const syslog_sink&) = delete;
|
syslog_sink& operator=(const syslog_sink&) = delete;
|
||||||
|
|
||||||
void log(const details::log_msg &msg) override
|
void log(const details::log_msg &msg) override
|
||||||
{
|
{
|
||||||
::syslog(syslog_prio_from_level(msg), "%s", msg.raw.str().c_str());
|
::syslog(syslog_prio_from_level(msg), "%s", msg.raw.str().c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
void flush() override
|
void flush() override
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::array<int, 10> _priorities;
|
std::array<int, 10> _priorities;
|
||||||
//must store the ident because the man says openlog might use the pointer as is and not a string copy
|
//must store the ident because the man says openlog might use the pointer as is and not a string copy
|
||||||
const std::string _ident;
|
const std::string _ident;
|
||||||
|
|
||||||
//
|
//
|
||||||
// Simply maps spdlog's log level to syslog priority level.
|
// Simply maps spdlog's log level to syslog priority level.
|
||||||
//
|
//
|
||||||
int syslog_prio_from_level(const details::log_msg &msg) const
|
int syslog_prio_from_level(const details::log_msg &msg) const
|
||||||
{
|
{
|
||||||
return _priorities[static_cast<int>(msg.level)];
|
return _priorities[static_cast<int>(msg.level)];
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -1,140 +1,140 @@
|
|||||||
//
|
//
|
||||||
// Copyright(c) 2015 Gabi Melman.
|
// Copyright(c) 2015 Gabi Melman.
|
||||||
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||||
//
|
//
|
||||||
|
|
||||||
// spdlog main header file.
|
// spdlog main header file.
|
||||||
// see example.cpp for usage example
|
// see example.cpp for usage example
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <spdlog/tweakme.h>
|
#include <spdlog/tweakme.h>
|
||||||
#include <spdlog/common.h>
|
#include <spdlog/common.h>
|
||||||
#include <spdlog/logger.h>
|
#include <spdlog/logger.h>
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
namespace spdlog
|
namespace spdlog
|
||||||
{
|
{
|
||||||
// Return an existing logger or nullptr if a logger with such name doesn't exist.
|
// Return an existing logger or nullptr if a logger with such name doesn't exist.
|
||||||
// Examples:
|
// Examples:
|
||||||
//
|
//
|
||||||
// spdlog::get("mylog")->info("Hello");
|
// spdlog::get("mylog")->info("Hello");
|
||||||
// auto logger = spdlog::get("mylog");
|
// auto logger = spdlog::get("mylog");
|
||||||
// logger.info("This is another message" , x, y, z);
|
// logger.info("This is another message" , x, y, z);
|
||||||
// logger.info() << "This is another message" << x << y << z;
|
// logger.info() << "This is another message" << x << y << z;
|
||||||
std::shared_ptr<logger> get(const std::string& name);
|
std::shared_ptr<logger> get(const std::string& name);
|
||||||
|
|
||||||
//
|
//
|
||||||
// Set global formatting
|
// Set global formatting
|
||||||
// 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(const std::string& format_string);
|
void set_pattern(const std::string& format_string);
|
||||||
void set_formatter(formatter_ptr f);
|
void set_formatter(formatter_ptr f);
|
||||||
|
|
||||||
//
|
//
|
||||||
// Set global logging level for
|
// Set global logging level for
|
||||||
//
|
//
|
||||||
void set_level(level::level_enum log_level);
|
void set_level(level::level_enum log_level);
|
||||||
|
|
||||||
//
|
//
|
||||||
// Turn on async mode (off by default) and set the queue size for each async_logger.
|
// Turn on async mode (off by default) and set the queue size for each async_logger.
|
||||||
// effective only for loggers created after this call.
|
// effective only for loggers created after this call.
|
||||||
// queue_size: size of queue (must be power of 2):
|
// queue_size: size of queue (must be power of 2):
|
||||||
// Each logger will pre-allocate a dedicated queue with queue_size entries upon construction.
|
// Each logger will pre-allocate a dedicated queue with queue_size entries upon construction.
|
||||||
//
|
//
|
||||||
// async_overflow_policy (optional, block_retry by default):
|
// async_overflow_policy (optional, block_retry by default):
|
||||||
// async_overflow_policy::block_retry - if queue is full, block until queue has room for the new log entry.
|
// async_overflow_policy::block_retry - if queue is full, block until queue has room for the new log entry.
|
||||||
// async_overflow_policy::discard_log_msg - never block and discard any new messages when queue overflows.
|
// async_overflow_policy::discard_log_msg - never block and discard any new messages when queue overflows.
|
||||||
//
|
//
|
||||||
// worker_warmup_cb (optional):
|
// worker_warmup_cb (optional):
|
||||||
// callback function that will be called in worker thread upon start (can be used to init stuff like thread affinity)
|
// callback function that will be called in worker thread upon start (can be used to init stuff like thread affinity)
|
||||||
//
|
//
|
||||||
void set_async_mode(size_t queue_size, const async_overflow_policy overflow_policy = async_overflow_policy::block_retry, const std::function<void()>& worker_warmup_cb = nullptr, const std::chrono::milliseconds& flush_interval_ms = std::chrono::milliseconds::zero());
|
void set_async_mode(size_t queue_size, const async_overflow_policy overflow_policy = async_overflow_policy::block_retry, const std::function<void()>& worker_warmup_cb = nullptr, const std::chrono::milliseconds& flush_interval_ms = std::chrono::milliseconds::zero());
|
||||||
|
|
||||||
// Turn off async mode
|
// Turn off async mode
|
||||||
void set_sync_mode();
|
void set_sync_mode();
|
||||||
|
|
||||||
//
|
//
|
||||||
// Create and register multi/single threaded rotating file logger
|
// Create and register multi/single threaded rotating file logger
|
||||||
//
|
//
|
||||||
std::shared_ptr<logger> rotating_logger_mt(const std::string& logger_name, const std::string& filenameB, size_t max_file_size, size_t max_files, bool force_flush = false);
|
std::shared_ptr<logger> rotating_logger_mt(const std::string& logger_name, const std::string& filenameB, size_t max_file_size, size_t max_files, bool force_flush = false);
|
||||||
std::shared_ptr<logger> rotating_logger_st(const std::string& logger_name, const std::string& filename, size_t max_file_size, size_t max_files, bool force_flush = false);
|
std::shared_ptr<logger> rotating_logger_st(const std::string& logger_name, const std::string& filename, size_t max_file_size, size_t max_files, bool force_flush = false);
|
||||||
|
|
||||||
//
|
//
|
||||||
// Create file logger which creates new file on the given time (default in midnight):
|
// Create file logger which creates new file on the given time (default in midnight):
|
||||||
//
|
//
|
||||||
std::shared_ptr<logger> daily_logger_mt(const std::string& logger_name, const std::string& filename, int hour=0, int minute=0, bool force_flush = false);
|
std::shared_ptr<logger> daily_logger_mt(const std::string& logger_name, const std::string& filename, int hour=0, int minute=0, bool force_flush = false);
|
||||||
std::shared_ptr<logger> daily_logger_st(const std::string& logger_name, const std::string& filename, int hour=0, int minute=0, bool force_flush = false);
|
std::shared_ptr<logger> daily_logger_st(const std::string& logger_name, const std::string& filename, int hour=0, int minute=0, bool force_flush = false);
|
||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// Create and register stdout/stderr loggers
|
// Create and register stdout/stderr loggers
|
||||||
//
|
//
|
||||||
std::shared_ptr<logger> stdout_logger_mt(const std::string& logger_name, bool color = false);
|
std::shared_ptr<logger> stdout_logger_mt(const std::string& logger_name, bool color = false);
|
||||||
std::shared_ptr<logger> stdout_logger_st(const std::string& logger_name, bool color = false);
|
std::shared_ptr<logger> stdout_logger_st(const std::string& logger_name, bool color = false);
|
||||||
std::shared_ptr<logger> stderr_logger_mt(const std::string& logger_name, bool color = false);
|
std::shared_ptr<logger> stderr_logger_mt(const std::string& logger_name, bool color = false);
|
||||||
std::shared_ptr<logger> stderr_logger_st(const std::string& logger_name, bool color = false);
|
std::shared_ptr<logger> stderr_logger_st(const std::string& logger_name, bool color = false);
|
||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// Create and register a syslog logger
|
// Create and register a syslog logger
|
||||||
//
|
//
|
||||||
#if defined(__linux__) || defined(__APPLE__)
|
#if defined(__linux__) || defined(__APPLE__)
|
||||||
std::shared_ptr<logger> syslog_logger(const std::string& logger_name, const std::string& ident = "", int syslog_option = 0);
|
std::shared_ptr<logger> syslog_logger(const std::string& logger_name, const std::string& ident = "", int syslog_option = 0);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
// Create and register a logger with multiple sinks
|
// Create and register a logger with multiple sinks
|
||||||
std::shared_ptr<logger> create(const std::string& logger_name, sinks_init_list sinks);
|
std::shared_ptr<logger> create(const std::string& logger_name, sinks_init_list sinks);
|
||||||
template<class It>
|
template<class It>
|
||||||
std::shared_ptr<logger> create(const std::string& logger_name, const It& sinks_begin, const It& sinks_end);
|
std::shared_ptr<logger> create(const std::string& logger_name, const It& sinks_begin, const It& sinks_end);
|
||||||
|
|
||||||
|
|
||||||
// Create and register a logger with templated sink type
|
// Create and register a logger with templated sink type
|
||||||
// Example: spdlog::create<daily_file_sink_st>("mylog", "dailylog_filename", "txt");
|
// Example: spdlog::create<daily_file_sink_st>("mylog", "dailylog_filename", "txt");
|
||||||
template <typename Sink, typename... Args>
|
template <typename Sink, typename... Args>
|
||||||
std::shared_ptr<spdlog::logger> create(const std::string& logger_name, Args...);
|
std::shared_ptr<spdlog::logger> create(const std::string& logger_name, Args...);
|
||||||
|
|
||||||
|
|
||||||
// Register the given logger with the given name
|
// Register the given logger with the given name
|
||||||
void register_logger(std::shared_ptr<logger> logger);
|
void register_logger(std::shared_ptr<logger> logger);
|
||||||
|
|
||||||
// Drop the reference to the given logger
|
// Drop the reference to the given logger
|
||||||
void drop(const std::string &name);
|
void drop(const std::string &name);
|
||||||
|
|
||||||
// Drop all references
|
// Drop all references
|
||||||
void drop_all();
|
void drop_all();
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
//
|
//
|
||||||
// Macros to be display source file & line
|
// Macros to be display source file & line
|
||||||
// Trace & Debug can be switched on/off at compile time for zero cost debug statements.
|
// Trace & Debug can be switched on/off at compile time for zero cost debug statements.
|
||||||
// Uncomment SPDLOG_DEBUG_ON/SPDLOG_TRACE_ON in teakme.h to enable.
|
// Uncomment SPDLOG_DEBUG_ON/SPDLOG_TRACE_ON in teakme.h to enable.
|
||||||
//
|
//
|
||||||
// Example:
|
// Example:
|
||||||
// spdlog::set_level(spdlog::level::debug);
|
// spdlog::set_level(spdlog::level::debug);
|
||||||
// SPDLOG_DEBUG(my_logger, "Some debug message {} {}", 1, 3.2);
|
// SPDLOG_DEBUG(my_logger, "Some debug message {} {}", 1, 3.2);
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
#ifdef SPDLOG_TRACE_ON
|
#ifdef SPDLOG_TRACE_ON
|
||||||
#define SPDLOG_TRACE(logger, ...) logger->trace(__VA_ARGS__) << " (" << __FILE__ << " #" << __LINE__ <<")";
|
#define SPDLOG_TRACE(logger, ...) logger->trace(__VA_ARGS__) << " (" << __FILE__ << " #" << __LINE__ <<")";
|
||||||
#else
|
#else
|
||||||
#define SPDLOG_TRACE(logger, ...)
|
#define SPDLOG_TRACE(logger, ...)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef SPDLOG_DEBUG_ON
|
#ifdef SPDLOG_DEBUG_ON
|
||||||
#define SPDLOG_DEBUG(logger, ...) logger->debug(__VA_ARGS__) << " (" << __FILE__ << " #" << __LINE__ <<")";
|
#define SPDLOG_DEBUG(logger, ...) logger->debug(__VA_ARGS__) << " (" << __FILE__ << " #" << __LINE__ <<")";
|
||||||
#else
|
#else
|
||||||
#define SPDLOG_DEBUG(logger, ...)
|
#define SPDLOG_DEBUG(logger, ...)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#include <spdlog/details/spdlog_impl.h>
|
#include <spdlog/details/spdlog_impl.h>
|
||||||
|
@ -1,22 +1,22 @@
|
|||||||
CXX ?= g++
|
CXX ?= g++
|
||||||
CXXFLAGS = -Wall -pedantic -std=c++11 -pthread -O2 -I../include
|
CXXFLAGS = -Wall -pedantic -std=c++11 -pthread -O2 -I../include
|
||||||
LDPFALGS = -pthread
|
LDPFALGS = -pthread
|
||||||
|
|
||||||
CPP_FILES := $(wildcard *.cpp)
|
CPP_FILES := $(wildcard *.cpp)
|
||||||
OBJ_FILES := $(addprefix ./,$(notdir $(CPP_FILES:.cpp=.o)))
|
OBJ_FILES := $(addprefix ./,$(notdir $(CPP_FILES:.cpp=.o)))
|
||||||
|
|
||||||
|
|
||||||
tests: $(OBJ_FILES)
|
tests: $(OBJ_FILES)
|
||||||
$(CXX) $(CXXFLAGS) $(LDPFALGS) -o $@ $^
|
$(CXX) $(CXXFLAGS) $(LDPFALGS) -o $@ $^
|
||||||
mkdir -p logs
|
mkdir -p logs
|
||||||
|
|
||||||
%.o: %.cpp
|
%.o: %.cpp
|
||||||
$(CXX) $(CXXFLAGS) -c -o $@ $<
|
$(CXX) $(CXXFLAGS) -c -o $@ $<
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -f tests *.o logs/*.txt
|
rm -f tests *.o logs/*.txt
|
||||||
|
|
||||||
rebuild: clean tests
|
rebuild: clean tests
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,77 +1,77 @@
|
|||||||
/*
|
/*
|
||||||
* This content is released under the MIT License as specified in https://raw.githubusercontent.com/gabime/spdlog/master/LICENSE
|
* This content is released under the MIT License as specified in https://raw.githubusercontent.com/gabime/spdlog/master/LICENSE
|
||||||
*/
|
*/
|
||||||
#include "includes.h"
|
#include "includes.h"
|
||||||
|
|
||||||
using namespace spdlog::details;
|
using namespace spdlog::details;
|
||||||
|
|
||||||
static const std::string target_filename = "logs/file_helper_test.txt";
|
static const std::string target_filename = "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)
|
||||||
{
|
{
|
||||||
log_msg msg;
|
log_msg msg;
|
||||||
msg.formatted << std::string(howmany, '1');
|
msg.formatted << std::string(howmany, '1');
|
||||||
helper.write(msg);
|
helper.write(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
TEST_CASE("file_helper_filename", "[file_helper::filename()]]")
|
TEST_CASE("file_helper_filename", "[file_helper::filename()]]")
|
||||||
{
|
{
|
||||||
prepare_logdir();
|
prepare_logdir();
|
||||||
|
|
||||||
file_helper helper(false);
|
file_helper helper(false);
|
||||||
helper.open(target_filename);
|
helper.open(target_filename);
|
||||||
REQUIRE(helper.filename() == target_filename);
|
REQUIRE(helper.filename() == target_filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
TEST_CASE("file_helper_size", "[file_helper::size()]]")
|
TEST_CASE("file_helper_size", "[file_helper::size()]]")
|
||||||
{
|
{
|
||||||
prepare_logdir();
|
prepare_logdir();
|
||||||
auto expected_size = 123;
|
auto expected_size = 123;
|
||||||
{
|
{
|
||||||
file_helper helper(true);
|
file_helper helper(true);
|
||||||
helper.open(target_filename);
|
helper.open(target_filename);
|
||||||
write_with_helper(helper, expected_size);
|
write_with_helper(helper, expected_size);
|
||||||
REQUIRE(helper.size() == expected_size);
|
REQUIRE(helper.size() == expected_size);
|
||||||
}
|
}
|
||||||
REQUIRE(get_filesize(target_filename) == expected_size);
|
REQUIRE(get_filesize(target_filename) == expected_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
TEST_CASE("file_helper_exists", "[file_helper::file_exists()]]")
|
TEST_CASE("file_helper_exists", "[file_helper::file_exists()]]")
|
||||||
{
|
{
|
||||||
prepare_logdir();
|
prepare_logdir();
|
||||||
REQUIRE(!file_helper::file_exists(target_filename));
|
REQUIRE(!file_helper::file_exists(target_filename));
|
||||||
file_helper helper(false);
|
file_helper helper(false);
|
||||||
helper.open(target_filename);
|
helper.open(target_filename);
|
||||||
REQUIRE(file_helper::file_exists(target_filename));
|
REQUIRE(file_helper::file_exists(target_filename));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("file_helper_reopen", "[file_helper::reopen()]]")
|
TEST_CASE("file_helper_reopen", "[file_helper::reopen()]]")
|
||||||
{
|
{
|
||||||
prepare_logdir();
|
prepare_logdir();
|
||||||
file_helper helper(true);
|
file_helper helper(true);
|
||||||
helper.open(target_filename);
|
helper.open(target_filename);
|
||||||
write_with_helper(helper, 12);
|
write_with_helper(helper, 12);
|
||||||
REQUIRE(helper.size() == 12);
|
REQUIRE(helper.size() == 12);
|
||||||
helper.reopen(true);
|
helper.reopen(true);
|
||||||
REQUIRE(helper.size() == 0);
|
REQUIRE(helper.size() == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("file_helper_reopen2", "[file_helper::reopen(false)]]")
|
TEST_CASE("file_helper_reopen2", "[file_helper::reopen(false)]]")
|
||||||
{
|
{
|
||||||
prepare_logdir();
|
prepare_logdir();
|
||||||
auto expected_size = 14;
|
auto expected_size = 14;
|
||||||
file_helper helper(true);
|
file_helper helper(true);
|
||||||
helper.open(target_filename);
|
helper.open(target_filename);
|
||||||
write_with_helper(helper, expected_size);
|
write_with_helper(helper, expected_size);
|
||||||
REQUIRE(helper.size() == expected_size);
|
REQUIRE(helper.size() == expected_size);
|
||||||
helper.reopen(false);
|
helper.reopen(false);
|
||||||
REQUIRE(helper.size() == expected_size);
|
REQUIRE(helper.size() == expected_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,91 +1,91 @@
|
|||||||
/*
|
/*
|
||||||
* This content is released under the MIT License as specified in https://raw.githubusercontent.com/gabime/spdlog/master/LICENSE
|
* This content is released under the MIT License as specified in https://raw.githubusercontent.com/gabime/spdlog/master/LICENSE
|
||||||
*/
|
*/
|
||||||
#include "includes.h"
|
#include "includes.h"
|
||||||
|
|
||||||
|
|
||||||
TEST_CASE("simple_file_logger", "[simple_logger]]")
|
TEST_CASE("simple_file_logger", "[simple_logger]]")
|
||||||
{
|
{
|
||||||
prepare_logdir();
|
prepare_logdir();
|
||||||
std::string filename = "logs/simple_log.txt";
|
std::string filename = "logs/simple_log.txt";
|
||||||
|
|
||||||
auto logger = spdlog::create<spdlog::sinks::simple_file_sink_mt>("logger", filename);
|
auto logger = spdlog::create<spdlog::sinks::simple_file_sink_mt>("logger", filename);
|
||||||
logger->set_pattern("%v");
|
logger->set_pattern("%v");
|
||||||
|
|
||||||
|
|
||||||
logger->info("Test message {}", 1);
|
logger->info("Test message {}", 1);
|
||||||
logger->info("Test message {}", 2);
|
logger->info("Test message {}", 2);
|
||||||
logger->flush();
|
logger->flush();
|
||||||
REQUIRE(file_contents(filename) == std::string("Test message 1\nTest message 2\n"));
|
REQUIRE(file_contents(filename) == std::string("Test message 1\nTest message 2\n"));
|
||||||
REQUIRE(count_lines(filename) == 2);
|
REQUIRE(count_lines(filename) == 2);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("rotating_file_logger1", "[rotating_logger]]")
|
TEST_CASE("rotating_file_logger1", "[rotating_logger]]")
|
||||||
{
|
{
|
||||||
prepare_logdir();
|
prepare_logdir();
|
||||||
std::string basename = "logs/rotating_log";
|
std::string basename = "logs/rotating_log";
|
||||||
auto logger = spdlog::rotating_logger_mt("logger", basename, 1024, 0, true);
|
auto logger = spdlog::rotating_logger_mt("logger", basename, 1024, 0, true);
|
||||||
for (int i = 0; i < 10; ++i)
|
for (int i = 0; i < 10; ++i)
|
||||||
logger->info("Test message {}", i);
|
logger->info("Test message {}", i);
|
||||||
|
|
||||||
auto filename = basename + ".txt";
|
auto filename = basename + ".txt";
|
||||||
REQUIRE(count_lines(filename) == 10);
|
REQUIRE(count_lines(filename) == 10);
|
||||||
for (int i = 0; i < 1000; i++)
|
for (int i = 0; i < 1000; i++)
|
||||||
logger->info("Test message {}", i);
|
logger->info("Test message {}", i);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
TEST_CASE("rotating_file_logger2", "[rotating_logger]]")
|
TEST_CASE("rotating_file_logger2", "[rotating_logger]]")
|
||||||
{
|
{
|
||||||
prepare_logdir();
|
prepare_logdir();
|
||||||
std::string basename = "logs/rotating_log";
|
std::string basename = "logs/rotating_log";
|
||||||
auto logger = spdlog::rotating_logger_mt("logger", basename, 1024, 1, false);
|
auto logger = spdlog::rotating_logger_mt("logger", basename, 1024, 1, false);
|
||||||
for (int i = 0; i < 10; ++i)
|
for (int i = 0; i < 10; ++i)
|
||||||
logger->info("Test message {}", i);
|
logger->info("Test message {}", i);
|
||||||
|
|
||||||
logger->flush();
|
logger->flush();
|
||||||
auto filename = basename + ".txt";
|
auto filename = basename + ".txt";
|
||||||
REQUIRE(count_lines(filename) == 10);
|
REQUIRE(count_lines(filename) == 10);
|
||||||
for (int i = 0; i < 1000; i++)
|
for (int i = 0; i < 1000; i++)
|
||||||
logger->info("Test message {}", i);
|
logger->info("Test message {}", i);
|
||||||
|
|
||||||
logger->flush();
|
logger->flush();
|
||||||
REQUIRE(get_filesize(filename) <= 1024);
|
REQUIRE(get_filesize(filename) <= 1024);
|
||||||
auto filename1 = basename + ".1.txt";
|
auto filename1 = basename + ".1.txt";
|
||||||
REQUIRE(get_filesize(filename1) <= 1024);
|
REQUIRE(get_filesize(filename1) <= 1024);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
TEST_CASE("daily_logger", "[daily_logger]]")
|
TEST_CASE("daily_logger", "[daily_logger]]")
|
||||||
{
|
{
|
||||||
|
|
||||||
prepare_logdir();
|
prepare_logdir();
|
||||||
//calculate filename (time based)
|
//calculate filename (time based)
|
||||||
std::string basename = "logs/daily_log";
|
std::string basename = "logs/daily_log";
|
||||||
std::tm tm = spdlog::details::os::localtime();
|
std::tm tm = spdlog::details::os::localtime();
|
||||||
fmt::MemoryWriter w;
|
fmt::MemoryWriter w;
|
||||||
w.write("{}_{:04d}-{:02d}-{:02d}_{:02d}-{:02d}.txt", basename, tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min);
|
w.write("{}_{:04d}-{:02d}-{:02d}_{:02d}-{:02d}.txt", basename, tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min);
|
||||||
|
|
||||||
auto logger = spdlog::daily_logger_mt("logger", basename, 0, 0, true);
|
auto logger = spdlog::daily_logger_mt("logger", basename, 0, 0, true);
|
||||||
for (int i = 0; i < 10; ++i)
|
for (int i = 0; i < 10; ++i)
|
||||||
logger->info("Test message {}", i);
|
logger->info("Test message {}", i);
|
||||||
|
|
||||||
auto filename = w.str();
|
auto filename = w.str();
|
||||||
REQUIRE(count_lines(filename) == 10);
|
REQUIRE(count_lines(filename) == 10);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,15 +1,15 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <ostream>
|
#include <ostream>
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <exception>
|
#include <exception>
|
||||||
|
|
||||||
#include "catch.hpp"
|
#include "catch.hpp"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
|
|
||||||
#include "../include/spdlog/spdlog.h"
|
#include "../include/spdlog/spdlog.h"
|
||||||
#include "../include/spdlog/sinks/null_sink.h"
|
#include "../include/spdlog/sinks/null_sink.h"
|
||||||
|
|
||||||
|
@ -1,141 +1,141 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
<ItemGroup Label="ProjectConfigurations">
|
<ItemGroup Label="ProjectConfigurations">
|
||||||
<ProjectConfiguration Include="Debug|Win32">
|
<ProjectConfiguration Include="Debug|Win32">
|
||||||
<Configuration>Debug</Configuration>
|
<Configuration>Debug</Configuration>
|
||||||
<Platform>Win32</Platform>
|
<Platform>Win32</Platform>
|
||||||
</ProjectConfiguration>
|
</ProjectConfiguration>
|
||||||
<ProjectConfiguration Include="Debug|x64">
|
<ProjectConfiguration Include="Debug|x64">
|
||||||
<Configuration>Debug</Configuration>
|
<Configuration>Debug</Configuration>
|
||||||
<Platform>x64</Platform>
|
<Platform>x64</Platform>
|
||||||
</ProjectConfiguration>
|
</ProjectConfiguration>
|
||||||
<ProjectConfiguration Include="Release|Win32">
|
<ProjectConfiguration Include="Release|Win32">
|
||||||
<Configuration>Release</Configuration>
|
<Configuration>Release</Configuration>
|
||||||
<Platform>Win32</Platform>
|
<Platform>Win32</Platform>
|
||||||
</ProjectConfiguration>
|
</ProjectConfiguration>
|
||||||
<ProjectConfiguration Include="Release|x64">
|
<ProjectConfiguration Include="Release|x64">
|
||||||
<Configuration>Release</Configuration>
|
<Configuration>Release</Configuration>
|
||||||
<Platform>x64</Platform>
|
<Platform>x64</Platform>
|
||||||
</ProjectConfiguration>
|
</ProjectConfiguration>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<PropertyGroup Label="Globals">
|
<PropertyGroup Label="Globals">
|
||||||
<ProjectGuid>{59A07559-5F38-4DD6-A7FA-DB4153690B42}</ProjectGuid>
|
<ProjectGuid>{59A07559-5F38-4DD6-A7FA-DB4153690B42}</ProjectGuid>
|
||||||
<RootNamespace>tests</RootNamespace>
|
<RootNamespace>tests</RootNamespace>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||||
<ConfigurationType>Application</ConfigurationType>
|
<ConfigurationType>Application</ConfigurationType>
|
||||||
<UseDebugLibraries>true</UseDebugLibraries>
|
<UseDebugLibraries>true</UseDebugLibraries>
|
||||||
<PlatformToolset>v140</PlatformToolset>
|
<PlatformToolset>v140</PlatformToolset>
|
||||||
<CharacterSet>MultiByte</CharacterSet>
|
<CharacterSet>MultiByte</CharacterSet>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||||
<ConfigurationType>Application</ConfigurationType>
|
<ConfigurationType>Application</ConfigurationType>
|
||||||
<UseDebugLibraries>true</UseDebugLibraries>
|
<UseDebugLibraries>true</UseDebugLibraries>
|
||||||
<PlatformToolset>v140</PlatformToolset>
|
<PlatformToolset>v140</PlatformToolset>
|
||||||
<CharacterSet>MultiByte</CharacterSet>
|
<CharacterSet>MultiByte</CharacterSet>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||||
<ConfigurationType>Application</ConfigurationType>
|
<ConfigurationType>Application</ConfigurationType>
|
||||||
<UseDebugLibraries>false</UseDebugLibraries>
|
<UseDebugLibraries>false</UseDebugLibraries>
|
||||||
<PlatformToolset>v140</PlatformToolset>
|
<PlatformToolset>v140</PlatformToolset>
|
||||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||||
<CharacterSet>MultiByte</CharacterSet>
|
<CharacterSet>MultiByte</CharacterSet>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||||
<ConfigurationType>Application</ConfigurationType>
|
<ConfigurationType>Application</ConfigurationType>
|
||||||
<UseDebugLibraries>false</UseDebugLibraries>
|
<UseDebugLibraries>false</UseDebugLibraries>
|
||||||
<PlatformToolset>v140</PlatformToolset>
|
<PlatformToolset>v140</PlatformToolset>
|
||||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||||
<CharacterSet>MultiByte</CharacterSet>
|
<CharacterSet>MultiByte</CharacterSet>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||||
<ImportGroup Label="ExtensionSettings">
|
<ImportGroup Label="ExtensionSettings">
|
||||||
</ImportGroup>
|
</ImportGroup>
|
||||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
</ImportGroup>
|
</ImportGroup>
|
||||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
|
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
|
||||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
</ImportGroup>
|
</ImportGroup>
|
||||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
</ImportGroup>
|
</ImportGroup>
|
||||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
|
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
|
||||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
</ImportGroup>
|
</ImportGroup>
|
||||||
<PropertyGroup Label="UserMacros" />
|
<PropertyGroup Label="UserMacros" />
|
||||||
<PropertyGroup />
|
<PropertyGroup />
|
||||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||||
<ClCompile>
|
<ClCompile>
|
||||||
<WarningLevel>Level3</WarningLevel>
|
<WarningLevel>Level3</WarningLevel>
|
||||||
<Optimization>Disabled</Optimization>
|
<Optimization>Disabled</Optimization>
|
||||||
<SDLCheck>true</SDLCheck>
|
<SDLCheck>true</SDLCheck>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<Link>
|
<Link>
|
||||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
<SubSystem>Console</SubSystem>
|
<SubSystem>Console</SubSystem>
|
||||||
</Link>
|
</Link>
|
||||||
</ItemDefinitionGroup>
|
</ItemDefinitionGroup>
|
||||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||||
<ClCompile>
|
<ClCompile>
|
||||||
<WarningLevel>Level3</WarningLevel>
|
<WarningLevel>Level3</WarningLevel>
|
||||||
<Optimization>Disabled</Optimization>
|
<Optimization>Disabled</Optimization>
|
||||||
<SDLCheck>true</SDLCheck>
|
<SDLCheck>true</SDLCheck>
|
||||||
<PreprocessorDefinitions>_MBCS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
<PreprocessorDefinitions>_MBCS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
<AdditionalIncludeDirectories>$(SolutionDir)..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
<AdditionalIncludeDirectories>$(SolutionDir)..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<Link>
|
<Link>
|
||||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
<SubSystem>Console</SubSystem>
|
<SubSystem>Console</SubSystem>
|
||||||
</Link>
|
</Link>
|
||||||
</ItemDefinitionGroup>
|
</ItemDefinitionGroup>
|
||||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||||
<ClCompile>
|
<ClCompile>
|
||||||
<WarningLevel>Level4</WarningLevel>
|
<WarningLevel>Level4</WarningLevel>
|
||||||
<Optimization>MaxSpeed</Optimization>
|
<Optimization>MaxSpeed</Optimization>
|
||||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||||
<SDLCheck>true</SDLCheck>
|
<SDLCheck>true</SDLCheck>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<Link>
|
<Link>
|
||||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||||
<OptimizeReferences>true</OptimizeReferences>
|
<OptimizeReferences>true</OptimizeReferences>
|
||||||
<SubSystem>Console</SubSystem>
|
<SubSystem>Console</SubSystem>
|
||||||
</Link>
|
</Link>
|
||||||
</ItemDefinitionGroup>
|
</ItemDefinitionGroup>
|
||||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||||
<ClCompile>
|
<ClCompile>
|
||||||
<WarningLevel>Level4</WarningLevel>
|
<WarningLevel>Level4</WarningLevel>
|
||||||
<Optimization>MaxSpeed</Optimization>
|
<Optimization>MaxSpeed</Optimization>
|
||||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||||
<SDLCheck>true</SDLCheck>
|
<SDLCheck>true</SDLCheck>
|
||||||
<PreprocessorDefinitions>_MBCS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
<PreprocessorDefinitions>_MBCS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
<AdditionalIncludeDirectories>$(SolutionDir)..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
<AdditionalIncludeDirectories>$(SolutionDir)..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<Link>
|
<Link>
|
||||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||||
<OptimizeReferences>true</OptimizeReferences>
|
<OptimizeReferences>true</OptimizeReferences>
|
||||||
<SubSystem>Console</SubSystem>
|
<SubSystem>Console</SubSystem>
|
||||||
</Link>
|
</Link>
|
||||||
</ItemDefinitionGroup>
|
</ItemDefinitionGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClCompile Include="file_helper.cpp" />
|
<ClCompile Include="file_helper.cpp" />
|
||||||
<ClCompile Include="file_log.cpp" />
|
<ClCompile Include="file_log.cpp" />
|
||||||
<ClCompile Include="format.cpp" />
|
<ClCompile Include="format.cpp" />
|
||||||
<ClCompile Include="main.cpp" />
|
<ClCompile Include="main.cpp" />
|
||||||
<ClCompile Include="registry.cpp" />
|
<ClCompile Include="registry.cpp" />
|
||||||
<ClCompile Include="utils.cpp" />
|
<ClCompile Include="utils.cpp" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="catch.hpp" />
|
<ClInclude Include="catch.hpp" />
|
||||||
<ClInclude Include="includes.h" />
|
<ClInclude Include="includes.h" />
|
||||||
<ClInclude Include="utils.h" />
|
<ClInclude Include="utils.h" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||||
<ImportGroup Label="ExtensionTargets">
|
<ImportGroup Label="ExtensionTargets">
|
||||||
</ImportGroup>
|
</ImportGroup>
|
||||||
</Project>
|
</Project>
|
@ -1,48 +1,48 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Filter Include="Source Files">
|
<Filter Include="Source Files">
|
||||||
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||||
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||||
</Filter>
|
</Filter>
|
||||||
<Filter Include="Header Files">
|
<Filter Include="Header Files">
|
||||||
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||||
<Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
|
<Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
|
||||||
</Filter>
|
</Filter>
|
||||||
<Filter Include="Resource Files">
|
<Filter Include="Resource Files">
|
||||||
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
|
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
|
||||||
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
|
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
|
||||||
</Filter>
|
</Filter>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClCompile Include="file_log.cpp">
|
<ClCompile Include="file_log.cpp">
|
||||||
<Filter>Source Files</Filter>
|
<Filter>Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClCompile Include="format.cpp">
|
<ClCompile Include="format.cpp">
|
||||||
<Filter>Source Files</Filter>
|
<Filter>Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClCompile Include="main.cpp">
|
<ClCompile Include="main.cpp">
|
||||||
<Filter>Source Files</Filter>
|
<Filter>Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClCompile Include="registry.cpp">
|
<ClCompile Include="registry.cpp">
|
||||||
<Filter>Source Files</Filter>
|
<Filter>Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClCompile Include="file_helper.cpp">
|
<ClCompile Include="file_helper.cpp">
|
||||||
<Filter>Source Files</Filter>
|
<Filter>Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClCompile Include="utils.cpp">
|
<ClCompile Include="utils.cpp">
|
||||||
<Filter>Source Files</Filter>
|
<Filter>Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="includes.h">
|
<ClInclude Include="includes.h">
|
||||||
<Filter>Header Files</Filter>
|
<Filter>Header Files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClInclude Include="catch.hpp">
|
<ClInclude Include="catch.hpp">
|
||||||
<Filter>Header Files</Filter>
|
<Filter>Header Files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClInclude Include="utils.h">
|
<ClInclude Include="utils.h">
|
||||||
<Filter>Header Files</Filter>
|
<Filter>Header Files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
@ -1,45 +1,45 @@
|
|||||||
#include "includes.h"
|
#include "includes.h"
|
||||||
|
|
||||||
void prepare_logdir()
|
void prepare_logdir()
|
||||||
{
|
{
|
||||||
spdlog::drop_all();
|
spdlog::drop_all();
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
auto rv = system("del /F /Q logs\\*");
|
auto rv = system("del /F /Q logs\\*");
|
||||||
#else
|
#else
|
||||||
auto rv = system("rm -f logs/*");
|
auto rv = system("rm -f logs/*");
|
||||||
#endif
|
#endif
|
||||||
(void)rv;
|
(void)rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
std::string file_contents(const std::string& filename)
|
std::string file_contents(const std::string& filename)
|
||||||
{
|
{
|
||||||
std::ifstream ifs(filename);
|
std::ifstream ifs(filename);
|
||||||
if (!ifs)
|
if (!ifs)
|
||||||
throw std::runtime_error("Failed open file ");
|
throw std::runtime_error("Failed open file ");
|
||||||
return std::string((std::istreambuf_iterator<char>(ifs)),
|
return std::string((std::istreambuf_iterator<char>(ifs)),
|
||||||
(std::istreambuf_iterator<char>()));
|
(std::istreambuf_iterator<char>()));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::size_t count_lines(const std::string& filename)
|
std::size_t count_lines(const std::string& filename)
|
||||||
{
|
{
|
||||||
std::ifstream ifs(filename);
|
std::ifstream ifs(filename);
|
||||||
if (!ifs)
|
if (!ifs)
|
||||||
throw std::runtime_error("Failed open file ");
|
throw std::runtime_error("Failed open file ");
|
||||||
|
|
||||||
std::string line;
|
std::string line;
|
||||||
size_t counter = 0;
|
size_t counter = 0;
|
||||||
while(std::getline(ifs, line))
|
while(std::getline(ifs, line))
|
||||||
counter++;
|
counter++;
|
||||||
return counter;
|
return counter;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::size_t get_filesize(const std::string& filename)
|
std::size_t get_filesize(const std::string& filename)
|
||||||
{
|
{
|
||||||
std::ifstream ifs(filename, std::ifstream::ate | std::ifstream::binary);
|
std::ifstream ifs(filename, std::ifstream::ate | std::ifstream::binary);
|
||||||
if (!ifs)
|
if (!ifs)
|
||||||
throw std::runtime_error("Failed open file ");
|
throw std::runtime_error("Failed open file ");
|
||||||
|
|
||||||
return ifs.tellg();
|
return ifs.tellg();
|
||||||
}
|
}
|
||||||
|
@ -1,15 +1,15 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include<cstddef>
|
#include<cstddef>
|
||||||
|
|
||||||
std::size_t count_lines(const std::string& filename);
|
std::size_t count_lines(const std::string& filename);
|
||||||
|
|
||||||
void prepare_logdir();
|
void prepare_logdir();
|
||||||
|
|
||||||
std::string file_contents(const std::string& filename);
|
std::string file_contents(const std::string& filename);
|
||||||
|
|
||||||
std::size_t count_lines(const std::string& filename);
|
std::size_t count_lines(const std::string& filename);
|
||||||
|
|
||||||
std::size_t get_filesize(const std::string& filename);
|
std::size_t get_filesize(const std::string& filename);
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user