This commit is contained in:
gabime 2016-04-03 02:14:54 +03:00
parent 9230d9e63d
commit 495ecaeaee
48 changed files with 10700 additions and 10556 deletions

View File

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

View File

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

@ -1,158 +1,158 @@
# spdlog # spdlog
Very fast, header only, C++ logging library. [![Build Status](https://travis-ci.org/gabime/spdlog.svg?branch=master)](https://travis-ci.org/gabime/spdlog) Very fast, header only, C++ logging library. [![Build Status](https://travis-ci.org/gabime/spdlog.svg?branch=master)](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.

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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 << "..";
} }

View File

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

View File

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

View File

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

View File

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

View File

@ -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);
} }

View File

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

View File

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

View File

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

View File

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

View File

@ -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();
} }

View File

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

View File

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

View File

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

View File

@ -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();
} }

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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);
} }

View File

@ -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);
} }

View File

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

View File

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

View File

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

View File

@ -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();
} }

View File

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