Merge branch 'master' into custom_flag

pull/623/head
Fernando Gomes 8 years ago committed by GitHub
commit 955550d3c7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -0,0 +1,108 @@
---
Language: Cpp
# BasedOnStyle: LLVM
AccessModifierOffset: -4
AlignAfterOpenBracket: DontAlign
AlignConsecutiveAssignments: false
AlignConsecutiveDeclarations: false
AlignEscapedNewlines: Right
AlignOperands: true
AlignTrailingComments: true
AllowAllParametersOfDeclarationOnNextLine: true
AllowShortBlocksOnASingleLine: true
AllowShortCaseLabelsOnASingleLine: false
AllowShortFunctionsOnASingleLine: Empty
AllowShortIfStatementsOnASingleLine: false
AllowShortLoopsOnASingleLine: false
AlwaysBreakAfterDefinitionReturnType: None
AlwaysBreakAfterReturnType: None
AlwaysBreakBeforeMultilineStrings: false
AlwaysBreakTemplateDeclarations: true
BinPackArguments: true
BinPackParameters: true
BraceWrapping:
AfterClass: true
AfterControlStatement: true
AfterEnum: true
AfterFunction: true
AfterNamespace: false
AfterObjCDeclaration: true
AfterStruct: true
AfterUnion: true
BeforeCatch: true
BeforeElse: true
IndentBraces: false
SplitEmptyFunction: true
SplitEmptyRecord: true
SplitEmptyNamespace: true
BreakBeforeBinaryOperators: None
BreakBeforeBraces: Custom
BreakBeforeInheritanceComma: false
BreakBeforeTernaryOperators: true
BreakConstructorInitializersBeforeComma: true
BreakConstructorInitializers: BeforeColon
BreakAfterJavaFieldAnnotations: false
BreakStringLiterals: true
ColumnLimit: 140
CommentPragmas: '^ IWYU pragma:'
CompactNamespaces: false
ConstructorInitializerAllOnOneLineOrOnePerLine: false
ConstructorInitializerIndentWidth: 4
ContinuationIndentWidth: 4
Cpp11BracedListStyle: true
DerivePointerAlignment: false
DisableFormat: false
ExperimentalAutoDetectBinPacking: false
FixNamespaceComments: true
ForEachMacros:
- foreach
- Q_FOREACH
- BOOST_FOREACH
IncludeCategories:
- Regex: '^"(llvm|llvm-c|clang|clang-c)/'
Priority: 2
- Regex: '^(<|"(gtest|gmock|isl|json)/)'
Priority: 3
- Regex: '.*'
Priority: 1
IncludeIsMainRegex: '(Test)?$'
IndentCaseLabels: false
IndentWidth: 4
IndentWrappedFunctionNames: false
JavaScriptQuotes: Leave
JavaScriptWrapImports: true
KeepEmptyLinesAtTheStartOfBlocks: true
MacroBlockBegin: ''
MacroBlockEnd: ''
MaxEmptyLinesToKeep: 1
NamespaceIndentation: None
ObjCBlockIndentWidth: 2
ObjCSpaceAfterProperty: false
ObjCSpaceBeforeProtocolList: true
PenaltyBreakAssignment: 2
PenaltyBreakBeforeFirstCallParameter: 19
PenaltyBreakComment: 300
PenaltyBreakFirstLessLess: 120
PenaltyBreakString: 1000
PenaltyExcessCharacter: 1000000
PenaltyReturnTypeOnItsOwnLine: 60
PointerAlignment: Right
ReflowComments: true
SortIncludes: true
SortUsingDeclarations: true
SpaceAfterCStyleCast: false
SpaceAfterTemplateKeyword: false
SpaceBeforeAssignmentOperators: true
SpaceBeforeParens: ControlStatements
SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 1
SpacesInAngles: false
SpacesInContainerLiterals: true
SpacesInCStyleCastParentheses: false
SpacesInParentheses: false
SpacesInSquareBrackets: false
Standard: Cpp11
TabWidth: 8
UseTab: Never
...

4
.gitignore vendored

@ -1,4 +1,5 @@
# Auto generated files # Auto generated files
build/*
*.slo *.slo
*.lo *.lo
*.o *.o
@ -65,3 +66,6 @@ install_manifest.txt
# idea # idea
.idea/ .idea/
# vscode
.vscode/

@ -16,7 +16,7 @@ set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_STANDARD_REQUIRED ON)
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" OR "${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang") if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" OR "${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")
set(CMAKE_CXX_FLAGS "-Wall ${CMAKE_CXX_FLAGS}") set(CMAKE_CXX_FLAGS "-Wall -O3 ${CMAKE_CXX_FLAGS}")
endif() endif()
#--------------------------------------------------------------------------------------- #---------------------------------------------------------------------------------------

@ -120,9 +120,9 @@ int main(int, char*[])
daily_logger->info(123.44); daily_logger->info(123.44);
// 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");
rotating_logger->info("This is another message with custom format"); console->info("This an info message with custom format (and custom color range between the '%^' and '%$')");
console->error("This an error message with custom format (and custom color range between the '%^' and '%$')");
// 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

@ -1,5 +0,0 @@
#!/bin/bash
find . -name "*\.h" -o -name "*\.cpp"|xargs dos2unix
find . -name "*\.h" -o -name "*\.cpp"|xargs astyle -n -c -A1

@ -3,7 +3,16 @@ CXXFLAGS = -march=native -Wall -Wextra -pedantic -std=c++11 -pthread -I../includ
CXX_RELEASE_FLAGS = -O3 -flto -DNDEBUG CXX_RELEASE_FLAGS = -O3 -flto -DNDEBUG
binaries=spdlog-bench spdlog-bench-mt spdlog-async spdlog-null-async boost-bench boost-bench-mt glog-bench glog-bench-mt g2log-async easylogging-bench easylogging-bench-mt # g2log-async
binaries=spdlog-bench spdlog-bench-mt spdlog-async spdlog-null-async \
boost-bench boost-bench-mt \
glog-bench glog-bench-mt \
g3log-async \
p7-bench p7-bench-mt \
log4cpp-bench log4cpp-bench-mt \
log4cplus-bench log4cplus-bench-mt \
easylogging-bench easylogging-bench-mt easylogging-bench-async \
plog-bench plog-bench-mt
all: $(binaries) all: $(binaries)
@ -16,13 +25,10 @@ spdlog-bench-mt: spdlog-bench-mt.cpp
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)
spdlog-null-async: spdlog-null-async.cpp spdlog-null-async: spdlog-null-async.cpp
$(CXX) spdlog-null-async.cpp -o spdlog-null-async $(CXXFLAGS) $(CXX_RELEASE_FLAGS) $(CXX) spdlog-null-async.cpp -o spdlog-null-async $(CXXFLAGS) $(CXX_RELEASE_FLAGS)
BOOST_FLAGS = -DBOOST_LOG_DYN_LINK -I$(HOME)/include -I/usr/include -L$(HOME)/lib -lboost_log_setup -lboost_log -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)
@ -30,33 +36,62 @@ boost-bench: boost-bench.cpp
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 = -I$(HOME)/include -L$(HOME)/lib -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)/include -L$(HOME)/lib -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)
G3LOG_FLAGS = -I$(HOME)/include -L$(HOME)/lib -lg3logger
g3log-async: g3log-async.cpp
$(CXX) g3log-async.cpp -o g3log-async $(CXXFLAGS) $(G3LOG_FLAGS) $(CXX_RELEASE_FLAGS)
P7_FLAGS = -I$(HOME)/P7/Headers -I$(HOME)/include -L$(HOME)/lib -lP7
p7-bench: p7-bench.cpp
$(CXX) p7-bench.cpp -o p7-bench $(CXXFLAGS) $(P7_FLAGS) $(CXX_RELEASE_FLAGS)
p7-bench-mt: p7-bench-mt.cpp
$(CXX) p7-bench-mt.cpp -o p7-bench-mt $(CXXFLAGS) $(P7_FLAGS) $(CXX_RELEASE_FLAGS)
LOG4CPP_FLAGS = -I$(HOME)/include -L$(HOME)/lib -llog4cpp
log4cpp-bench: log4cpp-bench.cpp
$(CXX) log4cpp-bench.cpp -o log4cpp-bench $(CXXFLAGS) $(LOG4CPP_FLAGS) $(CXX_RELEASE_FLAGS)
log4cpp-bench-mt: log4cpp-bench-mt.cpp
$(CXX) log4cpp-bench-mt.cpp -o log4cpp-bench-mt $(CXXFLAGS) $(LOG4CPP_FLAGS) $(CXX_RELEASE_FLAGS)
LOG4CPLUS_FLAGS = -I$(HOME)/include -L$(HOME)/lib -llog4cplus
log4cplus-bench: log4cplus-bench.cpp
$(CXX) log4cplus-bench.cpp -o log4cplus-bench $(CXXFLAGS) $(LOG4CPLUS_FLAGS) $(CXX_RELEASE_FLAGS)
EASYL_FLAGS = -I../../easylogging/src/ log4cplus-bench-mt: log4cplus-bench-mt.cpp
$(CXX) log4cplus-bench-mt.cpp -o log4cplus-bench-mt $(CXXFLAGS) $(LOG4CPLUS_FLAGS) $(CXX_RELEASE_FLAGS)
EASYL_FLAGS = -I$(HOME)/easyloggingpp/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)
easylogging-bench-async: easylogging-bench-async.cpp
$(CXX) easylogging-bench-async.cpp -o easylogging-bench-async $(CXXFLAGS) $(EASYL_FLAGS) $(CXX_RELEASE_FLAGS)
PLOG_FLAGS = -I$(HOME)/include
plog-bench: plog-bench.cpp
$(CXX) plog-bench.cpp -o plog-bench $(CXXFLAGS) $(PLOG_FLAGS) $(CXX_RELEASE_FLAGS)
plog-bench-mt: plog-bench-mt.cpp
$(CXX) plog-bench-mt.cpp -o plog-bench-mt $(CXXFLAGS) $(PLOG_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

@ -0,0 +1,14 @@
# loggers
Name | License | Lang. | Year | Platform | Compiler | Dependence | URL
--- | --- | --- | --- | --- | --- | --- | ---
Pantheios | BSD | C++ | 2017 | Windows, Linux, MacOSX | VC++, GCC(3.2+), Intel, Borland, Comeau, Digital Mars, Metrowerks | STLSoft | http://www.pantheios.org/ <br> http://blog.pantheios.org/ <br> https://github.com/synesissoftware/Pantheios <br> http://www.pantheios.org/performance.html
Glog | 3-clause BSD| C++| 2017 | Windows, Linux, MacOSX | VC++, GCC, Clang, intel| Google gflags | https://github.com/google/glog
G3log | Public Domain | C++11 | 2018 | Windows, Linux, MacOSX, iPhoneOS | VC++, GCC, Clang, MinGW | None | https://github.com/KjellKod/g3log <br> https://github.com/KjellKod/g3sinks <br> https://kjellkod.wordpress.com/2014/08/16/presenting-g3log-the-next-version-of-the-next-generation-of-loggers/ <br> https://kjellkod.wordpress.com/2015/06/30/the-worlds-fastest-logger-vs-g3log/
P7 | LGPL | C++, C, C#, Python | 2017 | Windows, Linux | VC++, GCC, Clang, MinGW | None | http://baical.net/p7.html
log4cpp | LGPL | C++ | 2017 | Windows, Linux, MacOSX | VC++, GCC, Sun CC, OpenVMS | Boost | http://log4cpp.sourceforge.net/
log4cplus | 2-clause BSD or Apache 2 | C++ | 2017 | Windows, Linux, MacOSX, Android | VC++, GCC, Clang | Boost | https://github.com/log4cplus/log4cplus <br> https://sourceforge.net/p/log4cplus/wiki/Home/
Easylogging | MIT | C++11 | 2018 | Windows, Linux, MacOSX, iPhoneOS, Android | VC++, GCC, Clang, Intel, MinGW | None | https://github.com/muflihun/easyloggingpp
Spdlog | MIT | C++11 | 2018 | Windows, Linux, MacOSX, iPhoneOS, Android(logcat) | VC++, GCC, Clang, MinGW | None, Headers only library | https://github.com/gabime/spdlog <br> https://github.com/fmtlib/fmt
Boost.Log v2 | Boost | C++ | 2016 | Windows, Linux, MacOSX, iPhoneOS, Android | VC++, GCC, Clang | Boost | https://github.com/boostorg/log <br> http://www.boost.org/doc/libs/1_66_0/libs/log/doc/html/index.html
plog | MPL 2.0 | C++ | 2017 | Windows, Linux, MacOSX, iPhoneOS, Android | gcc, clang, msvc, mingw, mingw-w64, icc, c++builder | None, Headers only library | https://github.com/SergiusTheBest/plog

@ -3,18 +3,20 @@
// Distributed under the MIT License (http://opensource.org/licenses/MIT) // Distributed under the MIT License (http://opensource.org/licenses/MIT)
// //
#include <atomic>
#include <chrono>
#include <iostream>
#include <thread> #include <thread>
#include <vector> #include <vector>
#include <atomic>
#include <boost/log/core.hpp> #include <boost/log/core.hpp>
#include <boost/log/trivial.hpp>
#include <boost/log/expressions.hpp> #include <boost/log/expressions.hpp>
#include <boost/log/sinks/text_file_backend.hpp> #include <boost/log/sinks/text_file_backend.hpp>
#include <boost/log/utility/setup/file.hpp>
#include <boost/log/utility/setup/common_attributes.hpp>
#include <boost/log/sources/severity_logger.hpp>
#include <boost/log/sources/record_ostream.hpp> #include <boost/log/sources/record_ostream.hpp>
#include <boost/log/sources/severity_logger.hpp>
#include <boost/log/trivial.hpp>
#include <boost/log/utility/setup/common_attributes.hpp>
#include <boost/log/utility/setup/file.hpp>
namespace logging = boost::log; namespace logging = boost::log;
namespace src = boost::log::sources; namespace src = boost::log::sources;
@ -23,36 +25,28 @@ namespace keywords = boost::log::keywords;
void init() void init()
{ {
logging::add_file_log logging::add_file_log(keywords::file_name = "logs/boost-bench-mt_%N.log", /*< file name pattern >*/
( keywords::auto_flush = false, keywords::format = "[%TimeStamp%]: %Message%");
keywords::file_name = "logs/boost-sample_%N.log", /*< file name pattern >*/
keywords::auto_flush = false,
keywords::format = "[%TimeStamp%]: %Message%"
);
logging::core::get()->set_filter
(
logging::trivial::severity >= logging::trivial::info
);
}
logging::core::get()->set_filter(logging::trivial::severity >= logging::trivial::info);
}
using namespace std; using namespace std;
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
using namespace std::chrono;
using clock = steady_clock;
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;
init(); init();
logging::add_common_attributes(); logging::add_common_attributes();
using namespace logging::trivial; using namespace logging::trivial;
src::severity_logger_mt<severity_level> lg; src::severity_logger_mt<severity_level> lg;
@ -60,25 +54,33 @@ int main(int argc, char* argv[])
std::atomic<int> msg_counter{0}; std::atomic<int> msg_counter{0};
vector<thread> threads; vector<thread> threads;
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;
BOOST_LOG_SEV(lg, info) << "boost message #" << counter << ": This is some text for your pleasure"; BOOST_LOG_SEV(lg, info) << "boost 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;
float deltaf = delta.count();
auto rate = howmany / deltaf;
std::cout << "Total: " << howmany << std::endl;
std::cout << "Threads: " << thread_count << std::endl;
std::cout << "Delta = " << deltaf << " seconds" << std::endl;
std::cout << "Rate = " << rate << "/sec" << std::endl;
return 0; return 0;
} }

@ -2,14 +2,18 @@
// 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 <chrono>
#include <iostream>
#include <boost/log/core.hpp> #include <boost/log/core.hpp>
#include <boost/log/trivial.hpp>
#include <boost/log/expressions.hpp> #include <boost/log/expressions.hpp>
#include <boost/log/sinks/text_file_backend.hpp> #include <boost/log/sinks/text_file_backend.hpp>
#include <boost/log/utility/setup/file.hpp>
#include <boost/log/utility/setup/common_attributes.hpp>
#include <boost/log/sources/severity_logger.hpp>
#include <boost/log/sources/record_ostream.hpp> #include <boost/log/sources/record_ostream.hpp>
#include <boost/log/sources/severity_logger.hpp>
#include <boost/log/trivial.hpp>
#include <boost/log/utility/setup/common_attributes.hpp>
#include <boost/log/utility/setup/file.hpp>
namespace logging = boost::log; namespace logging = boost::log;
namespace src = boost::log::sources; namespace src = boost::log::sources;
@ -18,30 +22,35 @@ namespace keywords = boost::log::keywords;
void init() void init()
{ {
logging::add_file_log logging::add_file_log(keywords::file_name = "logs/boost-bench_%N.log", /*< file name pattern >*/
( keywords::auto_flush = false, keywords::format = "[%TimeStamp%]: %Message%");
keywords::file_name = "logs/boost-sample_%N.log", /*< file name pattern >*/
keywords::auto_flush = false,
keywords::format = "[%TimeStamp%]: %Message%"
);
logging::core::get()->set_filter
(
logging::trivial::severity >= logging::trivial::info
);
}
logging::core::get()->set_filter(logging::trivial::severity >= logging::trivial::info);
}
int main(int argc, char* []) int main(int, char *[])
{ {
using namespace std::chrono;
using clock = steady_clock;
int howmany = 1000000; int howmany = 1000000;
init(); init();
logging::add_common_attributes(); logging::add_common_attributes();
using namespace logging::trivial; using namespace logging::trivial;
src::severity_logger_mt<severity_level> lg; src::severity_logger_mt<severity_level> lg;
auto start = clock::now();
for (int i = 0; i < howmany; ++i) for (int i = 0; i < howmany; ++i)
BOOST_LOG_SEV(lg, info) << "boost message #" << i << ": This is some text for your pleasure"; BOOST_LOG_SEV(lg, info) << "boost message #" << i << ": This is some text for your pleasure";
duration<float> delta = clock::now() - start;
float deltaf = delta.count();
auto rate = howmany / deltaf;
std::cout << "Total: " << howmany << std::endl;
std::cout << "Delta = " << deltaf << " seconds" << std::endl;
std::cout << "Rate = " << rate << "/sec" << std::endl;
return 0; return 0;
} }

@ -0,0 +1,10 @@
* GLOBAL:
FORMAT = "[%datetime]: %levshort %thread %msg"
FILENAME = ./logs/easylogging-async.log
ENABLED = true
TO_FILE = true
TO_STANDARD_OUTPUT = false
MILLISECONDS_WIDTH = 3
PERFORMANCE_TRACKING = false
MAX_LOG_FILE_SIZE = 10485760
Log_Flush_Threshold = 10485760

@ -0,0 +1,10 @@
* GLOBAL:
FORMAT = "[%datetime]: %levshort %thread %msg"
FILENAME = ./logs/easylogging-mt.log
ENABLED = true
TO_FILE = true
TO_STANDARD_OUTPUT = false
MILLISECONDS_WIDTH = 3
PERFORMANCE_TRACKING = false
MAX_LOG_FILE_SIZE = 10485760
Log_Flush_Threshold = 10485760

@ -1,5 +1,5 @@
* GLOBAL: * GLOBAL:
FORMAT = "[%datetime]: %msg" FORMAT = "[%datetime]: %levshort %msg"
FILENAME = ./logs/easylogging.log FILENAME = ./logs/easylogging.log
ENABLED = true ENABLED = true
TO_FILE = true TO_FILE = true

@ -0,0 +1,67 @@
//
// Copyright(c) 2015 Gabi Melman.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
//
#include <atomic>
#include <chrono>
#include <iostream>
#include <thread>
#include <vector>
#define ELPP_THREAD_SAFE
#define ELPP_EXPERIMENTAL_ASYNC
#include "easylogging++.cc"
#include "easylogging++.h"
INITIALIZE_EASYLOGGINGPP
using namespace std;
int main(int argc, char *argv[])
{
using namespace std::chrono;
using clock = steady_clock;
int thread_count = 10;
if (argc > 1)
thread_count = atoi(argv[1]);
int howmany = 1000000;
// Load configuration from file
el::Configurations conf("easyl-async.conf");
el::Loggers::reconfigureLogger("default", conf);
std::atomic<int> msg_counter{0};
vector<thread> threads;
auto start = clock::now();
for (int t = 0; t < thread_count; ++t)
{
threads.push_back(std::thread([&]() {
while (true)
{
int counter = ++msg_counter;
if (counter > howmany)
break;
LOG(INFO) << "easylog message #" << counter << ": This is some text for your pleasure";
}
}));
}
for (auto &t : threads)
{
t.join();
}
duration<float> delta = clock::now() - start;
float deltaf = delta.count();
auto rate = howmany / deltaf;
std::cout << "Total: " << howmany << std::endl;
std::cout << "Threads: " << thread_count << std::endl;
std::cout << "Delta = " << deltaf << " seconds" << std::endl;
std::cout << "Rate = " << rate << "/sec" << std::endl;
return 0;
}

@ -3,18 +3,23 @@
// Distributed under the MIT License (http://opensource.org/licenses/MIT) // Distributed under the MIT License (http://opensource.org/licenses/MIT)
// //
#include <atomic>
#include <chrono>
#include <iostream>
#include <thread> #include <thread>
#include <vector> #include <vector>
#include <atomic>
#define _ELPP_THREAD_SAFE #define ELPP_THREAD_SAFE
#include "easylogging++.cc"
#include "easylogging++.h" #include "easylogging++.h"
_INITIALIZE_EASYLOGGINGPP INITIALIZE_EASYLOGGINGPP
using namespace std; using namespace std;
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
using namespace std::chrono;
using clock = steady_clock;
int thread_count = 10; int thread_count = 10;
if (argc > 1) if (argc > 1)
@ -23,30 +28,39 @@ int main(int argc, char* argv[])
int howmany = 1000000; int howmany = 1000000;
// Load configuration from file // Load configuration from file
el::Configurations conf("easyl.conf"); el::Configurations conf("easyl-mt.conf");
el::Loggers::reconfigureLogger("default", conf); el::Loggers::reconfigureLogger("default", conf);
std::atomic<int> msg_counter{0}; std::atomic<int> msg_counter{0};
vector<thread> threads; vector<thread> threads;
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;
LOG(INFO) << "easylog message #" << counter << ": This is some text for your pleasure"; LOG(INFO) << "easylog 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;
float deltaf = delta.count();
auto rate = howmany / deltaf;
std::cout << "Total: " << howmany << std::endl;
std::cout << "Threads: " << thread_count << std::endl;
std::cout << "Delta = " << deltaf << " seconds" << std::endl;
std::cout << "Rate = " << rate << "/sec" << std::endl;
return 0; return 0;
} }

@ -3,20 +3,37 @@
// Distributed under the MIT License (http://opensource.org/licenses/MIT) // Distributed under the MIT License (http://opensource.org/licenses/MIT)
// //
#include <chrono>
#include <iostream>
#include "easylogging++.cc"
#include "easylogging++.h" #include "easylogging++.h"
INITIALIZE_EASYLOGGINGPP
_INITIALIZE_EASYLOGGINGPP
int main(int, char *[]) int main(int, char *[])
{ {
using namespace std::chrono;
using clock = steady_clock;
int howmany = 1000000; int howmany = 1000000;
// Load configuration from file // Load configuration from file
el::Configurations conf("easyl.conf"); el::Configurations conf("easyl.conf");
el::Loggers::reconfigureLogger("default", conf); el::Loggers::reconfigureLogger("default", conf);
el::Logger *defaultLogger = el::Loggers::getLogger("default");
auto start = clock::now();
for (int i = 0; i < howmany; ++i) for (int i = 0; i < howmany; ++i)
LOG(INFO) << "easylog message #" << i << ": This is some text for your pleasure"; LOG(INFO) << "easylog message #" << i << ": This is some text for your pleasure";
duration<float> delta = clock::now() - start;
float deltaf = delta.count();
auto rate = howmany / deltaf;
std::cout << "Total: " << howmany << std::endl;
std::cout << "Delta = " << deltaf << " seconds" << std::endl;
std::cout << "Rate = " << rate << "/sec" << std::endl;
return 0; return 0;
} }

@ -3,17 +3,18 @@
// Distributed under the MIT License (http://opensource.org/licenses/MIT) // Distributed under the MIT License (http://opensource.org/licenses/MIT)
// //
#include <thread>
#include <vector>
#include <atomic> #include <atomic>
#include <iostream>
#include <chrono> #include <chrono>
#include <iostream>
#include <thread>
#include <vector>
#include "g2logworker.h"
#include "g2log.h" #include "g2log.h"
#include "g2logworker.h"
using namespace std; using namespace std;
template<typename T> std::string format(const T& value); template<typename T>
std::string format(const T &value);
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
@ -28,28 +29,26 @@ int main(int argc, char* argv[])
g2LogWorker g2log(argv[0], "logs"); g2LogWorker g2log(argv[0], "logs");
g2::initializeLogging(&g2log); g2::initializeLogging(&g2log);
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;
LOG(INFO) << "g2log message #" << counter << ": This is some text for your pleasure"; LOG(INFO) << "g2log 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();

@ -0,0 +1,63 @@
//
// Copyright(c) 2015 Gabi Melman.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
//
#include <atomic>
#include <chrono>
#include <iostream>
#include <thread>
#include <vector>
#include "g3log/g3log.hpp"
#include "g3log/logworker.hpp"
using namespace std;
template<typename T>
std::string format(const T &value);
int main(int argc, char *argv[])
{
using namespace std::chrono;
using clock = steady_clock;
int thread_count = 10;
if (argc > 1)
thread_count = atoi(argv[1]);
int howmany = 1000000;
auto worker = g3::LogWorker::createLogWorker();
auto handle = worker->addDefaultLogger(argv[0], "logs");
g3::initializeLogging(worker.get());
std::atomic<int> msg_counter{0};
vector<thread> threads;
auto start = clock::now();
for (int t = 0; t < thread_count; ++t)
{
threads.push_back(std::thread([&]() {
while (true)
{
int counter = ++msg_counter;
if (counter > howmany)
break;
LOG(INFO) << "g3log message #" << counter << ": This is some text for your pleasure";
}
}));
}
for (auto &t : threads)
{
t.join();
}
duration<float> delta = clock::now() - start;
float deltaf = delta.count();
auto rate = howmany / deltaf;
cout << "Total: " << howmany << std::endl;
cout << "Threads: " << thread_count << std::endl;
std::cout << "Delta = " << deltaf << " seconds" << std::endl;
std::cout << "Rate = " << rate << "/sec" << std::endl;
}

@ -3,9 +3,11 @@
// Distributed under the MIT License (http://opensource.org/licenses/MIT) // Distributed under the MIT License (http://opensource.org/licenses/MIT)
// //
#include <atomic>
#include <chrono>
#include <iostream>
#include <thread> #include <thread>
#include <vector> #include <vector>
#include <atomic>
#include "glog/logging.h" #include "glog/logging.h"
@ -13,6 +15,8 @@ using namespace std;
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
using namespace std::chrono;
using clock = steady_clock;
int thread_count = 10; int thread_count = 10;
if (argc > 1) if (argc > 1)
@ -27,24 +31,33 @@ int main(int argc, char* argv[])
std::atomic<int> msg_counter{0}; std::atomic<int> msg_counter{0};
vector<thread> threads; vector<thread> threads;
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;
LOG(INFO) << "glog message #" << counter << ": This is some text for your pleasure"; LOG(INFO) << "glog 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;
float deltaf = delta.count();
auto rate = howmany / deltaf;
std::cout << "Total: " << howmany << std::endl;
std::cout << "Threads: " << thread_count << std::endl;
std::cout << "Delta = " << deltaf << " seconds" << std::endl;
std::cout << "Rate = " << rate << "/sec" << std::endl;
return 0; return 0;
} }

@ -3,19 +3,32 @@
// Distributed under the MIT License (http://opensource.org/licenses/MIT) // Distributed under the MIT License (http://opensource.org/licenses/MIT)
// //
#include "glog/logging.h" #include <chrono>
#include <iostream>
#include "glog/logging.h"
int main(int, char *argv[]) int main(int, char *argv[])
{ {
int howmany = 1000000; using namespace std::chrono;
using clock = steady_clock;
int howmany = 1000000;
FLAGS_logtostderr = 0; FLAGS_logtostderr = 0;
FLAGS_log_dir = "logs"; FLAGS_log_dir = "logs";
google::InitGoogleLogging(argv[0]); google::InitGoogleLogging(argv[0]);
auto start = clock::now();
for (int i = 0; i < howmany; ++i) for (int i = 0; i < howmany; ++i)
LOG(INFO) << "glog message #" << i << ": This is some text for your pleasure"; LOG(INFO) << "glog message #" << i << ": This is some text for your pleasure";
duration<float> delta = clock::now() - start;
float deltaf = delta.count();
auto rate = howmany / deltaf;
std::cout << "Total: " << howmany << std::endl;
std::cout << "Delta = " << deltaf << " seconds" << std::endl;
std::cout << "Rate = " << rate << "/sec" << std::endl;
return 0; return 0;
} }

@ -16,7 +16,6 @@ void CrusherLoop()
} }
} }
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
std::cout << "WARNING: This test will exaust all your machine memory and will crush it!" << std::endl; std::cout << "WARNING: This test will exaust all your machine memory and will crush it!" << std::endl;
@ -33,5 +32,3 @@ int main(int argc, char** argv)
return 0; return 0;
} }

@ -1,31 +1,25 @@
#include <thread> #include "utils.h"
#include <vector> #include <algorithm>
#include <atomic> #include <atomic>
#include <iostream>
#include <chrono> #include <chrono>
#include <algorithm> #include <cstdio>
#include <fstream>
#include <functional>
#include <g3log/g3log.hpp>
#include <g3log/logworker.hpp>
#include <iomanip> #include <iomanip>
#include <iostream> #include <iostream>
#include <sstream>
#include <fstream>
#include <cstdio>
#include <map> #include <map>
#include <numeric> #include <numeric>
#include <functional> #include <sstream>
#include <thread> #include <thread>
#include "utils.h" #include <vector>
#include <g3log/g3log.hpp>
#include <g3log/logworker.hpp>
namespace namespace {
{
const uint64_t g_iterations = 1000000; const uint64_t g_iterations = 1000000;
std::atomic<size_t> g_counter = {0}; std::atomic<size_t> g_counter = {0};
void MeasurePeakDuringLogWrites(const size_t id, std::vector<uint64_t> &result) void MeasurePeakDuringLogWrites(const size_t id, std::vector<uint64_t> &result)
{ {
@ -45,8 +39,6 @@ void MeasurePeakDuringLogWrites(const size_t id, std::vector<uint64_t>& result)
} }
} }
void PrintResults(const std::map<size_t, std::vector<uint64_t>> &threads_result, size_t total_us) void PrintResults(const std::map<size_t, std::vector<uint64_t>> &threads_result, size_t total_us)
{ {
@ -64,11 +56,10 @@ void PrintResults(const std::map<size_t, std::vector<uint64_t>>& threads_result,
auto total = accumulate(begin(all_measurements), end(all_measurements), 0, std::plus<uint64_t>()); auto total = accumulate(begin(all_measurements), end(all_measurements), 0, std::plus<uint64_t>());
auto avg = double(total) / all_measurements.size(); auto avg = double(total) / all_measurements.size();
std::cout << "[g3log] worst: " << std::setw(10) << std::right << worst << "\tAvg: " << avg << "\tTotal: " << utils::format(total_us) << " us" << std::endl; std::cout << "[g3log] worst: " << std::setw(10) << std::right << worst << "\tAvg: " << avg << "\tTotal: " << utils::format(total_us)
<< " us" << std::endl;
} }
}// anonymous } // namespace
// The purpose of this test is NOT to see how fast // The purpose of this test is NOT to see how fast
// each thread can possibly write. It is to see what // each thread can possibly write. It is to see what
@ -91,7 +82,6 @@ int main(int argc, char** argv)
return 1; return 1;
} }
std::vector<std::thread> threads(number_of_threads); std::vector<std::thread> threads(number_of_threads);
std::map<size_t, std::vector<uint64_t>> threads_result; std::map<size_t, std::vector<uint64_t>> threads_result;
@ -121,9 +111,8 @@ int main(int argc, char** argv)
} }
auto stop_time_application_total = std::chrono::high_resolution_clock::now(); auto stop_time_application_total = std::chrono::high_resolution_clock::now();
uint64_t total_time_in_us = std::chrono::duration_cast<std::chrono::microseconds>(stop_time_application_total - start_time_application_total).count(); uint64_t total_time_in_us =
std::chrono::duration_cast<std::chrono::microseconds>(stop_time_application_total - start_time_application_total).count();
PrintResults(threads_result, total_time_in_us); PrintResults(threads_result, total_time_in_us);
return 0; return 0;
} }

@ -1,30 +1,25 @@
#include <thread> #include "utils.h"
#include <vector> #include <algorithm>
#include <atomic> #include <atomic>
#include <iostream>
#include <chrono> #include <chrono>
#include <algorithm>
#include <iostream>
#include <cstdio> #include <cstdio>
#include <functional>
#include <iostream>
#include <map> #include <map>
#include <numeric> #include <numeric>
#include <functional>
#include "utils.h"
#include <thread> #include <thread>
#include <vector>
#include "spdlog/spdlog.h" #include "spdlog/spdlog.h"
namespace spd = spdlog; namespace spd = spdlog;
namespace namespace {
{
const uint64_t g_iterations = 1000000; const uint64_t g_iterations = 1000000;
std::atomic<size_t> g_counter = {0}; std::atomic<size_t> g_counter = {0};
void MeasurePeakDuringLogWrites(const size_t id, std::vector<uint64_t> &result) void MeasurePeakDuringLogWrites(const size_t id, std::vector<uint64_t> &result)
{ {
auto logger = spd::get("file_logger"); auto logger = spd::get("file_logger");
@ -44,7 +39,6 @@ void MeasurePeakDuringLogWrites(const size_t id, std::vector<uint64_t>& result)
} }
} }
void PrintResults(const std::map<size_t, std::vector<uint64_t>> &threads_result, size_t total_us) void PrintResults(const std::map<size_t, std::vector<uint64_t>> &threads_result, size_t total_us)
{ {
@ -62,11 +56,10 @@ void PrintResults(const std::map<size_t, std::vector<uint64_t>>& threads_result,
auto total = accumulate(begin(all_measurements), end(all_measurements), 0, std::plus<uint64_t>()); auto total = accumulate(begin(all_measurements), end(all_measurements), 0, std::plus<uint64_t>());
auto avg = double(total) / all_measurements.size(); auto avg = double(total) / all_measurements.size();
std::cout << "[spdlog] worst: " << std::setw(10) << std::right << worst << "\tAvg: " << avg << "\tTotal: " << utils::format(total_us) << " us" << std::endl; std::cout << "[spdlog] worst: " << std::setw(10) << std::right << worst << "\tAvg: " << avg << "\tTotal: " << utils::format(total_us)
<< " us" << std::endl;
} }
}// anonymous } // namespace
// The purpose of this test is NOT to see how fast // The purpose of this test is NOT to see how fast
// each thread can possibly write. It is to see what // each thread can possibly write. It is to see what
@ -89,7 +82,6 @@ int main(int argc, char** argv)
return 1; return 1;
} }
std::vector<std::thread> threads(number_of_threads); std::vector<std::thread> threads(number_of_threads);
std::map<size_t, std::vector<uint64_t>> threads_result; std::map<size_t, std::vector<uint64_t>> threads_result;
@ -119,10 +111,9 @@ int main(int argc, char** argv)
} }
auto stop_time_application_total = std::chrono::high_resolution_clock::now(); auto stop_time_application_total = std::chrono::high_resolution_clock::now();
uint64_t total_time_in_us = std::chrono::duration_cast<std::chrono::microseconds>(stop_time_application_total - start_time_application_total).count(); uint64_t total_time_in_us =
std::chrono::duration_cast<std::chrono::microseconds>(stop_time_application_total - start_time_application_total).count();
PrintResults(threads_result, total_time_in_us); PrintResults(threads_result, total_time_in_us);
return 0; return 0;
} }

@ -5,12 +5,11 @@
#pragma once #pragma once
#include <sstream>
#include <iomanip> #include <iomanip>
#include <locale> #include <locale>
#include <sstream>
namespace utils namespace utils {
{
template<typename T> template<typename T>
inline std::string format(const T &value) inline std::string format(const T &value)
@ -32,4 +31,4 @@ inline std::string format(const double & value)
return ss.str(); return ss.str();
} }
} } // namespace utils

@ -0,0 +1,78 @@
//
// Copyright(c) 2015 Gabi Melman.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
//
#include <atomic>
#include <chrono>
#include <iostream>
#include <memory>
#include <thread>
#include <vector>
#include "log4cplus/fileappender.h"
#include "log4cplus/helpers/loglog.h"
#include "log4cplus/helpers/property.h"
#include "log4cplus/layout.h"
#include "log4cplus/logger.h"
#include "log4cplus/loggingmacros.h"
#include "log4cplus/ndc.h"
using namespace log4cplus;
int main(int argc, char *argv[])
{
using namespace std::chrono;
using clock = steady_clock;
int thread_count = 10;
if (argc > 1)
thread_count = std::atoi(argv[1]);
int howmany = 1000000;
log4cplus::initialize();
SharedFileAppenderPtr append(new FileAppender(LOG4CPLUS_TEXT("logs/log4cplus-bench-mt.log"), std::ios_base::trunc, true, true));
append->setName(LOG4CPLUS_TEXT("File"));
log4cplus::tstring pattern = LOG4CPLUS_TEXT("%d{%Y-%m-%d %H:%M:%S.%Q}: %p - %m %n");
append->setLayout(std::auto_ptr<Layout>(new PatternLayout(pattern)));
append->getloc();
Logger::getRoot().addAppender(SharedAppenderPtr(append.get()));
Logger root = Logger::getRoot();
std::atomic<int> msg_counter{0};
std::vector<std::thread> threads;
auto start = clock::now();
for (int t = 0; t < thread_count; ++t)
{
threads.push_back(std::thread([&]() {
while (true)
{
int counter = ++msg_counter;
if (counter > howmany)
break;
LOG4CPLUS_INFO(root, "log4cplus message #" << counter << ": This is some text for your pleasure");
}
}));
}
for (auto &t : threads)
{
t.join();
}
duration<float> delta = clock::now() - start;
float deltaf = delta.count();
auto rate = howmany / deltaf;
std::cout << "Total: " << howmany << std::endl;
std::cout << "Threads: " << thread_count << std::endl;
std::cout << "Delta = " << deltaf << " seconds" << std::endl;
std::cout << "Rate = " << rate << "/sec" << std::endl;
log4cplus::Logger::shutdown();
return 0;
}

@ -0,0 +1,52 @@
//
// Copyright(c) 2015 Gabi Melman.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
//
#include <chrono>
#include <iostream>
#include <memory>
#include "log4cplus/fileappender.h"
#include "log4cplus/helpers/loglog.h"
#include "log4cplus/helpers/property.h"
#include "log4cplus/layout.h"
#include "log4cplus/logger.h"
#include "log4cplus/loggingmacros.h"
#include "log4cplus/ndc.h"
using namespace log4cplus;
int main(int, char *[])
{
using namespace std::chrono;
using clock = steady_clock;
int howmany = 1000000;
log4cplus::initialize();
SharedFileAppenderPtr append(new FileAppender(LOG4CPLUS_TEXT("logs/log4cplus-bench.log"), std::ios_base::trunc, true, true));
append->setName(LOG4CPLUS_TEXT("File"));
log4cplus::tstring pattern = LOG4CPLUS_TEXT("%d{%Y-%m-%d %H:%M:%S.%Q}: %p - %m %n");
append->setLayout(std::auto_ptr<Layout>(new PatternLayout(pattern)));
append->getloc();
Logger::getRoot().addAppender(SharedAppenderPtr(append.get()));
Logger root = Logger::getRoot();
auto start = clock::now();
for (int i = 0; i < howmany; ++i)
LOG4CPLUS_INFO(root, "log4cplus message #" << i << ": This is some text for your pleasure");
duration<float> delta = clock::now() - start;
float deltaf = delta.count();
auto rate = howmany / deltaf;
std::cout << "Total: " << howmany << std::endl;
std::cout << "Delta = " << deltaf << " seconds" << std::endl;
std::cout << "Rate = " << rate << "/sec" << std::endl;
log4cplus::Logger::shutdown();
return 0;
}

@ -0,0 +1,74 @@
//
// Copyright(c) 2015 Gabi Melman.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
//
#include <atomic>
#include <chrono>
#include <iostream>
#include <memory>
#include <thread>
#include <vector>
#include "log4cpp/Appender.hh"
#include "log4cpp/BasicLayout.hh"
#include "log4cpp/Category.hh"
#include "log4cpp/FileAppender.hh"
#include "log4cpp/Layout.hh"
#include "log4cpp/PatternLayout.hh"
#include "log4cpp/Priority.hh"
int main(int argc, char *argv[])
{
using namespace std::chrono;
using clock = steady_clock;
int thread_count = 10;
if (argc > 1)
thread_count = std::atoi(argv[1]);
int howmany = 1000000;
log4cpp::Appender *appender = new log4cpp::FileAppender("default", "logs/log4cpp-bench-mt.log");
log4cpp::PatternLayout *layout = new log4cpp::PatternLayout();
layout->setConversionPattern("%d{%Y-%m-%d %H:%M:%S.%l}: %p - %m %n");
appender->setLayout(layout);
log4cpp::Category &root = log4cpp::Category::getRoot();
root.addAppender(appender);
root.setPriority(log4cpp::Priority::INFO);
std::atomic<int> msg_counter{0};
std::vector<std::thread> threads;
auto start = clock::now();
for (int t = 0; t < thread_count; ++t)
{
threads.push_back(std::thread([&]() {
while (true)
{
int counter = ++msg_counter;
if (counter > howmany)
break;
root << log4cpp::Priority::INFO << "log4cpp message #" << counter << ": This is some text for your pleasure";
}
}));
}
for (auto &t : threads)
{
t.join();
}
duration<float> delta = clock::now() - start;
float deltaf = delta.count();
auto rate = howmany / deltaf;
std::cout << "Total: " << howmany << std::endl;
std::cout << "Threads: " << thread_count << std::endl;
std::cout << "Delta = " << deltaf << " seconds" << std::endl;
std::cout << "Rate = " << rate << "/sec" << std::endl;
root.shutdown();
return 0;
}

@ -0,0 +1,48 @@
//
// Copyright(c) 2015 Gabi Melman.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
//
#include <chrono>
#include <iostream>
#include <memory>
#include "log4cpp/Appender.hh"
#include "log4cpp/BasicLayout.hh"
#include "log4cpp/Category.hh"
#include "log4cpp/FileAppender.hh"
#include "log4cpp/Layout.hh"
#include "log4cpp/PatternLayout.hh"
#include "log4cpp/Priority.hh"
int main(int, char *[])
{
using namespace std::chrono;
using clock = steady_clock;
int howmany = 1000000;
log4cpp::Appender *appender = new log4cpp::FileAppender("default", "logs/log4cpp-bench.log");
log4cpp::PatternLayout *layout = new log4cpp::PatternLayout();
layout->setConversionPattern("%d{%Y-%m-%d %H:%M:%S.%l}: %p - %m %n");
appender->setLayout(layout);
log4cpp::Category &root = log4cpp::Category::getRoot();
root.addAppender(appender);
root.setPriority(log4cpp::Priority::INFO);
auto start = clock::now();
for (int i = 0; i < howmany; ++i)
root << log4cpp::Priority::INFO << "log4cpp message #" << i << ": This is some text for your pleasure";
duration<float> delta = clock::now() - start;
float deltaf = delta.count();
auto rate = howmany / deltaf;
std::cout << "Total: " << howmany << std::endl;
std::cout << "Delta = " << deltaf << " seconds" << std::endl;
std::cout << "Rate = " << rate << "/sec" << std::endl;
root.shutdown();
return 0;
}

@ -0,0 +1,19 @@
#!/bin/sh
if [ $# -lt 1 ]; then
echo "usage: $0 <program>"
fi
PROG=$1
if [ ! -x "$PROG" ]; then
echo $PROG not found or not executable.
exit 1
fi
$* &
PID=$!
while `kill -0 $PID 2>/dev/null`; do
ps -eo size,pid,user,pcpu,command --sort -size | awk '{ line=1 ; hr=$1/1024 ; printf("%13.2f Mb ",hr); } { for ( x=4 ; x<=NF ; x++ ) { printf("%s ",$x) } print "" }' | grep -v grep | grep -v $0 | grep $PROG
done

@ -0,0 +1,94 @@
//
// Copyright(c) 2015 Gabi Melman.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
//
#include <atomic>
#include <chrono>
#include <functional>
#include <iostream>
#include <memory>
#include <thread>
#include <vector>
#include "P7_Trace.h"
int main(int argc, char *argv[])
{
using namespace std::chrono;
using clock = steady_clock;
int thread_count = 10;
if (argc > 1)
thread_count = std::atoi(argv[1]);
int howmany = 1000000;
IP7_Trace::hModule module = NULL;
// create P7 client object
std::unique_ptr<IP7_Client, std::function<void(IP7_Client *)>> client(
P7_Create_Client(TM("/P7.Pool=1024 /P7.Sink=FileTxt /P7.Dir=logs/p7-bench-mt")), [&](IP7_Client *ptr) {
if (ptr)
ptr->Release();
});
if (!client)
{
std::cout << "Can't create IP7_Client" << std::endl;
return 1;
}
// create P7 trace object 1
std::unique_ptr<IP7_Trace, std::function<void(IP7_Trace *)>> trace(
P7_Create_Trace(client.get(), TM("Trace channel 1")), [&](IP7_Trace *ptr) {
if (ptr)
ptr->Release();
});
if (!trace)
{
std::cout << "Can't create IP7_Trace" << std::endl;
return 1;
}
trace->Register_Thread(TM("Application"), 0);
trace->Register_Module(TM("Main"), &module);
std::atomic<int> msg_counter{0};
std::vector<std::thread> threads;
auto start = clock::now();
for (int t = 0; t < thread_count; ++t)
{
threads.push_back(std::thread([&]() {
trace->Register_Thread(TM("Application"), t + 1);
while (true)
{
int counter = ++msg_counter;
if (counter > howmany)
break;
trace->P7_INFO(module, TM("p7 message #%d: This is some text for your pleasure"), counter);
}
trace->Register_Thread(TM("Application"), t + 1);
}));
}
for (auto &t : threads)
{
t.join();
}
duration<float> delta = clock::now() - start;
float deltaf = delta.count();
auto rate = howmany / deltaf;
std::cout << "Total: " << howmany << std::endl;
std::cout << "Threads: " << thread_count << std::endl;
std::cout << "Delta = " << deltaf << " seconds" << std::endl;
std::cout << "Rate = " << rate << "/sec" << std::endl;
trace->Unregister_Thread(0);
return 0;
}

@ -0,0 +1,66 @@
//
// Copyright(c) 2015 Gabi Melman.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
//
#include <chrono>
#include <functional>
#include <iostream>
#include <memory>
#include "P7_Trace.h"
int main(int, char *[])
{
using namespace std::chrono;
using clock = steady_clock;
int howmany = 1000000;
IP7_Trace::hModule module = NULL;
// create P7 client object
std::unique_ptr<IP7_Client, std::function<void(IP7_Client *)>> client(
P7_Create_Client(TM("/P7.Pool=1024 /P7.Sink=FileTxt /P7.Dir=logs/p7-bench")), [&](IP7_Client *ptr) {
if (ptr)
ptr->Release();
});
if (!client)
{
std::cout << "Can't create IP7_Client" << std::endl;
return 1;
}
// create P7 trace object 1
std::unique_ptr<IP7_Trace, std::function<void(IP7_Trace *)>> trace(
P7_Create_Trace(client.get(), TM("Trace channel 1")), [&](IP7_Trace *ptr) {
if (ptr)
ptr->Release();
});
if (!trace)
{
std::cout << "Can't create IP7_Trace" << std::endl;
return 1;
}
trace->Register_Thread(TM("Application"), 0);
trace->Register_Module(TM("Main"), &module);
auto start = clock::now();
for (int i = 0; i < howmany; ++i)
trace->P7_INFO(module, TM("p7 message #%d: This is some text for your pleasure"), i);
duration<float> delta = clock::now() - start;
float deltaf = delta.count();
auto rate = howmany / deltaf;
std::cout << "Total: " << howmany << std::endl;
std::cout << "Delta = " << deltaf << " seconds" << std::endl;
std::cout << "Rate = " << rate << "/sec" << std::endl;
trace->Unregister_Thread(0);
return 0;
}

@ -0,0 +1,61 @@
//
// Copyright(c) 2015 Gabi Melman.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
//
#include <atomic>
#include <chrono>
#include <iostream>
#include <thread>
#include <vector>
#include "plog/Log.h"
using namespace std;
int main(int argc, char *argv[])
{
using namespace std::chrono;
using clock = steady_clock;
int thread_count = 10;
if (argc > 1)
thread_count = atoi(argv[1]);
int howmany = 1000000;
plog::init(plog::debug, "logs/plog-bench-mt.log");
std::atomic<int> msg_counter{0};
vector<thread> threads;
auto start = clock::now();
for (int t = 0; t < thread_count; ++t)
{
threads.push_back(std::thread([&]() {
while (true)
{
int counter = ++msg_counter;
if (counter > howmany)
break;
LOG_INFO << "plog message #" << counter << ": This is some text for your pleasure";
}
}));
}
for (auto &t : threads)
{
t.join();
}
duration<float> delta = clock::now() - start;
float deltaf = delta.count();
auto rate = howmany / deltaf;
std::cout << "Total: " << howmany << std::endl;
std::cout << "Threads: " << thread_count << std::endl;
std::cout << "Delta = " << deltaf << " seconds" << std::endl;
std::cout << "Rate = " << rate << "/sec" << std::endl;
return 0;
}

@ -0,0 +1,34 @@
//
// Copyright(c) 2015 Gabi Melman.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
//
#include <chrono>
#include <iostream>
#include <memory>
#include "plog/Log.h"
int main(int, char *[])
{
using namespace std::chrono;
using clock = steady_clock;
int howmany = 1000000;
plog::init(plog::debug, "logs/plog-bench.log");
auto start = clock::now();
for (int i = 0; i < howmany; ++i)
LOG_INFO << "plog message #" << i << ": This is some text for your pleasure";
duration<float> delta = clock::now() - start;
float deltaf = delta.count();
auto rate = howmany / deltaf;
std::cout << "Total: " << howmany << std::endl;
std::cout << "Delta = " << deltaf << " seconds" << std::endl;
std::cout << "Rate = " << rate << "/sec" << std::endl;
return 0;
}

@ -3,44 +3,53 @@
// Distributed under the MIT License (http://opensource.org/licenses/MIT) // Distributed under the MIT License (http://opensource.org/licenses/MIT)
// //
#include <thread>
#include <vector>
#include <atomic> #include <atomic>
#include <iostream>
#include <chrono> #include <chrono>
#include <cstdlib> #include <cstdlib>
#include <iostream>
#include <thread>
#include <vector>
#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;
int thread_count = 10; int thread_count = 10;
if (argc > 1) if (argc > 1)
thread_count = ::atoi(argv[1]); thread_count = std::atoi(argv[1]);
int howmany = 1000000; int howmany = 1000000;
spd::set_async_mode(1048576); spdlog::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<spdlog::sinks::simple_file_sink_mt>("file_logger", "logs/spdlog-bench-async.log", false);
logger->set_pattern("[%Y-%b-%d %T.%e]: %v"); logger->set_pattern("[%Y-%m-%d %T.%F]: %L %t %v");
std::cout << "To stop, press <Enter>" << std::endl;
std::atomic<bool> run{true};
std::thread stoper(std::thread([&run]() {
std::cin.get();
run = false;
}));
while (run)
{
std::atomic<int> msg_counter{0}; std::atomic<int> msg_counter{0};
vector<thread> threads; std::vector<std::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 #{}: This is some text for your pleasure", counter); logger->info("spdlog message #{}: This is some text for your pleasure", counter);
} }
})); }));
@ -49,14 +58,19 @@ int main(int argc, char* argv[])
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; std::cout << "Total: " << howmany << std::endl;
cout << "Threads: " << thread_count << std::endl; std::cout << "Threads: " << thread_count << std::endl;
std::cout << "Delta = " << deltaf << " seconds" << std::endl; std::cout << "Delta = " << std::fixed << deltaf << " seconds" << std::endl;
std::cout << "Rate = " << rate << "/sec" << std::endl; std::cout << "Rate = " << std::fixed << rate << "/sec" << std::endl;
} // while
stoper.join();
return 0;
} }

@ -3,17 +3,21 @@
// Distributed under the MIT License (http://opensource.org/licenses/MIT) // Distributed under the MIT License (http://opensource.org/licenses/MIT)
// //
#include <thread>
#include <vector>
#include <atomic> #include <atomic>
#include <chrono>
#include <cstdlib> #include <cstdlib>
#include "spdlog/spdlog.h" #include <iostream>
#include <thread>
#include <vector>
#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 clock = steady_clock;
int thread_count = 10; int thread_count = 10;
if (argc > 1) if (argc > 1)
@ -21,35 +25,39 @@ int main(int argc, char* argv[])
int howmany = 1000000; int howmany = 1000000;
namespace spd = spdlog; auto logger = spdlog::create<spdlog::sinks::simple_file_sink_mt>("file_logger", "logs/spdlog-bench-mt.log", false);
logger->set_pattern("[%Y-%m-%d %T.%F]: %L %t %v");
auto logger = spdlog::create<spd::sinks::simple_file_sink_mt>("file_logger", "logs/spd-bench-mt.txt", false);
logger->set_pattern("[%Y-%b-%d %T.%e]: %v");
std::atomic<int> msg_counter{0}; std::atomic<int> msg_counter{0};
std::vector<thread> threads; std::vector<thread> threads;
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 #{}: This is some text for your pleasure", counter); logger->info("spdlog message #{}: This is some text for your pleasure", counter);
} }
})); }));
} }
for (auto &t : threads) for (auto &t : threads)
{ {
t.join(); t.join();
}; }
duration<float> delta = clock::now() - start;
float deltaf = delta.count();
auto rate = howmany / deltaf;
std::cout << "Total: " << howmany << std::endl;
std::cout << "Threads: " << thread_count << std::endl;
std::cout << "Delta = " << std::fixed << deltaf << " seconds" << std::endl;
std::cout << "Rate = " << std::fixed << rate << "/sec" << std::endl;
return 0; return 0;
} }

@ -3,18 +3,32 @@
// Distributed under the MIT License (http://opensource.org/licenses/MIT) // Distributed under the MIT License (http://opensource.org/licenses/MIT)
// //
#include "spdlog/spdlog.h" #include <chrono>
#include <iostream>
#include "spdlog/spdlog.h"
int main(int, char *[]) int main(int, char *[])
{ {
using namespace std::chrono;
using clock = steady_clock;
int howmany = 1000000; int howmany = 1000000;
namespace spd = spdlog;
///Create a file rotating logger with 5mb size max and 3 rotated files
auto logger = spdlog::create<spd::sinks::simple_file_sink_st>("file_logger", "logs/spd-bench-st.txt", false);
logger->set_pattern("[%Y-%b-%d %T.%e]: %v"); auto logger = spdlog::create<spdlog::sinks::simple_file_sink_st>("file_logger", "logs/spdlog-bench.log", false);
logger->set_pattern("[%Y-%m-%d %T.%F]: %L %v");
auto start = clock::now();
for (int i = 0; i < howmany; ++i) for (int i = 0; i < howmany; ++i)
logger->info("spdlog message #{} : This is some text for your pleasure", i); logger->info("spdlog message #{} : This is some text for your pleasure", i);
duration<float> delta = clock::now() - start;
float deltaf = delta.count();
auto rate = howmany / deltaf;
std::cout << "Total: " << howmany << std::endl;
std::cout << "Delta = " << std::fixed << deltaf << " seconds" << std::endl;
std::cout << "Rate = " << std::fixed << rate << "/sec" << std::endl;
return 0; return 0;
} }

@ -6,17 +6,16 @@
// //
// bench.cpp : spdlog benchmarks // bench.cpp : spdlog benchmarks
// //
#include "spdlog/async_logger.h"
#include "spdlog/sinks/null_sink.h"
#include "spdlog/spdlog.h"
#include "utils.h"
#include <atomic> #include <atomic>
#include <cstdlib> // EXIT_FAILURE #include <cstdlib> // EXIT_FAILURE
#include <iostream> #include <iostream>
#include <memory> #include <memory>
#include <string> #include <string>
#include <thread> #include <thread>
#include "spdlog/spdlog.h"
#include "spdlog/async_logger.h"
#include "spdlog/sinks/null_sink.h"
#include "utils.h"
using namespace std; using namespace std;
using namespace std::chrono; using namespace std::chrono;
@ -24,8 +23,6 @@ using namespace spdlog;
using namespace spdlog::sinks; using namespace spdlog::sinks;
using namespace utils; using namespace utils;
size_t bench_as(int howmany, std::shared_ptr<spdlog::logger> log, int thread_count); size_t bench_as(int howmany, std::shared_ptr<spdlog::logger> log, int thread_count);
int main(int argc, char *argv[]) int main(int argc, char *argv[])
@ -46,7 +43,6 @@ int main(int argc, char* argv[])
if (argc > 3) if (argc > 3)
queue_size = atoi(argv[3]); queue_size = atoi(argv[3]);
cout << "\n*******************************************************************************\n"; cout << "\n*******************************************************************************\n";
cout << "async logging.. " << threads << " threads sharing same logger, " << format(howmany) << " messages " << endl; cout << "async logging.. " << threads << " threads sharing same logger, " << format(howmany) << " messages " << endl;
cout << "*******************************************************************************\n"; cout << "*******************************************************************************\n";
@ -64,7 +60,6 @@ int main(int argc, char* argv[])
} }
std::cout << endl; std::cout << endl;
std::cout << "Avg rate: " << format(total_rate / iters) << "/sec" << std::endl; std::cout << "Avg rate: " << format(total_rate / iters) << "/sec" << std::endl;
} }
catch (std::exception &ex) catch (std::exception &ex)
{ {
@ -75,8 +70,6 @@ int main(int argc, char* argv[])
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }
// return rate/sec // return rate/sec
size_t bench_as(int howmany, std::shared_ptr<spdlog::logger> log, int thread_count) size_t bench_as(int howmany, std::shared_ptr<spdlog::logger> log, int thread_count)
{ {
@ -86,23 +79,21 @@ size_t bench_as(int howmany, std::shared_ptr<spdlog::logger> log, int thread_cou
auto start = system_clock::now(); auto start = system_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([&]() {
{
for (;;) for (;;)
{ {
int counter = ++msg_counter; int counter = ++msg_counter;
if (counter > howmany) break; if (counter > howmany)
break;
log->info("Hello logger: msg number {}", counter); log->info("Hello logger: msg number {}", counter);
} }
})); }));
} }
for (auto &t : threads) for (auto &t : threads)
{ {
t.join(); t.join();
}; }
auto delta = system_clock::now() - start; auto delta = system_clock::now() - start;
auto delta_d = duration_cast<duration<double>>(delta).count(); auto delta_d = duration_cast<duration<double>>(delta).count();

@ -5,12 +5,11 @@
#pragma once #pragma once
#include <sstream>
#include <iomanip> #include <iomanip>
#include <locale> #include <locale>
#include <sstream>
namespace utils namespace utils {
{
template<typename T> template<typename T>
inline std::string format(const T &value) inline std::string format(const T &value)
@ -32,4 +31,4 @@ inline std::string format(const double & value)
return ss.str(); return ss.str();
} }
} } // namespace utils

@ -1,4 +1,4 @@
CXX ?= clang++ CXX = clang++
CXXFLAGS = -march=native -Wall -Wextra -Wshadow -pedantic -std=c++11 -pthread -I../include CXXFLAGS = -march=native -Wall -Wextra -Wshadow -pedantic -std=c++11 -pthread -I../include
CXX_RELEASE_FLAGS = -O2 CXX_RELEASE_FLAGS = -O2
CXX_DEBUG_FLAGS= -g CXX_DEBUG_FLAGS= -g

@ -6,18 +6,17 @@
// //
// bench.cpp : spdlog benchmarks // bench.cpp : spdlog benchmarks
// //
#include "spdlog/async_logger.h"
#include "spdlog/sinks/file_sinks.h"
#include "spdlog/sinks/null_sink.h"
#include "spdlog/spdlog.h"
#include "utils.h"
#include <atomic> #include <atomic>
#include <cstdlib> // EXIT_FAILURE #include <cstdlib> // EXIT_FAILURE
#include <iostream> #include <iostream>
#include <memory> #include <memory>
#include <string> #include <string>
#include <thread> #include <thread>
#include "spdlog/spdlog.h"
#include "spdlog/async_logger.h"
#include "spdlog/sinks/file_sinks.h"
#include "spdlog/sinks/null_sink.h"
#include "utils.h"
using namespace std; using namespace std;
using namespace std::chrono; using namespace std::chrono;
@ -25,7 +24,6 @@ using namespace spdlog;
using namespace spdlog::sinks; using namespace spdlog::sinks;
using namespace utils; using namespace utils;
void bench(int howmany, std::shared_ptr<spdlog::logger> log); void bench(int howmany, std::shared_ptr<spdlog::logger> log);
void bench_mt(int howmany, std::shared_ptr<spdlog::logger> log, int thread_count); void bench_mt(int howmany, std::shared_ptr<spdlog::logger> log, int thread_count);
@ -48,14 +46,13 @@ int main(int argc, char* argv[])
if (argc > 3) if (argc > 3)
queue_size = atoi(argv[3]); queue_size = atoi(argv[3]);
cout << "*******************************************************************************\n"; cout << "*******************************************************************************\n";
cout << "Single thread, " << format(howmany) << " iterations" << endl; cout << "Single thread, " << format(howmany) << " iterations" << endl;
cout << "*******************************************************************************\n"; cout << "*******************************************************************************\n";
auto rotating_st = spdlog::rotating_logger_st("rotating_st", "logs/rotating_st", file_size, rotating_files); auto rotating_st = spdlog::rotating_logger_st("rotating_st", "logs/rotating_st.log", file_size, rotating_files);
bench(howmany, rotating_st); bench(howmany, rotating_st);
auto daily_st = spdlog::daily_logger_st("daily_st", "logs/daily_st"); auto daily_st = spdlog::daily_logger_st("daily_st", "logs/daily_st.log");
bench(howmany, daily_st); bench(howmany, daily_st);
bench(howmany, spdlog::create<null_sink_st>("null_st")); bench(howmany, spdlog::create<null_sink_st>("null_st"));
@ -63,11 +60,10 @@ int main(int argc, char* argv[])
cout << threads << " threads sharing same logger, " << format(howmany) << " iterations" << endl; cout << threads << " threads sharing same logger, " << format(howmany) << " iterations" << endl;
cout << "*******************************************************************************\n"; cout << "*******************************************************************************\n";
auto rotating_mt = spdlog::rotating_logger_mt("rotating_mt", "logs/rotating_mt", file_size, rotating_files); auto rotating_mt = spdlog::rotating_logger_mt("rotating_mt", "logs/rotating_mt.log", file_size, rotating_files);
bench_mt(howmany, rotating_mt, threads); bench_mt(howmany, rotating_mt, threads);
auto daily_mt = spdlog::daily_logger_mt("daily_mt", "logs/daily_mt.log");
auto daily_mt = spdlog::daily_logger_mt("daily_mt", "logs/daily_mt");
bench_mt(howmany, daily_mt, threads); bench_mt(howmany, daily_mt, threads);
bench(howmany, spdlog::create<null_sink_st>("null_mt")); bench(howmany, spdlog::create<null_sink_st>("null_mt"));
@ -75,12 +71,11 @@ int main(int argc, char* argv[])
cout << "async logging.. " << threads << " threads sharing same logger, " << format(howmany) << " iterations " << endl; cout << "async logging.. " << threads << " threads sharing same logger, " << format(howmany) << " iterations " << endl;
cout << "*******************************************************************************\n"; cout << "*******************************************************************************\n";
spdlog::set_async_mode(queue_size); spdlog::set_async_mode(queue_size);
for (int i = 0; i < 3; ++i) for (int i = 0; i < 3; ++i)
{ {
auto as = spdlog::daily_logger_st("as", "logs/daily_async"); auto as = spdlog::daily_logger_st("as", "logs/daily_async.log");
bench_mt(howmany, as, threads); bench_mt(howmany, as, threads);
spdlog::drop("as"); spdlog::drop("as");
} }
@ -94,7 +89,6 @@ int main(int argc, char* argv[])
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }
void bench(int howmany, std::shared_ptr<spdlog::logger> log) void bench(int howmany, std::shared_ptr<spdlog::logger> log)
{ {
cout << log->name() << "...\t\t" << flush; cout << log->name() << "...\t\t" << flush;
@ -104,13 +98,11 @@ void bench(int howmany, std::shared_ptr<spdlog::logger> log)
log->info("Hello logger: msg number {}", i); log->info("Hello logger: msg number {}", i);
} }
auto delta = system_clock::now() - start; auto delta = system_clock::now() - start;
auto delta_d = duration_cast<duration<double>>(delta).count(); auto delta_d = duration_cast<duration<double>>(delta).count();
cout << format(int(howmany / delta_d)) << "/sec" << endl; cout << format(int(howmany / delta_d)) << "/sec" << endl;
} }
void bench_mt(int howmany, std::shared_ptr<spdlog::logger> log, int thread_count) void bench_mt(int howmany, std::shared_ptr<spdlog::logger> log, int thread_count)
{ {
@ -120,24 +112,22 @@ void bench_mt(int howmany, std::shared_ptr<spdlog::logger> log, int thread_count
auto start = system_clock::now(); auto start = system_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([&]() {
{
for (;;) for (;;)
{ {
int counter = ++msg_counter; int counter = ++msg_counter;
if (counter > howmany) break; if (counter > howmany)
break;
log->info("Hello logger: msg number {}", counter); log->info("Hello logger: msg number {}", counter);
} }
})); }));
} }
for (auto &t : threads) for (auto &t : threads)
{ {
t.join(); t.join();
}; };
auto delta = system_clock::now() - start; auto delta = system_clock::now() - start;
auto delta_d = duration_cast<duration<double>>(delta).count(); auto delta_d = duration_cast<duration<double>>(delta).count();
cout << format(int(howmany / delta_d)) << "/sec" << endl; cout << format(int(howmany / delta_d)) << "/sec" << endl;

@ -31,7 +31,6 @@ int main(int, char*[])
console->info("Welcome to spdlog!"); console->info("Welcome to spdlog!");
console->error("Some error message with arg{}..", 1); console->error("Some error message with arg{}..", 1);
// Formatting examples // Formatting examples
console->warn("Easy padding in numbers like {:08d}", 12); console->warn("Easy padding in numbers like {:08d}", 12);
console->critical("Support for int: {0:d}; hex: {0:x}; oct: {0:o}; bin: {0:b}", 42); console->critical("Support for int: {0:d}; hex: {0:x}; oct: {0:o}; bin: {0:b}", 42);
@ -41,7 +40,6 @@ int main(int, char*[])
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");
// Create basic file logger (not rotated) // Create basic file logger (not rotated)
auto my_logger = spd::basic_logger_mt("basic_logger", "logs/basic-log.txt"); auto my_logger = spd::basic_logger_mt("basic_logger", "logs/basic-log.txt");
my_logger->info("Some log message"); my_logger->info("Some log message");
@ -49,7 +47,9 @@ int main(int, char*[])
// 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 rotating_logger = spd::rotating_logger_mt("some_logger_name", "logs/rotating.txt", 1048576 * 5, 3); auto rotating_logger = spd::rotating_logger_mt("some_logger_name", "logs/rotating.txt", 1048576 * 5, 3);
for (int i = 0; i < 10; ++i) for (int i = 0; i < 10; ++i)
{
rotating_logger->info("{} * {} equals {:>10}", i, i, i * i); rotating_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.txt", 2, 30); auto daily_logger = spd::daily_logger_mt("daily_logger", "logs/daily.txt", 2, 30);
@ -58,9 +58,9 @@ int main(int, char*[])
daily_logger->info(123.44); daily_logger->info(123.44);
// 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");
rotating_logger->info("This is another message with custom format"); console->info("This an info message with custom format");
console->error("This an error message with custom format");
// 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
@ -73,7 +73,6 @@ int main(int, char*[])
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();
@ -91,10 +90,7 @@ int main(int, char*[])
err_handler_example(); err_handler_example();
// Apply a function on all registered loggers // Apply a function on all registered loggers
spd::apply_all([&](std::shared_ptr<spdlog::logger> l) spd::apply_all([&](std::shared_ptr<spdlog::logger> l) { l->info("End of example."); });
{
l->info("End of example.");
});
// Release and close all loggers // Release and close all loggers
spdlog::drop_all(); spdlog::drop_all();
@ -113,8 +109,10 @@ void async_example()
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/freebsd) // syslog example (linux/osx/freebsd)
void syslog_example() void syslog_example()
@ -159,9 +157,6 @@ void user_defined_example()
void err_handler_example() void err_handler_example()
{ {
// can be set globaly or per logger(logger->set_error_handler(..)) // can be set globaly or per logger(logger->set_error_handler(..))
spdlog::set_error_handler([](const std::string& msg) spdlog::set_error_handler([](const std::string &msg) { std::cerr << "my err handler: " << msg << std::endl; });
{
std::cerr << "my err handler: " << msg << std::endl;
});
spd::get("console")->info("some invalid message to trigger an error {}{}{}{}", 3); spd::get("console")->info("some invalid message to trigger an error {}{}{}{}", 3);
} }

@ -1 +0,0 @@
../example.cpp

@ -0,0 +1,157 @@
//
// Copyright(c) 2015 Gabi Melman.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
//
//
// spdlog usage example
//
//
#define SPDLOG_TRACE_ON
#define SPDLOG_DEBUG_ON
#include "spdlog/spdlog.h"
#include <iostream>
#include <memory>
void async_example();
void syslog_example();
void android_example();
void user_defined_example();
void err_handler_example();
namespace spd = spdlog;
int main(int, char *[])
{
try
{
// Console logger with color
auto console = spd::stdout_color_mt("console");
console->info("Welcome to spdlog!");
console->error("Some error message with arg{}..", 1);
// Formatting examples
console->warn("Easy padding in numbers like {:08d}", 12);
console->critical("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("Positional args are {1} {0}..", "too", "supported");
console->info("{:<30}", "left aligned");
spd::get("console")->info("loggers can be retrieved from a global registry using the spdlog::get(logger_name) function");
// Create basic file logger (not rotated)
auto my_logger = spd::basic_logger_mt("basic_logger", "logs/basic-log.txt");
my_logger->info("Some log message");
// Create a file rotating logger with 5mb size max and 3 rotated files
auto rotating_logger = spd::rotating_logger_mt("some_logger_name", "logs/rotating.txt", 1048576 * 5, 3);
for (int i = 0; i < 10; ++i)
rotating_logger->info("{} * {} equals {:>10}", i, i, i * i);
// Create a daily logger - a new file is created every day on 2:30am
auto daily_logger = spd::daily_logger_mt("daily_logger", "logs/daily.txt", 2, 30);
// trigger flush if the log severity is error or higher
daily_logger->flush_on(spd::level::err);
daily_logger->info(123.44);
// Customize msg format for all messages
spd::set_pattern("*** [%H:%M:%S %z] [thread %t] %v ***");
rotating_logger->info("This is another message with custom format");
// Runtime log levels
spd::set_level(spd::level::info); // Set global log level to info
console->debug("This message should not be displayed!");
console->set_level(spd::level::debug); // Set specific logger's log level
console->debug("This message should be displayed..");
// Compile time log levels
// define SPDLOG_DEBUG_ON or SPDLOG_TRACE_ON
SPDLOG_TRACE(console, "Enabled only #ifdef SPDLOG_TRACE_ON..{} ,{}", 1, 3.23);
SPDLOG_DEBUG(console, "Enabled only #ifdef SPDLOG_DEBUG_ON.. {} ,{}", 1, 3.23);
// Asynchronous logging is very fast..
// Just call spdlog::set_async_mode(q_size) and all created loggers from now on will be asynchronous..
async_example();
// syslog example. linux/osx only
syslog_example();
// android example. compile with NDK
android_example();
// Log user-defined types example
user_defined_example();
// Change default log error handler
err_handler_example();
// Apply a function on all registered loggers
spd::apply_all([&](std::shared_ptr<spdlog::logger> l) { l->info("End of example."); });
// Release and close all loggers
spdlog::drop_all();
}
// Exceptions will only be thrown upon failed logger or sink construction (not during logging)
catch (const spd::spdlog_ex &ex)
{
std::cout << "Log init failed: " << ex.what() << std::endl;
return 1;
}
}
void async_example()
{
size_t q_size = 4096; // queue size must be power of 2
spdlog::set_async_mode(q_size);
auto async_file = spd::daily_logger_st("async_file_logger", "logs/async_log.txt");
for (int i = 0; i < 100; ++i)
async_file->info("Async message #{}", i);
}
// syslog example (linux/osx/freebsd)
void syslog_example()
{
#ifdef SPDLOG_ENABLE_SYSLOG
std::string ident = "spdlog-example";
auto syslog_logger = spd::syslog_logger("syslog", ident, LOG_PID);
syslog_logger->warn("This is warning that will end up in syslog.");
#endif
}
// Android example
void android_example()
{
#if defined(__ANDROID__)
std::string tag = "spdlog-android";
auto android_logger = spd::android_logger("android", tag);
android_logger->critical("Use \"adb shell logcat\" to view this message.");
#endif
}
// user defined types logging by implementing operator<<
struct my_type
{
int i;
template<typename OStream>
friend OStream &operator<<(OStream &os, const my_type &c)
{
return os << "[my_type i=" << c.i << "]";
}
};
#include "spdlog/fmt/ostr.h" // must be included
void user_defined_example()
{
spd::get("console")->info("user defined type: {}", my_type{14});
}
//
// custom error handler
//
void err_handler_example()
{
// can be set globaly or per logger(logger->set_error_handler(..))
spdlog::set_error_handler([](const std::string &msg) { std::cerr << "my err handler: " << msg << std::endl; });
spd::get("console")->info("some invalid message to trigger an error {}{}{}{}", 3);
}

@ -44,4 +44,3 @@ int main(int, char*[])
return 1; return 1;
} }
} }

@ -5,12 +5,11 @@
#pragma once #pragma once
#include <sstream>
#include <iomanip> #include <iomanip>
#include <locale> #include <locale>
#include <sstream>
namespace utils namespace utils {
{
template<typename T> template<typename T>
inline std::string format(const T &value) inline std::string format(const T &value)
@ -32,4 +31,4 @@ inline std::string format(const double & value)
return ss.str(); return ss.str();
} }
} } // namespace utils

@ -0,0 +1,9 @@
#!/bin/bash
echo -n "Running dos2unix "
find . -name "*\.h" -o -name "*\.cpp"|xargs -I {} sh -c "dos2unix '{}' 2>/dev/null; echo -n '.'"
echo
echo -n "Running clang-format "
find . -name "*\.h" -o -name "*\.cpp"|xargs -I {} sh -c "clang-format -i {}; echo -n '.'"
echo

@ -20,14 +20,12 @@
#include <chrono> #include <chrono>
#include <functional> #include <functional>
#include <string>
#include <memory> #include <memory>
#include <string>
namespace spdlog namespace spdlog {
{
namespace details namespace details {
{
class async_log_helper; class async_log_helper;
} }
@ -35,26 +33,19 @@ class async_logger SPDLOG_FINAL : public logger
{ {
public: public:
template<class It> template<class It>
async_logger(const std::string& logger_name, async_logger(const std::string &logger_name, const It &begin, const It &end, size_t queue_size,
const It& begin,
const It& end,
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(),
const std::function<void()> &worker_teardown_cb = nullptr); const std::function<void()> &worker_teardown_cb = nullptr);
async_logger(const std::string& logger_name, async_logger(const std::string &logger_name, sinks_init_list sinks, size_t queue_size,
sinks_init_list sinks,
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(),
const std::function<void()> &worker_teardown_cb = nullptr); const std::function<void()> &worker_teardown_cb = nullptr);
async_logger(const std::string& logger_name, async_logger(const std::string &logger_name, sink_ptr single_sink, size_t queue_size,
sink_ptr single_sink,
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(),
@ -76,6 +67,6 @@ protected:
private: private:
std::unique_ptr<details::async_log_helper> _async_log_helper; std::unique_ptr<details::async_log_helper> _async_log_helper;
}; };
} } // namespace spdlog
#include "details/async_logger_impl.h" #include "details/async_logger_impl.h"

@ -5,17 +5,18 @@
#pragma once #pragma once
#define SPDLOG_VERSION "0.16.3" #define SPDLOG_VERSION "0.16.4-rc"
#include "tweakme.h" #include "tweakme.h"
#include <string>
#include <initializer_list>
#include <chrono>
#include <memory>
#include <atomic> #include <atomic>
#include <chrono>
#include <exception> #include <exception>
#include <functional> #include <functional>
#include <initializer_list>
#include <memory>
#include <string>
#include <unordered_map>
#if defined(_WIN32) && defined(SPDLOG_WCHAR_FILENAMES) #if defined(_WIN32) && defined(SPDLOG_WCHAR_FILENAMES)
#include <codecvt> #include <codecvt>
@ -50,13 +51,11 @@
#include "fmt/fmt.h" #include "fmt/fmt.h"
namespace spdlog namespace spdlog {
{
class formatter; class formatter;
namespace sinks namespace sinks {
{
class sink; class sink;
} }
@ -73,8 +72,7 @@ using level_t = std::atomic<int>;
using log_err_handler = std::function<void(const std::string &err_msg)>; using log_err_handler = std::function<void(const std::string &err_msg)>;
// Log level enum // Log level enum
namespace level namespace level {
{
enum level_enum enum level_enum
{ {
trace = 0, trace = 0,
@ -87,7 +85,10 @@ enum level_enum
}; };
#if !defined(SPDLOG_LEVEL_NAMES) #if !defined(SPDLOG_LEVEL_NAMES)
#define SPDLOG_LEVEL_NAMES { "trace", "debug", "info", "warning", "error", "critical", "off" } #define SPDLOG_LEVEL_NAMES \
{ \
"trace", "debug", "info", "warning", "error", "critical", "off" \
}
#endif #endif
static const char *level_names[] SPDLOG_LEVEL_NAMES; static const char *level_names[] SPDLOG_LEVEL_NAMES;
@ -102,9 +103,23 @@ inline const char* to_short_str(spdlog::level::level_enum l)
{ {
return short_level_names[l]; return short_level_names[l];
} }
using level_hasher = std::hash<int>; inline spdlog::level::level_enum from_str(const std::string &name)
{
static std::unordered_map<std::string, level_enum> name_to_level = // map string->level
{{level_names[0], level::trace}, // trace
{level_names[1], level::debug}, // debug
{level_names[2], level::info}, // info
{level_names[3], level::warn}, // warn
{level_names[4], level::err}, // err
{level_names[5], level::critical}, // critical
{level_names[6], level::off}}; // off
auto lvl_it = name_to_level.find(name);
return lvl_it != name_to_level.end() ? lvl_it->second : level::off;
}
} //level using level_hasher = std::hash<int>;
} // namespace level
// //
// Async overflow policy - block by default. // Async overflow policy - block by default.
@ -128,18 +143,18 @@ enum class pattern_time_type
// //
// Log exception // Log exception
// //
namespace details namespace details {
{ namespace os {
namespace os
{
std::string errno_str(int err_num); std::string errno_str(int err_num);
} }
} } // namespace details
class spdlog_ex : public std::exception class spdlog_ex : public std::exception
{ {
public: public:
explicit spdlog_ex(std::string msg) : _msg(std::move(msg)) explicit spdlog_ex(std::string msg)
{} : _msg(std::move(msg))
{
}
spdlog_ex(const std::string &msg, int last_errno) spdlog_ex(const std::string &msg, int last_errno)
{ {
@ -164,4 +179,4 @@ using filename_t = std::wstring;
using filename_t = std::string; using filename_t = std::string;
#endif #endif
} //spdlog } // namespace spdlog

@ -0,0 +1 @@
Please put here your contribs. Popular contribs will be moved to main tree after stablization

@ -0,0 +1,161 @@
#pragma once
#include "../../details/file_helper.h"
#include "../../details/null_mutex.h"
#include "../../fmt/fmt.h"
#include "../../sinks/base_sink.h"
#include <algorithm>
#include <cerrno>
#include <chrono>
#include <cstdio>
#include <ctime>
#include <mutex>
#include <string>
// Example for spdlog.h
//
// Create a file logger which creates new files with a specified time step and fixed file size:
//
// std::shared_ptr<logger> step_logger_mt(const std::string &logger_name, const filename_t &filename, unsigned seconds = 60, const filename_t &tmp_ext = ".tmp", unsigned max_file_size = std::numeric_limits<unsigned>::max());
// std::shared_ptr<logger> step_logger_st(const std::string &logger_name, const filename_t &filename, unsigned seconds = 60, const filename_t &tmp_ext = ".tmp", unsigned max_file_size = std::numeric_limits<unsigned>::max();;
// Example for spdlog_impl.h
// Create a file logger that creates new files with a specified increment
// inline std::shared_ptr<spdlog::logger> spdlog::step_logger_mt(
// const std::string &logger_name, const filename_t &filename_fmt, unsigned seconds, const filename_t &tmp_ext, unsigned max_file_size)
// {
// return create<spdlog::sinks::step_file_sink_mt>(logger_name, filename_fmt, seconds, tmp_ext, max_file_size);
// }
// inline std::shared_ptr<spdlog::logger> spdlog::step_logger_st(
// const std::string &logger_name, const filename_t &filename_fmt, unsigned seconds, const filename_t &tmp_ext, unsigned max_file_size)
// {
// return create<spdlog::sinks::step_file_sink_st>(logger_name, filename_fmt, seconds, tmp_ext, max_file_size);
// }
namespace spdlog {
namespace sinks {
/*
* Default generator of step log file names.
*/
struct default_step_file_name_calculator
{
// Create filename for the form filename_YYYY-MM-DD_hh-mm-ss.ext
static std::tuple<filename_t, filename_t> calc_filename(const filename_t &filename, const filename_t &tmp_ext)
{
std::tm tm = spdlog::details::os::localtime();
filename_t basename, ext;
std::tie(basename, ext) = details::file_helper::split_by_extenstion(filename);
std::conditional<std::is_same<filename_t::value_type, char>::value, fmt::MemoryWriter, fmt::WMemoryWriter>::type w;
w.write(SPDLOG_FILENAME_T("{}_{:04d}-{:02d}-{:02d}_{:02d}-{:02d}-{:02d}{}"), basename, tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
tm.tm_hour, tm.tm_min, tm.tm_sec, tmp_ext);
return std::make_tuple(w.str(), ext);
}
};
/*
* Rotating file sink based on size and a specified time step
*/
template<class Mutex, class FileNameCalc = default_step_file_name_calculator>
class step_file_sink SPDLOG_FINAL : public base_sink<Mutex>
{
public:
step_file_sink(filename_t base_filename, unsigned step_seconds, filename_t tmp_ext, unsigned max_size)
: _base_filename(std::move(base_filename))
, _tmp_ext(std::move(tmp_ext))
, _step_seconds(step_seconds)
, _max_size(max_size)
{
if (step_seconds == 0)
{
throw spdlog_ex("step_file_sink: Invalid time step in ctor");
}
if (max_size == 0)
{
throw spdlog_ex("step_file_sink: Invalid max log size in ctor");
}
_tp = _next_tp();
std::tie(_current_filename, _ext) = FileNameCalc::calc_filename(_base_filename, _tmp_ext);
if (_tmp_ext == _ext)
{
throw spdlog_ex("step_file_sink: The temporary extension matches the specified in ctor");
}
_file_helper.open(_current_filename);
_current_size = _file_helper.size(); // expensive. called only once
}
~step_file_sink()
{
using details::os::filename_to_str;
filename_t src =_current_filename, target;
std::tie(target, std::ignore) = details::file_helper::split_by_extenstion(src);
target += _ext;
details::os::rename(src, target);
}
protected:
void _sink_it(const details::log_msg &msg) override
{
_current_size += msg.formatted.size();
if (std::chrono::system_clock::now() >= _tp || _current_size > _max_size)
{
close_current_file();
std::tie(_current_filename, std::ignore) = FileNameCalc::calc_filename(_base_filename, _tmp_ext);
_file_helper.open(_current_filename);
_tp = _next_tp();
_current_size = msg.formatted.size();
}
_file_helper.write(msg);
}
void _flush() override
{
_file_helper.flush();
}
private:
std::chrono::system_clock::time_point _next_tp()
{
return std::chrono::system_clock::now() + _step_seconds;
}
void close_current_file()
{
using details::os::filename_to_str;
filename_t src =_current_filename, target;
std::tie(target, std::ignore) = details::file_helper::split_by_extenstion(src);
target += _ext;
if (details::file_helper::file_exists(src) && details::os::rename(src, target) != 0)
{
throw spdlog_ex("step_file_sink: failed renaming " + filename_to_str(src) + " to " + filename_to_str(target), errno);
}
}
const filename_t _base_filename;
const filename_t _tmp_ext;
const std::chrono::seconds _step_seconds;
const unsigned _max_size;
std::chrono::system_clock::time_point _tp;
filename_t _current_filename;
filename_t _ext;
unsigned _current_size;
details::file_helper _file_helper;
};
using step_file_sink_mt = step_file_sink<std::mutex>;
using step_file_sink_st = step_file_sink<details::null_mutex>;
} // namespace sinks
} // namespace spdlog

@ -13,11 +13,11 @@
#pragma once #pragma once
#include "../common.h" #include "../common.h"
#include "../sinks/sink.h"
#include "../details/mpmc_bounded_q.h"
#include "../details/log_msg.h" #include "../details/log_msg.h"
#include "../details/mpmc_bounded_q.h"
#include "../details/os.h" #include "../details/os.h"
#include "../formatter.h" #include "../formatter.h"
#include "../sinks/sink.h"
#include <chrono> #include <chrono>
#include <exception> #include <exception>
@ -28,10 +28,8 @@
#include <utility> #include <utility>
#include <vector> #include <vector>
namespace spdlog namespace spdlog {
{ namespace details {
namespace details
{
class async_log_helper class async_log_helper
{ {
@ -57,22 +55,23 @@ class async_log_helper
async_msg() = default; async_msg() = default;
~async_msg() = default; ~async_msg() = default;
explicit async_msg(async_msg_type m_type) : explicit async_msg(async_msg_type m_type)
level(level::info), : level(level::info)
thread_id(0), , thread_id(0)
msg_type(m_type), , msg_type(m_type)
msg_id(0) , msg_id(0)
{} {
}
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)),
thread_id(other.thread_id), thread_id(other.thread_id),
txt(std::move(other.txt)), txt(std::move(other.txt)),
msg_type(std::move(other.msg_type)), msg_type(std::move(other.msg_type)),
msg_id(other.msg_id) msg_id(other.msg_id)
{} {
}
async_msg &operator=(async_msg &&other) SPDLOG_NOEXCEPT async_msg &operator=(async_msg &&other) SPDLOG_NOEXCEPT
{ {
@ -91,13 +90,13 @@ async_msg(async_msg&& other) SPDLOG_NOEXCEPT :
async_msg &operator=(const async_msg &other) = delete; async_msg &operator=(const async_msg &other) = delete;
// construct from log_msg // construct from log_msg
explicit async_msg(const details::log_msg& m): explicit async_msg(const details::log_msg &m)
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)
msg_id(m.msg_id) , msg_id(m.msg_id)
{ {
#ifndef SPDLOG_NO_NAME #ifndef SPDLOG_NO_NAME
logger_name = *m.logger_name; logger_name = *m.logger_name;
@ -122,12 +121,8 @@ public:
using clock = std::chrono::steady_clock; using clock = std::chrono::steady_clock;
async_log_helper(formatter_ptr formatter, async_log_helper(formatter_ptr formatter, std::vector<sink_ptr> sinks, size_t queue_size, const log_err_handler err_handler,
std::vector<sink_ptr> sinks, const async_overflow_policy overflow_policy = async_overflow_policy::block_retry, std::function<void()> worker_warmup_cb = nullptr,
size_t queue_size,
const log_err_handler err_handler,
const async_overflow_policy overflow_policy = async_overflow_policy::block_retry,
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(),
std::function<void()> worker_teardown_cb = nullptr); std::function<void()> worker_teardown_cb = nullptr);
@ -189,33 +184,26 @@ private:
// wait until the queue is empty // wait until the queue is empty
void wait_empty_q(); void wait_empty_q();
}; };
} } // namespace details
} } // namespace spdlog
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// 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, std::vector<sink_ptr> sinks, size_t queue_size,
formatter_ptr formatter, log_err_handler err_handler, const async_overflow_policy overflow_policy, std::function<void()> worker_warmup_cb,
std::vector<sink_ptr> sinks, const std::chrono::milliseconds &flush_interval_ms, std::function<void()> worker_teardown_cb)
size_t queue_size, : _formatter(std::move(formatter))
log_err_handler err_handler, , _sinks(std::move(sinks))
const async_overflow_policy overflow_policy, , _q(queue_size)
std::function<void()> worker_warmup_cb, , _err_handler(std::move(err_handler))
const std::chrono::milliseconds& flush_interval_ms, , _flush_requested(false)
std::function<void()> worker_teardown_cb): , _terminate_requested(false)
_formatter(std::move(formatter)), , _overflow_policy(overflow_policy)
_sinks(std::move(sinks)), , _worker_warmup_cb(std::move(worker_warmup_cb))
_q(queue_size), , _flush_interval_ms(flush_interval_ms)
_err_handler(std::move(err_handler)), , _worker_teardown_cb(std::move(worker_teardown_cb))
_flush_requested(false),
_terminate_requested(false),
_overflow_policy(overflow_policy),
_worker_warmup_cb(std::move(worker_warmup_cb)),
_flush_interval_ms(flush_interval_ms),
_worker_teardown_cb(std::move(worker_teardown_cb))
{ {
_worker_thread = std::thread(&async_log_helper::worker_loop, this); _worker_thread = std::thread(&async_log_helper::worker_loop, this);
} }
@ -234,7 +222,6 @@ inline spdlog::details::async_log_helper::~async_log_helper()
} }
} }
// Try to push and block until succeeded (if the policy is not to discard when the queue is full) // Try to push and block until succeeded (if the policy is not to discard when the queue is full)
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)
{ {
@ -251,8 +238,7 @@ inline void spdlog::details::async_log_helper::push_msg(details::async_log_helpe
{ {
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)));
} }
} }
@ -261,12 +247,17 @@ inline void spdlog::details::async_log_helper::flush(bool wait_for_q)
{ {
push_msg(async_msg(async_msg_type::flush)); push_msg(async_msg(async_msg_type::flush));
if (wait_for_q) if (wait_for_q)
{
wait_empty_q(); // return when queue is empty wait_empty_q(); // return when queue is empty
} }
}
inline void spdlog::details::async_log_helper::worker_loop() inline void spdlog::details::async_log_helper::worker_loop()
{ {
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;
auto active = true; auto active = true;
@ -285,9 +276,10 @@ inline void spdlog::details::async_log_helper::worker_loop()
_err_handler("Unknown exeption in async logger worker loop."); _err_handler("Unknown exeption in async logger worker loop.");
} }
} }
if (_worker_teardown_cb) _worker_teardown_cb(); if (_worker_teardown_cb)
{
_worker_teardown_cb();
}
} }
// process next message in the queue // process next message in the queue
@ -336,11 +328,14 @@ inline bool spdlog::details::async_log_helper::process_next_msg(log_clock::time_
// flush all sinks if _flush_interval_ms has expired // flush all sinks if _flush_interval_ms has expired
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;
} }
@ -352,24 +347,31 @@ inline void spdlog::details::async_log_helper::set_formatter(formatter_ptr msg_f
} }
// spin, yield or sleep. use the time passed since last message as a hint // spin, yield or sleep. use 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::microseconds; using std::chrono::microseconds;
using std::chrono::milliseconds;
auto time_since_op = now - last_op_time; auto time_since_op = now - last_op_time;
// spin upto 50 micros // spin upto 50 micros
if (time_since_op <= microseconds(50)) if (time_since_op <= microseconds(50))
{
return; return;
}
// yield upto 150 micros // yield upto 150 micros
if (time_since_op <= microseconds(100)) if (time_since_op <= microseconds(100))
{
return std::this_thread::yield(); return std::this_thread::yield();
}
// sleep for 20 ms upto 200 ms // sleep for 20 ms upto 200 ms
if (time_since_op <= milliseconds(200)) if (time_since_op <= milliseconds(200))
{
return details::os::sleep_for_millis(20); return details::os::sleep_for_millis(20);
}
// sleep for 500 ms // sleep for 500 ms
return details::os::sleep_for_millis(500); return details::os::sleep_for_millis(500);

@ -8,49 +8,39 @@
// 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 "../details/async_log_helper.h"
#include "../async_logger.h" #include "../async_logger.h"
#include "../details/async_log_helper.h"
#include <string>
#include <functional>
#include <chrono> #include <chrono>
#include <functional>
#include <memory> #include <memory>
#include <string>
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 &end, size_t queue_size,
const It& begin, const async_overflow_policy overflow_policy, const std::function<void()> &worker_warmup_cb,
const It& end, const std::chrono::milliseconds &flush_interval_ms, const std::function<void()> &worker_teardown_cb)
size_t queue_size, : logger(logger_name, begin, end)
const async_overflow_policy overflow_policy, , _async_log_helper(new details::async_log_helper(
const std::function<void()>& worker_warmup_cb, _formatter, _sinks, queue_size, _err_handler, overflow_policy, worker_warmup_cb, flush_interval_ms, worker_teardown_cb))
const std::chrono::milliseconds& flush_interval_ms,
const std::function<void()>& worker_teardown_cb) :
logger(logger_name, begin, end),
_async_log_helper(new details::async_log_helper(_formatter, _sinks, queue_size, _err_handler, overflow_policy, worker_warmup_cb, flush_interval_ms, worker_teardown_cb))
{ {
} }
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_list, size_t queue_size,
sinks_init_list sinks_list, const async_overflow_policy overflow_policy, const std::function<void()> &worker_warmup_cb,
size_t queue_size, const std::chrono::milliseconds &flush_interval_ms, const std::function<void()> &worker_teardown_cb)
const async_overflow_policy overflow_policy, : async_logger(logger_name, sinks_list.begin(), sinks_list.end(), queue_size, overflow_policy, worker_warmup_cb, flush_interval_ms,
const std::function<void()>& worker_warmup_cb, worker_teardown_cb)
const std::chrono::milliseconds& flush_interval_ms,
const std::function<void()>& worker_teardown_cb) :
async_logger(logger_name, sinks_list.begin(), sinks_list.end(), queue_size, overflow_policy, worker_warmup_cb, flush_interval_ms, worker_teardown_cb) {}
inline spdlog::async_logger::async_logger(const std::string& logger_name,
sink_ptr single_sink,
size_t queue_size,
const async_overflow_policy overflow_policy,
const std::function<void()>& worker_warmup_cb,
const std::chrono::milliseconds& flush_interval_ms,
const std::function<void()>& worker_teardown_cb) :
async_logger(logger_name,
{ {
std::move(single_sink) }
}, queue_size, overflow_policy, worker_warmup_cb, flush_interval_ms, worker_teardown_cb) {}
inline spdlog::async_logger::async_logger(const std::string &logger_name, sink_ptr single_sink, size_t queue_size,
const async_overflow_policy overflow_policy, const std::function<void()> &worker_warmup_cb,
const std::chrono::milliseconds &flush_interval_ms, const std::function<void()> &worker_teardown_cb)
: async_logger(
logger_name, {std::move(single_sink)}, queue_size, overflow_policy, worker_warmup_cb, flush_interval_ms, worker_teardown_cb)
{
}
inline void spdlog::async_logger::flush() inline void spdlog::async_logger::flush()
{ {
@ -62,14 +52,12 @@ inline void spdlog::async_logger::set_error_handler(spdlog::log_err_handler err_
{ {
_err_handler = err_handler; _err_handler = err_handler;
_async_log_helper->set_error_handler(err_handler); _async_log_helper->set_error_handler(err_handler);
} }
inline spdlog::log_err_handler spdlog::async_logger::error_handler() inline spdlog::log_err_handler spdlog::async_logger::error_handler()
{ {
return _err_handler; return _err_handler;
} }
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;
@ -82,7 +70,6 @@ inline void spdlog::async_logger::_set_pattern(const std::string& pattern, patte
_async_log_helper->set_formatter(_formatter); _async_log_helper->set_formatter(_formatter);
} }
inline void spdlog::async_logger::_sink_it(details::log_msg &msg) inline void spdlog::async_logger::_sink_it(details::log_msg &msg)
{ {
try try
@ -92,8 +79,10 @@ inline void spdlog::async_logger::_sink_it(details::log_msg& msg)
#endif #endif
_async_log_helper->log(msg); _async_log_helper->log(msg);
if (_should_flush_on(msg)) if (_should_flush_on(msg))
{
_async_log_helper->flush(false); // do async flush _async_log_helper->flush(false); // do async flush
} }
}
catch (const std::exception &ex) catch (const std::exception &ex)
{ {
_err_handler(ex.what()); _err_handler(ex.what());
@ -103,5 +92,4 @@ inline void spdlog::async_logger::_sink_it(details::log_msg& msg)
_err_handler("Unknown exception in logger " + _name); _err_handler("Unknown exception in logger " + _name);
throw; throw;
} }
} }

@ -9,20 +9,18 @@
// 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)
// Throw spdlog_ex exception on errors // Throw spdlog_ex exception on errors
#include "../details/os.h"
#include "../details/log_msg.h" #include "../details/log_msg.h"
#include "../details/os.h"
#include <cerrno>
#include <chrono> #include <chrono>
#include <cstdio> #include <cstdio>
#include <string> #include <string>
#include <thread> #include <thread>
#include <tuple> #include <tuple>
#include <cerrno>
namespace spdlog namespace spdlog {
{ namespace details {
namespace details
{
class file_helper class file_helper
{ {
@ -41,7 +39,6 @@ public:
close(); close();
} }
void open(const filename_t &fname, bool truncate = false) void open(const filename_t &fname, bool truncate = false)
{ {
close(); close();
@ -50,7 +47,9 @@ public:
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;
}
details::os::sleep_for_millis(open_interval); details::os::sleep_for_millis(open_interval);
} }
@ -61,9 +60,10 @@ public:
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()
@ -85,8 +85,10 @@ public:
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 " + os::filename_to_str(_filename), errno); throw spdlog_ex("Failed writing to file " + os::filename_to_str(_filename), errno);
} }
}
size_t size() const size_t size() const
{ {
@ -126,12 +128,16 @@ public:
// no valid extension found - return whole path and empty string as extension // no valid extension found - return whole path and empty string as extension
if (ext_index == filename_t::npos || ext_index == 0 || ext_index == fname.size() - 1) if (ext_index == filename_t::npos || ext_index == 0 || ext_index == fname.size() - 1)
{
return std::make_tuple(fname, spdlog::filename_t()); return std::make_tuple(fname, spdlog::filename_t());
}
// treat casese like "/etc/rc.d/somelogfile or "/abc/.hiddenfile" // treat casese like "/etc/rc.d/somelogfile or "/abc/.hiddenfile"
auto folder_index = fname.rfind(details::os::folder_sep); auto folder_index = fname.rfind(details::os::folder_sep);
if (folder_index != fname.npos && folder_index >= ext_index - 1) if (folder_index != fname.npos && folder_index >= ext_index - 1)
{
return std::make_tuple(fname, spdlog::filename_t()); return std::make_tuple(fname, spdlog::filename_t());
}
// finally - return a valid base and extension tuple // finally - return a valid base and extension tuple
return std::make_tuple(fname.substr(0, ext_index), fname.substr(ext_index)); return std::make_tuple(fname.substr(0, ext_index), fname.substr(ext_index));
@ -141,5 +147,5 @@ private:
FILE *_fd{nullptr}; FILE *_fd{nullptr};
filename_t _filename; filename_t _filename;
}; };
} } // namespace details
} } // namespace spdlog

@ -12,10 +12,8 @@
#include <utility> #include <utility>
#include <unordered_map> #include <unordered_map>
namespace spdlog namespace spdlog {
{ namespace details {
namespace details
{
struct log_msg struct log_msg
{ {
log_msg() = default; log_msg() = default;
@ -37,7 +35,6 @@ struct log_msg
log_msg &operator=(log_msg &&other) = delete; log_msg &operator=(log_msg &&other) = delete;
log_msg(log_msg &&other) = delete; log_msg(log_msg &&other) = delete;
const std::string *logger_name{nullptr}; const std::string *logger_name{nullptr};
level::level_enum level; level::level_enum level;
log_clock::time_point time; log_clock::time_point time;
@ -46,6 +43,9 @@ struct log_msg
fmt::MemoryWriter formatted; fmt::MemoryWriter formatted;
size_t msg_id{ 0 }; size_t msg_id{ 0 };
std::unordered_map<char, std::string>* custom_flags; std::unordered_map<char, std::string>* custom_flags;
// wrap this range with color codes
size_t color_range_start{0};
size_t color_range_end{0};
}; };
} } // namespace details
} } // namespace spdlog

@ -14,39 +14,32 @@
// 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(std::string logger_name, const It& begin, const It& end): inline spdlog::logger::logger(std::string logger_name, const It &begin, const It &end)
_name(std::move(logger_name)), : _name(std::move(logger_name))
_sinks(begin, end), , _sinks(begin, end)
_formatter(std::make_shared<pattern_formatter>("%+")), , _formatter(std::make_shared<pattern_formatter>("%+"))
_level(level::info), , _level(level::info)
_flush_level(level::off), , _flush_level(level::off)
_last_err_time(0), , _last_err_time(0)
_msg_counter(1) // message counter will start from 1. 0-message id will be reserved for controll messages , _msg_counter(1) // message counter will start from 1. 0-message id will be reserved for controll messages
{ {
_err_handler = [this](const std::string &msg) _err_handler = [this](const std::string &msg) { this->_default_err_handler(msg); };
{
this->_default_err_handler(msg);
};
} }
// 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, {std::move(single_sink)})
{ {
std::move(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(std::move(msg_formatter)); _set_formatter(std::move(msg_formatter));
@ -60,7 +53,10 @@ inline void spdlog::logger::set_pattern(const std::string& pattern, pattern_time
template<typename... Args> template<typename... Args>
inline void spdlog::logger::log(level::level_enum lvl, const char *fmt, const Args &... args) inline void spdlog::logger::log(level::level_enum lvl, const char *fmt, const Args &... args)
{ {
if (!should_log(lvl)) return; if (!should_log(lvl))
{
return;
}
try try
{ {
@ -87,7 +83,10 @@ inline void spdlog::logger::log(level::level_enum lvl, const char* fmt, const Ar
template<typename... Args> template<typename... Args>
inline void spdlog::logger::log(level::level_enum lvl, const char *msg) inline void spdlog::logger::log(level::level_enum lvl, const char *msg)
{ {
if (!should_log(lvl)) return; if (!should_log(lvl))
{
return;
}
try try
{ {
details::log_msg log_msg(&_name, lvl, &_custom_flags); details::log_msg log_msg(&_name, lvl, &_custom_flags);
@ -108,7 +107,10 @@ inline void spdlog::logger::log(level::level_enum lvl, const char* msg)
template<typename T> template<typename T>
inline void spdlog::logger::log(level::level_enum lvl, const T &msg) inline void spdlog::logger::log(level::level_enum lvl, const T &msg)
{ {
if (!should_log(lvl)) return; if (!should_log(lvl))
{
return;
}
try try
{ {
details::log_msg log_msg(&_name, lvl,&_custom_flags); details::log_msg log_msg(&_name, lvl,&_custom_flags);
@ -126,7 +128,6 @@ inline void spdlog::logger::log(level::level_enum lvl, const T& msg)
} }
} }
template<typename Arg1, typename... Args> template<typename Arg1, typename... Args>
inline void spdlog::logger::trace(const char *fmt, const Arg1 &arg1, const Args &... args) inline void spdlog::logger::trace(const char *fmt, const Arg1 &arg1, const Args &... args)
{ {
@ -163,7 +164,6 @@ inline void spdlog::logger::critical(const char* fmt, const Arg1 &arg1, const Ar
log(level::critical, fmt, arg1, args...); log(level::critical, fmt, arg1, args...);
} }
template<typename T> template<typename T>
inline void spdlog::logger::trace(const T &msg) inline void spdlog::logger::trace(const T &msg)
{ {
@ -176,14 +176,12 @@ inline void spdlog::logger::debug(const T& msg)
log(level::debug, msg); log(level::debug, msg);
} }
template<typename T> template<typename T>
inline void spdlog::logger::info(const T &msg) inline void spdlog::logger::info(const T &msg)
{ {
log(level::info, msg); log(level::info, msg);
} }
template<typename T> template<typename T>
inline void spdlog::logger::warn(const T &msg) inline void spdlog::logger::warn(const T &msg)
{ {
@ -202,8 +200,6 @@ inline void spdlog::logger::critical(const T& msg)
log(level::critical, msg); log(level::critical, msg);
} }
#ifdef SPDLOG_WCHAR_TO_UTF8_SUPPORT #ifdef SPDLOG_WCHAR_TO_UTF8_SUPPORT
#include <codecvt> #include <codecvt>
#include <locale> #include <locale>
@ -243,7 +239,6 @@ inline void spdlog::logger::info(const wchar_t* fmt, const Args&... args)
log(level::info, fmt, args...); log(level::info, fmt, args...);
} }
template<typename... Args> template<typename... Args>
inline void spdlog::logger::warn(const wchar_t *fmt, const Args &... args) inline void spdlog::logger::warn(const wchar_t *fmt, const Args &... args)
{ {
@ -264,8 +259,6 @@ inline void spdlog::logger::critical(const wchar_t* fmt, const Args&... args)
#endif // SPDLOG_WCHAR_TO_UTF8_SUPPORT #endif // SPDLOG_WCHAR_TO_UTF8_SUPPORT
// //
// name and level // name and level
// //
@ -341,8 +334,10 @@ inline void spdlog::logger::_sink_it(details::log_msg& msg)
} }
if (_should_flush_on(msg)) if (_should_flush_on(msg))
{
flush(); flush();
} }
}
inline void spdlog::logger::_set_pattern(const std::string &pattern, pattern_time_type pattern_time) inline void spdlog::logger::_set_pattern(const std::string &pattern, pattern_time_type pattern_time)
{ {
@ -357,14 +352,18 @@ inline void spdlog::logger::_set_formatter(formatter_ptr msg_formatter)
inline void spdlog::logger::flush() inline void spdlog::logger::flush()
{ {
for (auto &sink : _sinks) for (auto &sink : _sinks)
{
sink->flush(); sink->flush();
} }
}
inline void spdlog::logger::_default_err_handler(const std::string &msg) inline void spdlog::logger::_default_err_handler(const std::string &msg)
{ {
auto now = time(nullptr); auto now = time(nullptr);
if (now - _last_err_time < 60) if (now - _last_err_time < 60)
{
return; return;
}
auto tm_time = details::os::localtime(now); auto tm_time = details::os::localtime(now);
char date_buf[100]; char date_buf[100];
std::strftime(date_buf, sizeof(date_buf), "%Y-%m-%d %H:%M:%S", &tm_time); std::strftime(date_buf, sizeof(date_buf), "%Y-%m-%d %H:%M:%S", &tm_time);
@ -389,4 +388,3 @@ inline const std::vector<spdlog::sink_ptr>& spdlog::logger::sinks() const
{ {
return _sinks; return _sinks;
} }

@ -48,10 +48,8 @@ Distributed under the MIT License (http://opensource.org/licenses/MIT)
#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
@ -60,16 +58,20 @@ public:
using item_type = T; using item_type = T;
explicit mpmc_bounded_queue(size_t buffer_size) explicit mpmc_bounded_queue(size_t buffer_size)
:max_size_(buffer_size), : max_size_(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);
} }
@ -94,8 +96,10 @@ public:
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;
@ -117,19 +121,24 @@ public:
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 = static_cast<intptr_t>(seq) - static_cast<intptr_t>(pos + 1); intptr_t dif = static_cast<intptr_t>(seq) - static_cast<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;
@ -144,8 +153,7 @@ public:
front = enqueue_pos_.load(std::memory_order_acquire); front = enqueue_pos_.load(std::memory_order_acquire);
back = dequeue_pos_.load(std::memory_order_acquire); back = dequeue_pos_.load(std::memory_order_acquire);
front1 = enqueue_pos_.load(std::memory_order_relaxed); front1 = enqueue_pos_.load(std::memory_order_relaxed);
} } while (front != front1);
while (front != front1);
return back == front; return back == front;
} }
@ -171,5 +179,5 @@ private:
cacheline_pad_t pad3_; cacheline_pad_t pad3_;
}; };
} // ns details } // namespace details
} // ns spdlog } // namespace spdlog

@ -8,10 +8,8 @@
#include <atomic> #include <atomic>
// null, no cost dummy "mutex" and dummy "atomic" int // null, no cost dummy "mutex" and dummy "atomic" int
namespace spdlog namespace spdlog {
{ namespace details {
namespace details
{
struct null_mutex struct null_mutex
{ {
void lock() {} void lock() {}
@ -27,8 +25,10 @@ struct null_atomic_int
int value; int value;
null_atomic_int() = default; null_atomic_int() = default;
explicit null_atomic_int(int val) : value(val) explicit null_atomic_int(int val)
{} : value(val)
{
}
int load(std::memory_order) const int load(std::memory_order) const
{ {
@ -41,5 +41,5 @@ struct null_atomic_int
} }
}; };
} } // namespace details
} } // namespace spdlog

@ -6,17 +6,17 @@
#include "../common.h" #include "../common.h"
#include <algorithm>
#include <chrono>
#include <cstdio> #include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime> #include <ctime>
#include <functional> #include <functional>
#include <string> #include <string>
#include <chrono>
#include <thread>
#include <algorithm>
#include <cstring>
#include <cstdlib>
#include <sys/stat.h> #include <sys/stat.h>
#include <sys/types.h> #include <sys/types.h>
#include <thread>
#ifdef _WIN32 #ifdef _WIN32
@ -27,9 +27,9 @@
#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 <process.h> // _get_pid support
#include <io.h> // _get_osfhandle and _isatty support #include <io.h> // _get_osfhandle and _isatty support
#include <process.h> // _get_pid support
#include <windows.h>
#ifdef __MINGW32__ #ifdef __MINGW32__
#include <share.h> #include <share.h>
@ -37,8 +37,8 @@
#else // unix #else // unix
#include <unistd.h>
#include <fcntl.h> #include <fcntl.h>
#include <unistd.h>
#ifdef __linux__ #ifdef __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
@ -53,13 +53,9 @@
#define __has_feature(x) 0 // Compatibility with non-clang compilers. #define __has_feature(x) 0 // Compatibility with non-clang compilers.
#endif #endif
namespace spdlog {
namespace spdlog namespace details {
{ namespace os {
namespace details
{
namespace os
{
inline spdlog::log_clock::time_point now() inline spdlog::log_clock::time_point now()
{ {
@ -68,14 +64,11 @@ inline spdlog::log_clock::time_point now()
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)
{ {
@ -116,13 +109,8 @@ inline std::tm gmtime()
} }
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_hour == tm2.tm_hour && tm1.tm_mday == tm2.tm_mday &&
tm1.tm_min == tm2.tm_min && tm1.tm_mon == tm2.tm_mon && tm1.tm_year == tm2.tm_year && tm1.tm_isdst == tm2.tm_isdst);
tm1.tm_hour == tm2.tm_hour &&
tm1.tm_mday == tm2.tm_mday &&
tm1.tm_mon == tm2.tm_mon &&
tm1.tm_year == tm2.tm_year &&
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)
@ -141,8 +129,6 @@ inline bool operator!=(const std::tm& tm1, const std::tm& tm2)
SPDLOG_CONSTEXPR static const char *default_eol = SPDLOG_EOL; SPDLOG_CONSTEXPR static const char *default_eol = SPDLOG_EOL;
// folder separator // folder separator
#ifdef _WIN32 #ifdef _WIN32
SPDLOG_CONSTEXPR static const char folder_sep = '\\'; SPDLOG_CONSTEXPR static const char folder_sep = '\\';
@ -150,7 +136,6 @@ SPDLOG_CONSTEXPR static const char folder_sep = '\\';
SPDLOG_CONSTEXPR static const char folder_sep = '/'; SPDLOG_CONSTEXPR static const char folder_sep = '/';
#endif #endif
inline void prevent_child_fd(FILE *f) inline void prevent_child_fd(FILE *f)
{ {
@ -163,11 +148,12 @@ inline void prevent_child_fd(FILE *f)
#else #else
auto fd = fileno(f); auto fd = fileno(f);
if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1) if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1)
{
throw spdlog_ex("fcntl with FD_CLOEXEC failed", errno); throw spdlog_ex("fcntl with FD_CLOEXEC failed", errno);
}
#endif #endif
} }
// fopen_s on non windows for writing // fopen_s on non windows for writing
inline bool fopen_s(FILE **fp, const filename_t &filename, const filename_t &mode) inline bool fopen_s(FILE **fp, const filename_t &filename, const filename_t &mode)
{ {
@ -183,12 +169,13 @@ inline bool fopen_s(FILE** fp, const filename_t& filename, const filename_t& mod
#ifdef SPDLOG_PREVENT_CHILD_FD #ifdef SPDLOG_PREVENT_CHILD_FD
if (*fp != nullptr) if (*fp != nullptr)
{
prevent_child_fd(*fp); prevent_child_fd(*fp);
}
#endif #endif
return *fp == nullptr; return *fp == nullptr;
} }
inline int remove(const filename_t &filename) inline int remove(const filename_t &filename)
{ {
#if defined(_WIN32) && defined(SPDLOG_WCHAR_FILENAMES) #if defined(_WIN32) && defined(SPDLOG_WCHAR_FILENAMES)
@ -207,7 +194,6 @@ inline int rename(const filename_t& filename1, const filename_t& filename2)
#endif #endif
} }
// Return if file exists // Return if file exists
inline bool file_exists(const filename_t &filename) inline bool file_exists(const filename_t &filename)
{ {
@ -224,25 +210,28 @@ inline bool file_exists(const filename_t& filename)
#endif #endif
} }
// Return file size according to open FILE* object // Return file size according to open FILE* object
inline size_t filesize(FILE *f) inline size_t filesize(FILE *f)
{ {
if (f == nullptr) if (f == nullptr)
{
throw spdlog_ex("Failed getting file size. fd is null"); throw spdlog_ex("Failed getting file size. fd is null");
}
#if defined(_WIN32) && !defined(__CYGWIN__) #if defined(_WIN32) && !defined(__CYGWIN__)
int fd = _fileno(f); int fd = _fileno(f);
#if _WIN64 // 64 bits #if _WIN64 // 64 bits
struct _stat64 st; struct _stat64 st;
if (_fstat64(fd, &st) == 0) if (_fstat64(fd, &st) == 0)
{
return st.st_size; return st.st_size;
}
#else // windows 32 bits #else // windows 32 bits
long ret = _filelength(fd); long ret = _filelength(fd);
if (ret >= 0) if (ret >= 0)
{
return static_cast<size_t>(ret); return static_cast<size_t>(ret);
}
#endif #endif
#else // unix #else // unix
@ -251,19 +240,21 @@ inline size_t filesize(FILE *f)
#if !defined(__FreeBSD__) && !defined(__APPLE__) && (defined(__x86_64__) || defined(__ppc64__)) && !defined(__CYGWIN__) #if !defined(__FreeBSD__) && !defined(__APPLE__) && (defined(__x86_64__) || defined(__ppc64__)) && !defined(__CYGWIN__)
struct stat64 st; struct stat64 st;
if (fstat64(fd, &st) == 0) if (fstat64(fd, &st) == 0)
{
return static_cast<size_t>(st.st_size); return static_cast<size_t>(st.st_size);
}
#else // unix 32 bits or cygwin #else // unix 32 bits or cygwin
struct stat st; struct stat st;
if (fstat(fd, &st) == 0) if (fstat(fd, &st) == 0)
{
return static_cast<size_t>(st.st_size); return static_cast<size_t>(st.st_size);
}
#endif #endif
#endif #endif
throw spdlog_ex("Failed getting file size from fd", errno); throw spdlog_ex("Failed getting file size from fd", errno);
} }
// 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())
{ {
@ -281,9 +272,13 @@ inline int utc_minutes_offset(const std::tm& tm = details::os::localtime())
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
@ -298,16 +293,15 @@ inline int utc_minutes_offset(const std::tm& tm = details::os::localtime())
long int days = ( long int days = (
// difference in day of year // difference in day of year
localtm.tm_yday - gmtm.tm_yday localtm.tm_yday -
gmtm.tm_yday
// + intervening leap days // + intervening leap days
+ ((local_year >> 2) - (gmt_year >> 2)) + ((local_year >> 2) - (gmt_year >> 2)) - (local_year / 100 - gmt_year / 100) +
- (local_year / 100 - gmt_year / 100) ((local_year / 100 >> 2) - (gmt_year / 100 >> 2))
+ ((local_year / 100 >> 2) - (gmt_year / 100 >> 2))
// + difference in years * 365 */ // + difference in years * 365 */
+ (long int)(local_year - gmt_year) * 365 + (long int)(local_year - gmt_year) * 365);
);
long int hours = (24 * days) + (localtm.tm_hour - gmtm.tm_hour); long int hours = (24 * days) + (localtm.tm_hour - gmtm.tm_hour);
long int mins = (60 * hours) + (localtm.tm_min - gmtm.tm_min); long int mins = (60 * hours) + (localtm.tm_min - gmtm.tm_min);
@ -353,17 +347,15 @@ inline size_t _thread_id()
// Return current thread id as size_t (from thread local storage) // Return current thread id as size_t (from thread local storage)
inline size_t thread_id() inline size_t thread_id()
{ {
#if defined(SPDLOG_DISABLE_TID_CACHING) || (defined(_MSC_VER) && (_MSC_VER < 1900)) || defined(__cplusplus_winrt ) || (defined(__clang__) && !__has_feature(cxx_thread_local)) #if defined(SPDLOG_DISABLE_TID_CACHING) || (defined(_MSC_VER) && (_MSC_VER < 1900)) || defined(__cplusplus_winrt) || \
(defined(__clang__) && !__has_feature(cxx_thread_local))
return _thread_id(); return _thread_id();
#else // cache thread id in tls #else // cache thread id in tls
static thread_local const size_t tid = _thread_id(); static thread_local const size_t tid = _thread_id();
return tid; return tid;
#endif #endif
} }
// This is avoid msvc issue in sleep_for that happens if the clock changes. // This is avoid msvc issue in sleep_for that happens if the clock changes.
// See https://github.com/gabime/spdlog/issues/609 // See https://github.com/gabime/spdlog/issues/609
inline void sleep_for_millis(int milliseconds) inline void sleep_for_millis(int milliseconds)
@ -413,17 +405,25 @@ inline std::string errno_str(int err_num)
#ifdef _WIN32 #ifdef _WIN32
if (strerror_s(buf, buf_size, err_num) == 0) if (strerror_s(buf, buf_size, err_num) == 0)
{
return std::string(buf); return std::string(buf);
}
else else
{
return "Unknown error"; return "Unknown error";
}
#elif defined(__FreeBSD__) || defined(__APPLE__) || defined(ANDROID) || defined(__SUNPRO_CC) || \ #elif defined(__FreeBSD__) || defined(__APPLE__) || defined(ANDROID) || defined(__SUNPRO_CC) || \
((_POSIX_C_SOURCE >= 200112L) && !defined(_GNU_SOURCE)) // posix version ((_POSIX_C_SOURCE >= 200112L) && !defined(_GNU_SOURCE)) // posix version
if (strerror_r(err_num, buf, buf_size) == 0) if (strerror_r(err_num, buf, buf_size) == 0)
{
return std::string(buf); return std::string(buf);
}
else else
{
return "Unknown error"; return "Unknown error";
}
#else // gnu version (might not use the given buf, so its retval pointer must be used) #else // gnu version (might not use the given buf, so its retval pointer must be used)
auto err = strerror_r(err_num, buf, buf_size); // let compiler choose type auto err = strerror_r(err_num, buf, buf_size); // let compiler choose type
@ -439,10 +439,8 @@ inline int pid()
#else #else
return static_cast<int>(::getpid()); return static_cast<int>(::getpid());
#endif #endif
} }
// Determine if the terminal supports colors // Determine if the terminal supports colors
// Source: https://github.com/agauniyal/rang/ // Source: https://github.com/agauniyal/rang/
inline bool is_color_terminal() inline bool is_color_terminal()
@ -450,11 +448,8 @@ inline bool is_color_terminal()
#ifdef _WIN32 #ifdef _WIN32
return true; return true;
#else #else
static constexpr const char* Terms[] = static constexpr const char *Terms[] = {
{ "ansi", "color", "console", "cygwin", "gnome", "konsole", "kterm", "linux", "msys", "putty", "rxvt", "screen", "vt100", "xterm"};
"ansi", "color", "console", "cygwin", "gnome", "konsole", "kterm",
"linux", "msys", "putty", "rxvt", "screen", "vt100", "xterm"
};
const char *env_p = std::getenv("TERM"); const char *env_p = std::getenv("TERM");
if (env_p == nullptr) if (env_p == nullptr)
@ -462,16 +457,12 @@ inline bool is_color_terminal()
return false; return false;
} }
static const bool result = std::any_of( static const bool result =
std::begin(Terms), std::end(Terms), [&](const char* term) std::any_of(std::begin(Terms), std::end(Terms), [&](const char *term) { return std::strstr(env_p, term) != nullptr; });
{
return std::strstr(env_p, term) != nullptr;
});
return result; return result;
#endif #endif
} }
// Detrmine if the terminal attached // Detrmine if the terminal attached
// Source: https://github.com/agauniyal/rang/ // Source: https://github.com/agauniyal/rang/
inline bool in_terminal(FILE *file) inline bool in_terminal(FILE *file)
@ -483,6 +474,6 @@ inline bool in_terminal(FILE* file)
return isatty(fileno(file)) != 0; return isatty(fileno(file)) != 0;
#endif #endif
} }
} //os } // namespace os
} //details } // namespace details
} //spdlog } // namespace spdlog

@ -5,11 +5,12 @@
#pragma once #pragma once
#include "../formatter.h"
#include "../details/log_msg.h" #include "../details/log_msg.h"
#include "../details/os.h" #include "../details/os.h"
#include "../fmt/fmt.h" #include "../fmt/fmt.h"
#include "../formatter.h"
#include <array>
#include <chrono> #include <chrono>
#include <ctime> #include <ctime>
#include <memory> #include <memory>
@ -18,12 +19,9 @@
#include <thread> #include <thread>
#include <utility> #include <utility>
#include <vector> #include <vector>
#include <array>
namespace spdlog namespace spdlog {
{ namespace details {
namespace details
{
class flag_formatter class flag_formatter
{ {
public: public:
@ -105,7 +103,8 @@ class b_formatter : public flag_formatter
}; };
// Full month name // Full month name
static const std::string full_months[] { "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" }; static const std::string full_months[]{
"January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"};
class B_formatter : public flag_formatter class B_formatter : public flag_formatter
{ {
void format(details::log_msg &msg, const std::tm &tm_time) override void format(details::log_msg &msg, const std::tm &tm_time) override
@ -334,6 +333,7 @@ public:
msg.formatted << sign; msg.formatted << sign;
pad_n_join(msg.formatted, h, m, ':'); pad_n_join(msg.formatted, h, m, ':');
} }
private: private:
log_clock::time_point _last_update{std::chrono::seconds(0)}; log_clock::time_point _last_update{std::chrono::seconds(0)};
int _offset_minutes{0}; int _offset_minutes{0};
@ -389,12 +389,15 @@ class v_formatter SPDLOG_FINAL : public flag_formatter
class ch_formatter SPDLOG_FINAL : public flag_formatter class ch_formatter SPDLOG_FINAL : public flag_formatter
{ {
public: public:
explicit ch_formatter(char ch): _ch(ch) explicit ch_formatter(char ch)
{} : _ch(ch)
{
}
void format(details::log_msg &msg, const std::tm &) override void format(details::log_msg &msg, const std::tm &) override
{ {
msg.formatted << _ch; msg.formatted << _ch;
} }
private: private:
char _ch; char _ch;
}; };
@ -420,7 +423,6 @@ private:
char _flag; char _flag;
}; };
// aggregate user chars to display as is // aggregate user chars to display as is
class aggregate_formatter SPDLOG_FINAL : public flag_formatter class aggregate_formatter SPDLOG_FINAL : public flag_formatter
{ {
@ -435,10 +437,27 @@ public:
{ {
msg.formatted << _str; msg.formatted << _str;
} }
private: private:
std::string _str; std::string _str;
}; };
// mark the color range. expect it to be in the form of "%^colored text%$"
class color_start_formatter SPDLOG_FINAL : public flag_formatter
{
void format(details::log_msg &msg, const std::tm &) override
{
msg.color_range_start = msg.formatted.size();
}
};
class color_stop_formatter SPDLOG_FINAL : public flag_formatter
{
void format(details::log_msg &msg, const std::tm &) override
{
msg.color_range_end = msg.formatted.size();
}
};
// Full info formatter // Full info formatter
// pattern: [%Y-%m-%d %H:%M:%S.%e] [%n] [%l] %v // pattern: [%Y-%m-%d %H:%M:%S.%e] [%n] [%l] %v
class full_formatter SPDLOG_FINAL : public flag_formatter class full_formatter SPDLOG_FINAL : public flag_formatter
@ -462,7 +481,6 @@ class full_formatter SPDLOG_FINAL : public flag_formatter
level::to_str(msg.level), level::to_str(msg.level),
msg.raw.str());*/ msg.raw.str());*/
// Faster (albeit uglier) way to format the line (5.6 million lines/sec under 10 threads) // Faster (albeit uglier) way to format the line (5.6 million lines/sec under 10 threads)
msg.formatted << '[' << static_cast<unsigned int>(tm_time.tm_year + 1900) << '-' msg.formatted << '[' << static_cast<unsigned int>(tm_time.tm_year + 1900) << '-'
<< fmt::pad(static_cast<unsigned int>(tm_time.tm_mon + 1), 2, '0') << '-' << fmt::pad(static_cast<unsigned int>(tm_time.tm_mon + 1), 2, '0') << '-'
@ -481,21 +499,23 @@ class full_formatter SPDLOG_FINAL : public flag_formatter
msg.formatted << '[' << *msg.logger_name << "] "; msg.formatted << '[' << *msg.logger_name << "] ";
#endif #endif
msg.formatted << '[' << level::to_str(msg.level) << "] "; msg.formatted << '[';
msg.formatted << fmt::StringRef(msg.raw.data(), msg.raw.size()); // wrap the level name with color
msg.color_range_start = msg.formatted.size();
msg.formatted << level::to_str(msg.level);
msg.color_range_end = msg.formatted.size();
msg.formatted << "] " << fmt::StringRef(msg.raw.data(), msg.raw.size());
} }
}; };
} // namespace details
} // namespace spdlog
}
}
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// pattern_formatter inline impl // pattern_formatter inline impl
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
inline spdlog::pattern_formatter::pattern_formatter(const std::string& pattern, pattern_time_type pattern_time, std::string eol) : inline spdlog::pattern_formatter::pattern_formatter(const std::string &pattern, pattern_time_type pattern_time, std::string eol)
_eol(std::move(eol)), : _eol(std::move(eol))
_pattern_time(pattern_time) , _pattern_time(pattern_time)
{ {
compile_pattern(pattern); compile_pattern(pattern);
} }
@ -509,16 +529,25 @@ inline void spdlog::pattern_formatter::compile_pattern(const std::string& patter
if (*it == '%') if (*it == '%')
{ {
if (user_chars) // append user chars found so far if (user_chars) // append user chars found so far
{
_formatters.push_back(std::move(user_chars)); _formatters.push_back(std::move(user_chars));
}
// if(
if (++it != end) if (++it != end)
{
handle_flag(*it); handle_flag(*it);
}
else else
{
break; break;
} }
}
else // chars not following the % sign should be displayed as is else // chars not following the % sign should be displayed as is
{ {
if (!user_chars) if (!user_chars)
{
user_chars = std::unique_ptr<details::aggregate_formatter>(new details::aggregate_formatter()); user_chars = std::unique_ptr<details::aggregate_formatter>(new details::aggregate_formatter());
}
user_chars->add_ch(*it); user_chars->add_ch(*it);
} }
} }
@ -526,7 +555,6 @@ inline void spdlog::pattern_formatter::compile_pattern(const std::string& patter
{ {
_formatters.push_back(std::move(user_chars)); _formatters.push_back(std::move(user_chars));
} }
} }
inline void spdlog::pattern_formatter::handle_flag(char flag) inline void spdlog::pattern_formatter::handle_flag(char flag)
{ {
@ -655,11 +683,18 @@ inline void spdlog::pattern_formatter::handle_flag(char flag)
_formatters.emplace_back(new details::pid_formatter()); _formatters.emplace_back(new details::pid_formatter());
break; break;
case ('i'): case ('i'):
_formatters.emplace_back(new details::i_formatter()); _formatters.emplace_back(new details::i_formatter());
break; break;
case ('^'):
_formatters.emplace_back(new details::color_start_formatter());
break;
case ('$'):
_formatters.emplace_back(new details::color_stop_formatter());
break;
default: //Unknown flag appears as is default: //Unknown flag appears as is
_formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::custom_formatter(flag))); _formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::custom_formatter(flag)));
break; break;
@ -688,5 +723,5 @@ inline void spdlog::pattern_formatter::format(details::log_msg& msg)
f->format(msg, tm_time); f->format(msg, tm_time);
} }
// write eol // write eol
msg.formatted.write(_eol.data(), _eol.size()); msg.formatted << _eol;
} }

@ -10,10 +10,10 @@
// 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 "../details/null_mutex.h"
#include "../logger.h"
#include "../async_logger.h" #include "../async_logger.h"
#include "../common.h" #include "../common.h"
#include "../details/null_mutex.h"
#include "../logger.h"
#include <chrono> #include <chrono>
#include <functional> #include <functional>
@ -22,10 +22,8 @@
#include <string> #include <string>
#include <unordered_map> #include <unordered_map>
namespace spdlog namespace spdlog {
{ namespace details {
namespace details
{
template<class Mutex> template<class Mutex>
class registry_t class registry_t
{ {
@ -55,37 +53,53 @@ public:
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, _worker_teardown_cb); {
new_logger = std::make_shared<async_logger>(logger_name, sinks_begin, sinks_end, _async_q_size, _overflow_policy,
_worker_warmup_cb, _flush_interval_ms, _worker_teardown_cb);
}
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);
}
if (_err_handler) if (_err_handler)
{
new_logger->set_error_handler(_err_handler); new_logger->set_error_handler(_err_handler);
}
new_logger->set_level(_level); new_logger->set_level(_level);
new_logger->flush_on(_flush_level); new_logger->flush_on(_flush_level);
// Add to registry // Add to registry
_loggers[logger_name] = new_logger; _loggers[logger_name] = new_logger;
return new_logger; return new_logger;
} }
template<class It> template<class It>
std::shared_ptr<async_logger> create_async(const std::string& logger_name, size_t queue_size, const async_overflow_policy overflow_policy, const std::function<void()>& worker_warmup_cb, const std::chrono::milliseconds& flush_interval_ms, const std::function<void()>& worker_teardown_cb, const It& sinks_begin, const It& sinks_end) std::shared_ptr<async_logger> create_async(const std::string &logger_name, size_t queue_size,
const async_overflow_policy overflow_policy, const std::function<void()> &worker_warmup_cb,
const std::chrono::milliseconds &flush_interval_ms, const std::function<void()> &worker_teardown_cb, 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);
auto new_logger = std::make_shared<async_logger>(logger_name, sinks_begin, sinks_end, queue_size, overflow_policy, worker_warmup_cb, flush_interval_ms, worker_teardown_cb); auto new_logger = std::make_shared<async_logger>(
logger_name, sinks_begin, sinks_end, queue_size, overflow_policy, worker_warmup_cb, flush_interval_ms, worker_teardown_cb);
if (_formatter) if (_formatter)
{
new_logger->set_formatter(_formatter); new_logger->set_formatter(_formatter);
}
if (_err_handler) if (_err_handler)
{
new_logger->set_error_handler(_err_handler); new_logger->set_error_handler(_err_handler);
}
new_logger->set_level(_level); new_logger->set_level(_level);
new_logger->flush_on(_flush_level); new_logger->flush_on(_flush_level);
@ -99,8 +113,10 @@ public:
{ {
std::lock_guard<Mutex> lock(_mutex); std::lock_guard<Mutex> lock(_mutex);
for (auto &l : _loggers) for (auto &l : _loggers)
{
fun(l.second); fun(l.second);
} }
}
void drop(const std::string &logger_name) void drop(const std::string &logger_name)
{ {
@ -124,12 +140,17 @@ public:
return create(logger_name, {sink}); return create(logger_name, {sink});
} }
std::shared_ptr<async_logger> create_async(const std::string& logger_name, size_t queue_size, const async_overflow_policy overflow_policy, const std::function<void()>& worker_warmup_cb, const std::chrono::milliseconds& flush_interval_ms, const std::function<void()>& worker_teardown_cb, sinks_init_list sinks) std::shared_ptr<async_logger> create_async(const std::string &logger_name, size_t queue_size,
const async_overflow_policy overflow_policy, const std::function<void()> &worker_warmup_cb,
const std::chrono::milliseconds &flush_interval_ms, const std::function<void()> &worker_teardown_cb, sinks_init_list sinks)
{ {
return create_async(logger_name, queue_size, overflow_policy, worker_warmup_cb, flush_interval_ms, worker_teardown_cb, sinks.begin(), sinks.end()); return create_async(
logger_name, queue_size, overflow_policy, worker_warmup_cb, flush_interval_ms, worker_teardown_cb, sinks.begin(), sinks.end());
} }
std::shared_ptr<async_logger> create_async(const std::string& logger_name, size_t queue_size, const async_overflow_policy overflow_policy, const std::function<void()>& worker_warmup_cb, const std::chrono::milliseconds& flush_interval_ms, const std::function<void()>& worker_teardown_cb, sink_ptr sink) std::shared_ptr<async_logger> create_async(const std::string &logger_name, size_t queue_size,
const async_overflow_policy overflow_policy, const std::function<void()> &worker_warmup_cb,
const std::chrono::milliseconds &flush_interval_ms, const std::function<void()> &worker_teardown_cb, sink_ptr sink)
{ {
return create_async(logger_name, queue_size, overflow_policy, worker_warmup_cb, flush_interval_ms, worker_teardown_cb, {sink}); return create_async(logger_name, queue_size, overflow_policy, worker_warmup_cb, flush_interval_ms, worker_teardown_cb, {sink});
} }
@ -139,22 +160,28 @@ public:
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;
} }
@ -184,18 +211,23 @@ public:
{ {
std::lock_guard<Mutex> lock(_mutex); std::lock_guard<Mutex> lock(_mutex);
for (auto &l : _loggers) for (auto &l : _loggers)
{
l.second->flush_on(log_level); l.second->flush_on(log_level);
}
_flush_level = log_level; _flush_level = log_level;
} }
void set_error_handler(log_err_handler handler) void set_error_handler(log_err_handler handler)
{ {
for (auto &l : _loggers) for (auto &l : _loggers)
{
l.second->set_error_handler(handler); l.second->set_error_handler(handler);
}
_err_handler = handler; _err_handler = handler;
} }
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, const std::function<void()>& worker_teardown_cb) 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, const std::function<void()> &worker_teardown_cb)
{ {
std::lock_guard<Mutex> lock(_mutex); std::lock_guard<Mutex> lock(_mutex);
_async_mode = true; _async_mode = true;
@ -224,8 +256,10 @@ private:
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;
@ -237,7 +271,7 @@ private:
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; std::function<void()> _worker_warmup_cb;
std::chrono::milliseconds _flush_interval_ms; std::chrono::milliseconds _flush_interval_ms{std::chrono::milliseconds::zero()};
std::function<void()> _worker_teardown_cb; std::function<void()> _worker_teardown_cb;
std::unordered_map<char, std::string> _custom_flags; std::unordered_map<char, std::string> _custom_flags;
}; };
@ -248,5 +282,5 @@ using registry = registry_t<spdlog::details::null_mutex>;
using registry = registry_t<std::mutex>; using registry = registry_t<std::mutex>;
#endif #endif
} } // namespace details
} } // namespace spdlog

@ -8,10 +8,10 @@
// //
// Global registry functions // Global registry functions
// //
#include "../spdlog.h"
#include "../details/registry.h" #include "../details/registry.h"
#include "../sinks/file_sinks.h" #include "../sinks/file_sinks.h"
#include "../sinks/stdout_sinks.h" #include "../sinks/stdout_sinks.h"
#include "../spdlog.h"
#ifdef SPDLOG_ENABLE_SYSLOG #ifdef SPDLOG_ENABLE_SYSLOG
#include "../sinks/syslog_sink.h" #include "../sinks/syslog_sink.h"
#endif #endif
@ -22,7 +22,6 @@
#include "../sinks/ansicolor_sink.h" #include "../sinks/ansicolor_sink.h"
#endif #endif
#ifdef __ANDROID__ #ifdef __ANDROID__
#include "../sinks/android_sink.h" #include "../sinks/android_sink.h"
#endif #endif
@ -59,28 +58,31 @@ inline std::shared_ptr<spdlog::logger> spdlog::basic_logger_st(const std::string
} }
// 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 filename_t& filename, size_t max_file_size, size_t max_files) inline std::shared_ptr<spdlog::logger> spdlog::rotating_logger_mt(
const std::string &logger_name, const filename_t &filename, size_t max_file_size, size_t max_files)
{ {
return create<spdlog::sinks::rotating_file_sink_mt>(logger_name, filename, max_file_size, max_files); return create<spdlog::sinks::rotating_file_sink_mt>(logger_name, filename, max_file_size, max_files);
} }
inline std::shared_ptr<spdlog::logger> spdlog::rotating_logger_st(const std::string& logger_name, const filename_t& filename, size_t max_file_size, size_t max_files) inline std::shared_ptr<spdlog::logger> spdlog::rotating_logger_st(
const std::string &logger_name, const filename_t &filename, size_t max_file_size, size_t max_files)
{ {
return create<spdlog::sinks::rotating_file_sink_st>(logger_name, filename, max_file_size, max_files); return create<spdlog::sinks::rotating_file_sink_st>(logger_name, filename, max_file_size, max_files);
} }
// 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 filename_t& filename, int hour, int minute) inline std::shared_ptr<spdlog::logger> spdlog::daily_logger_mt(
const std::string &logger_name, const filename_t &filename, int hour, int minute)
{ {
return create<spdlog::sinks::daily_file_sink_mt>(logger_name, filename, hour, minute); return create<spdlog::sinks::daily_file_sink_mt>(logger_name, filename, hour, minute);
} }
inline std::shared_ptr<spdlog::logger> spdlog::daily_logger_st(const std::string& logger_name, const filename_t& filename, int hour, int minute) inline std::shared_ptr<spdlog::logger> spdlog::daily_logger_st(
const std::string &logger_name, const filename_t &filename, int hour, int minute)
{ {
return create<spdlog::sinks::daily_file_sink_st>(logger_name, filename, hour, minute); return create<spdlog::sinks::daily_file_sink_st>(logger_name, filename, hour, minute);
} }
// //
// stdout/stderr loggers // stdout/stderr loggers
// //
@ -127,7 +129,6 @@ inline std::shared_ptr<spdlog::logger> spdlog::stderr_color_mt(const std::string
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::stderr_color_st(const std::string &logger_name) inline std::shared_ptr<spdlog::logger> spdlog::stderr_color_st(const std::string &logger_name)
{ {
auto sink = std::make_shared<spdlog::sinks::wincolor_stderr_sink_st>(); auto sink = std::make_shared<spdlog::sinks::wincolor_stderr_sink_st>();
@ -163,7 +164,8 @@ inline std::shared_ptr<spdlog::logger> spdlog::stderr_color_st(const std::string
#ifdef SPDLOG_ENABLE_SYSLOG #ifdef SPDLOG_ENABLE_SYSLOG
// 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, int syslog_facility) inline std::shared_ptr<spdlog::logger> spdlog::syslog_logger(
const std::string &logger_name, const std::string &syslog_ident, int syslog_option, int syslog_facility)
{ {
return create<spdlog::sinks::syslog_sink>(logger_name, syslog_ident, syslog_option, syslog_facility); return create<spdlog::sinks::syslog_sink>(logger_name, syslog_ident, syslog_option, syslog_facility);
} }
@ -202,21 +204,30 @@ inline std::shared_ptr<spdlog::logger> spdlog::create(const std::string& logger_
} }
// Create and register an async logger with a single sink // Create and register an async logger with a single sink
inline std::shared_ptr<spdlog::logger> spdlog::create_async(const std::string& logger_name, const sink_ptr& sink, size_t queue_size, const async_overflow_policy overflow_policy, const std::function<void()>& worker_warmup_cb, const std::chrono::milliseconds& flush_interval_ms, const std::function<void()>& worker_teardown_cb) inline std::shared_ptr<spdlog::logger> spdlog::create_async(const std::string &logger_name, const sink_ptr &sink, size_t queue_size,
const async_overflow_policy overflow_policy, const std::function<void()> &worker_warmup_cb,
const std::chrono::milliseconds &flush_interval_ms, const std::function<void()> &worker_teardown_cb)
{ {
return details::registry::instance().create_async(logger_name, queue_size, overflow_policy, worker_warmup_cb, flush_interval_ms, worker_teardown_cb, sink); return details::registry::instance().create_async(
logger_name, queue_size, overflow_policy, worker_warmup_cb, flush_interval_ms, worker_teardown_cb, sink);
} }
// Create and register an async logger with multiple sinks // Create and register an async logger with multiple sinks
inline std::shared_ptr<spdlog::logger> spdlog::create_async(const std::string& logger_name, sinks_init_list sinks, size_t queue_size, const async_overflow_policy overflow_policy, const std::function<void()>& worker_warmup_cb, const std::chrono::milliseconds& flush_interval_ms, const std::function<void()>& worker_teardown_cb ) inline std::shared_ptr<spdlog::logger> spdlog::create_async(const std::string &logger_name, sinks_init_list sinks, size_t queue_size,
const async_overflow_policy overflow_policy, const std::function<void()> &worker_warmup_cb,
const std::chrono::milliseconds &flush_interval_ms, const std::function<void()> &worker_teardown_cb)
{ {
return details::registry::instance().create_async(logger_name, queue_size, overflow_policy, worker_warmup_cb, flush_interval_ms, worker_teardown_cb, sinks); return details::registry::instance().create_async(
logger_name, queue_size, overflow_policy, worker_warmup_cb, flush_interval_ms, worker_teardown_cb, sinks);
} }
template<class It> template<class It>
inline std::shared_ptr<spdlog::logger> spdlog::create_async(const std::string& logger_name, const It& sinks_begin, const It& sinks_end, size_t queue_size, const async_overflow_policy overflow_policy, const std::function<void()>& worker_warmup_cb, const std::chrono::milliseconds& flush_interval_ms, const std::function<void()>& worker_teardown_cb) inline std::shared_ptr<spdlog::logger> spdlog::create_async(const std::string &logger_name, const It &sinks_begin, const It &sinks_end,
size_t queue_size, const async_overflow_policy overflow_policy, const std::function<void()> &worker_warmup_cb,
const std::chrono::milliseconds &flush_interval_ms, const std::function<void()> &worker_teardown_cb)
{ {
return details::registry::instance().create_async(logger_name, queue_size, overflow_policy, worker_warmup_cb, flush_interval_ms, worker_teardown_cb, sinks_begin, sinks_end); return details::registry::instance().create_async(
logger_name, queue_size, overflow_policy, worker_warmup_cb, flush_interval_ms, worker_teardown_cb, sinks_begin, sinks_end);
} }
inline void spdlog::set_formatter(spdlog::formatter_ptr f) inline void spdlog::set_formatter(spdlog::formatter_ptr f)
@ -254,7 +265,9 @@ inline void spdlog::set_error_handler(log_err_handler handler)
return details::registry::instance().set_error_handler(std::move(handler)); return details::registry::instance().set_error_handler(std::move(handler));
} }
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, const std::function<void()>& worker_teardown_cb) 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,
const std::function<void()> &worker_teardown_cb)
{ {
details::registry::instance().set_async_mode(queue_size, overflow_policy, worker_warmup_cb, flush_interval_ms, worker_teardown_cb); details::registry::instance().set_async_mode(queue_size, overflow_policy, worker_warmup_cb, flush_interval_ms, worker_teardown_cb);
} }

File diff suppressed because it is too large Load Diff

@ -13,11 +13,9 @@
#include "format.h" #include "format.h"
#include <ostream> #include <ostream>
namespace fmt namespace fmt {
{
namespace internal namespace internal {
{
template<class Char> template<class Char>
class FormatBuf : public std::basic_streambuf<Char> class FormatBuf : public std::basic_streambuf<Char>
@ -29,7 +27,10 @@ private:
Buffer<Char> &buffer_; Buffer<Char> &buffer_;
public: public:
FormatBuf(Buffer<Char> &buffer) : buffer_(buffer) {} FormatBuf(Buffer<Char> &buffer)
: buffer_(buffer)
{
}
protected: protected:
// The put-area is actually always empty. This makes the implementation // The put-area is actually always empty. This makes the implementation
@ -82,8 +83,7 @@ FMT_API void write(std::ostream &os, Writer &w);
// Formats a value. // Formats a value.
template<typename Char, typename ArgFormatter_, typename T> template<typename Char, typename ArgFormatter_, typename T>
void format_arg(BasicFormatter<Char, ArgFormatter_> &f, void format_arg(BasicFormatter<Char, ArgFormatter_> &f, const Char *&format_str, const T &value)
const Char *&format_str, const T &value)
{ {
internal::MemoryBuffer<Char, internal::INLINE_BUFFER_SIZE> buffer; internal::MemoryBuffer<Char, internal::INLINE_BUFFER_SIZE> buffer;

@ -55,7 +55,8 @@
// equals to EINTR. // equals to EINTR.
#ifndef _WIN32 #ifndef _WIN32
#define FMT_RETRY_VAL(result, expression, error_result) \ #define FMT_RETRY_VAL(result, expression, error_result) \
do { \ do \
{ \
result = (expression); \ result = (expression); \
} while (result == error_result && errno == EINTR) } while (result == error_result && errno == EINTR)
#else #else
@ -64,8 +65,7 @@
#define FMT_RETRY(result, expression) FMT_RETRY_VAL(result, expression, -1) #define FMT_RETRY(result, expression) FMT_RETRY_VAL(result, expression, -1)
namespace fmt namespace fmt {
{
// An error code. // An error code.
class ErrorCode class ErrorCode
@ -74,8 +74,7 @@ private:
int value_; int value_;
public: public:
explicit ErrorCode(int value = 0) FMT_NOEXCEPT : explicit ErrorCode(int value = 0) FMT_NOEXCEPT : value_(value) {}
value_(value) {}
int get() const FMT_NOEXCEPT int get() const FMT_NOEXCEPT
{ {
@ -91,12 +90,14 @@ private:
friend class File; friend class File;
explicit BufferedFile(FILE *f) : file_(f) {} explicit BufferedFile(FILE *f)
: file_(f)
{
}
public: public:
// Constructs a BufferedFile object which doesn't represent any file. // Constructs a BufferedFile object which doesn't represent any file.
BufferedFile() FMT_NOEXCEPT : BufferedFile() FMT_NOEXCEPT : file_(FMT_NULL) {}
file_(FMT_NULL) {}
// Destroys the object closing the file it represents if any. // Destroys the object closing the file it represents if any.
FMT_API ~BufferedFile() FMT_NOEXCEPT; FMT_API ~BufferedFile() FMT_NOEXCEPT;
@ -115,12 +116,10 @@ private:
public: public:
// A "move constructor" for moving from a temporary. // A "move constructor" for moving from a temporary.
BufferedFile(Proxy p) FMT_NOEXCEPT : BufferedFile(Proxy p) FMT_NOEXCEPT : file_(p.file) {}
file_(p.file) {}
// A "move constructor" for moving from an lvalue. // A "move constructor" for moving from an lvalue.
BufferedFile(BufferedFile &f) FMT_NOEXCEPT : BufferedFile(BufferedFile &f) FMT_NOEXCEPT : file_(f.file_)
file_(f.file_)
{ {
f.file_ = FMT_NULL; f.file_ = FMT_NULL;
} }
@ -156,8 +155,7 @@ private:
FMT_DISALLOW_COPY_AND_ASSIGN(BufferedFile); FMT_DISALLOW_COPY_AND_ASSIGN(BufferedFile);
public: public:
BufferedFile(BufferedFile &&other) FMT_NOEXCEPT : BufferedFile(BufferedFile &&other) FMT_NOEXCEPT : file_(other.file_)
file_(other.file_)
{ {
other.file_ = FMT_NULL; other.file_ = FMT_NULL;
} }
@ -206,7 +204,10 @@ private:
int fd_; // File descriptor. int fd_; // File descriptor.
// Constructs a File object with a given descriptor. // Constructs a File object with a given descriptor.
explicit File(int fd) : fd_(fd) {} explicit File(int fd)
: fd_(fd)
{
}
public: public:
// Possible values for the oflag argument to the constructor. // Possible values for the oflag argument to the constructor.
@ -218,8 +219,7 @@ public:
}; };
// Constructs a File object which doesn't represent any file. // Constructs a File object which doesn't represent any file.
File() FMT_NOEXCEPT : File() FMT_NOEXCEPT : fd_(-1) {}
fd_(-1) {}
// Opens a file and constructs a File object representing this file. // Opens a file and constructs a File object representing this file.
FMT_API File(CStringRef path, int oflag); FMT_API File(CStringRef path, int oflag);
@ -238,12 +238,10 @@ private:
public: public:
// A "move constructor" for moving from a temporary. // A "move constructor" for moving from a temporary.
File(Proxy p) FMT_NOEXCEPT : File(Proxy p) FMT_NOEXCEPT : fd_(p.fd) {}
fd_(p.fd) {}
// A "move constructor" for moving from an lvalue. // A "move constructor" for moving from an lvalue.
File(File &other) FMT_NOEXCEPT : File(File &other) FMT_NOEXCEPT : fd_(other.fd_)
fd_(other.fd_)
{ {
other.fd_ = -1; other.fd_ = -1;
} }
@ -279,8 +277,7 @@ private:
FMT_DISALLOW_COPY_AND_ASSIGN(File); FMT_DISALLOW_COPY_AND_ASSIGN(File);
public: public:
File(File &&other) FMT_NOEXCEPT : File(File &&other) FMT_NOEXCEPT : fd_(other.fd_)
fd_(other.fd_)
{ {
other.fd_ = -1; other.fd_ = -1;
} }
@ -340,8 +337,7 @@ File(File &&other) FMT_NOEXCEPT :
// Returns the memory page size. // Returns the memory page size.
long getpagesize(); long getpagesize();
#if (defined(LC_NUMERIC_MASK) || defined(_MSC_VER)) && \ #if (defined(LC_NUMERIC_MASK) || defined(_MSC_VER)) && !defined(__ANDROID__) && !defined(__CYGWIN__)
!defined(__ANDROID__) && !defined(__CYGWIN__)
#define FMT_LOCALE #define FMT_LOCALE
#endif #endif
@ -353,7 +349,10 @@ private:
#ifdef _MSC_VER #ifdef _MSC_VER
typedef _locale_t locale_t; typedef _locale_t locale_t;
enum { LC_NUMERIC_MASK = LC_NUMERIC }; enum
{
LC_NUMERIC_MASK = LC_NUMERIC
};
static locale_t newlocale(int category_mask, const char *locale, locale_t) static locale_t newlocale(int category_mask, const char *locale, locale_t)
{ {
@ -378,7 +377,8 @@ private:
public: public:
typedef locale_t Type; typedef locale_t Type;
Locale() : locale_(newlocale(LC_NUMERIC_MASK, "C", FMT_NULL)) Locale()
: locale_(newlocale(LC_NUMERIC_MASK, "C", FMT_NULL))
{ {
if (!locale_) if (!locale_)
FMT_THROW(fmt::SystemError(errno, "cannot create locale")); FMT_THROW(fmt::SystemError(errno, "cannot create locale"));
@ -407,8 +407,7 @@ public:
} // namespace fmt } // namespace fmt
#if !FMT_USE_RVALUE_REFERENCES #if !FMT_USE_RVALUE_REFERENCES
namespace std namespace std {
{
// For compatibility with C++98. // For compatibility with C++98.
inline fmt::BufferedFile &move(fmt::BufferedFile &f) inline fmt::BufferedFile &move(fmt::BufferedFile &f)
{ {
@ -418,7 +417,7 @@ inline fmt::File &move(fmt::File &f)
{ {
return f; return f;
} }
} } // namespace std
#endif #endif
#endif // FMT_POSIX_H_ #endif // FMT_POSIX_H_

@ -15,10 +15,8 @@
#include "ostream.h" #include "ostream.h"
namespace fmt namespace fmt {
{ namespace internal {
namespace internal
{
// Checks if a value fits in int - used to avoid warnings about comparing // Checks if a value fits in int - used to avoid warnings about comparing
// signed and unsigned integers. // signed and unsigned integers.
@ -43,8 +41,7 @@ struct IntChecker<true>
template<typename T> template<typename T>
static bool fits_in_int(T value) static bool fits_in_int(T value)
{ {
return value >= std::numeric_limits<int>::min() && return value >= std::numeric_limits<int>::min() && value <= std::numeric_limits<int>::max();
value <= std::numeric_limits<int>::max();
} }
static bool fits_in_int(int) static bool fits_in_int(int)
{ {
@ -120,13 +117,19 @@ public:
template<typename T, typename U> template<typename T, typename U>
struct is_same struct is_same
{ {
enum { value = 0 }; enum
{
value = 0
};
}; };
template<typename T> template<typename T>
struct is_same<T, T> struct is_same<T, T>
{ {
enum { value = 1 }; enum
{
value = 1
};
}; };
// An argument visitor that converts an integer argument to T for printf, // An argument visitor that converts an integer argument to T for printf,
@ -144,7 +147,10 @@ private:
public: public:
ArgConverter(internal::Arg &arg, wchar_t type) ArgConverter(internal::Arg &arg, wchar_t type)
: arg_(arg), type_(type) {} : arg_(arg)
, type_(type)
{
}
void visit_bool(bool value) void visit_bool(bool value)
{ {
@ -168,8 +174,7 @@ public:
} }
using internal::Arg; using internal::Arg;
typedef typename internal::Conditional< typedef typename internal::Conditional<is_same<T, void>::value, U, T>::type TargetType;
is_same<T, void>::value, U, T>::type TargetType;
if (const_check(sizeof(TargetType) <= sizeof(int))) if (const_check(sizeof(TargetType) <= sizeof(int)))
{ {
// Extra casts are used to silence warnings. // Extra casts are used to silence warnings.
@ -198,8 +203,7 @@ public:
else else
{ {
arg_.type = Arg::ULONG_LONG; arg_.type = Arg::ULONG_LONG;
arg_.ulong_long_value = arg_.ulong_long_value = static_cast<typename internal::MakeUnsigned<U>::Type>(value);
static_cast<typename internal::MakeUnsigned<U>::Type>(value);
} }
} }
} }
@ -214,7 +218,10 @@ private:
FMT_DISALLOW_COPY_AND_ASSIGN(CharConverter); FMT_DISALLOW_COPY_AND_ASSIGN(CharConverter);
public: public:
explicit CharConverter(internal::Arg &arg) : arg_(arg) {} explicit CharConverter(internal::Arg &arg)
: arg_(arg)
{
}
template<typename T> template<typename T>
void visit_any_int(T value) void visit_any_int(T value)
@ -234,7 +241,10 @@ private:
FMT_DISALLOW_COPY_AND_ASSIGN(WidthHandler); FMT_DISALLOW_COPY_AND_ASSIGN(WidthHandler);
public: public:
explicit WidthHandler(FormatSpec &spec) : spec_(spec) {} explicit WidthHandler(FormatSpec &spec)
: spec_(spec)
{
}
void report_unhandled_arg() void report_unhandled_arg()
{ {
@ -277,8 +287,7 @@ public:
\endrst \endrst
*/ */
template<typename Impl, typename Char, typename Spec> template<typename Impl, typename Char, typename Spec>
class BasicPrintfArgFormatter : class BasicPrintfArgFormatter : public internal::ArgFormatterBase<Impl, Char, Spec>
public internal::ArgFormatterBase<Impl, Char, Spec>
{ {
private: private:
void write_null_pointer() void write_null_pointer()
@ -298,7 +307,9 @@ public:
\endrst \endrst
*/ */
BasicPrintfArgFormatter(BasicWriter<Char> &w, Spec &s) BasicPrintfArgFormatter(BasicWriter<Char> &w, Spec &s)
: internal::ArgFormatterBase<Impl, Char, Spec>(w, s) {} : internal::ArgFormatterBase<Impl, Char, Spec>(w, s)
{
}
/** Formats an argument of type ``bool``. */ /** Formats an argument of type ``bool``. */
void visit_bool(bool value) void visit_bool(bool value)
@ -372,13 +383,14 @@ public:
/** The default printf argument formatter. */ /** The default printf argument formatter. */
template<typename Char> template<typename Char>
class PrintfArgFormatter : class PrintfArgFormatter : public BasicPrintfArgFormatter<PrintfArgFormatter<Char>, Char, FormatSpec>
public BasicPrintfArgFormatter<PrintfArgFormatter<Char>, Char, FormatSpec>
{ {
public: public:
/** Constructs an argument formatter object. */ /** Constructs an argument formatter object. */
PrintfArgFormatter(BasicWriter<Char> &w, FormatSpec &s) PrintfArgFormatter(BasicWriter<Char> &w, FormatSpec &s)
: BasicPrintfArgFormatter<PrintfArgFormatter<Char>, Char, FormatSpec>(w, s) {} : BasicPrintfArgFormatter<PrintfArgFormatter<Char>, Char, FormatSpec>(w, s)
{
}
}; };
/** This template formats data and writes the output to a writer. */ /** This template formats data and writes the output to a writer. */
@ -392,9 +404,7 @@ private:
// Returns the argument with specified index or, if arg_index is equal // Returns the argument with specified index or, if arg_index is equal
// to the maximum unsigned value, the next argument. // to the maximum unsigned value, the next argument.
internal::Arg get_arg( internal::Arg get_arg(const Char *s, unsigned arg_index = (std::numeric_limits<unsigned>::max)());
const Char *s,
unsigned arg_index = (std::numeric_limits<unsigned>::max)());
// Parses argument index, flags and width and returns the argument index. // Parses argument index, flags and width and returns the argument index.
unsigned parse_header(const Char *&s, FormatSpec &spec); unsigned parse_header(const Char *&s, FormatSpec &spec);
@ -408,7 +418,10 @@ public:
\endrst \endrst
*/ */
explicit PrintfFormatter(const ArgList &al, BasicWriter<Char> &w) explicit PrintfFormatter(const ArgList &al, BasicWriter<Char> &w)
: FormatterBase(al), writer_(w) {} : FormatterBase(al)
, writer_(w)
{
}
/** Formats stored arguments and writes the output to the writer. */ /** Formats stored arguments and writes the output to the writer. */
void format(BasicCStringRef<Char> format_str); void format(BasicCStringRef<Char> format_str);
@ -444,21 +457,18 @@ void PrintfFormatter<Char, AF>::parse_flags(FormatSpec &spec, const Char *&s)
} }
template<typename Char, typename AF> template<typename Char, typename AF>
internal::Arg PrintfFormatter<Char, AF>::get_arg(const Char *s, internal::Arg PrintfFormatter<Char, AF>::get_arg(const Char *s, unsigned arg_index)
unsigned arg_index)
{ {
(void)s; (void)s;
const char *error = FMT_NULL; const char *error = FMT_NULL;
internal::Arg arg = arg_index == std::numeric_limits<unsigned>::max() ? internal::Arg arg = arg_index == std::numeric_limits<unsigned>::max() ? next_arg(error) : FormatterBase::get_arg(arg_index - 1, error);
next_arg(error) : FormatterBase::get_arg(arg_index - 1, error);
if (error) if (error)
FMT_THROW(FormatError(!*s ? "invalid format string" : error)); FMT_THROW(FormatError(!*s ? "invalid format string" : error));
return arg; return arg;
} }
template<typename Char, typename AF> template<typename Char, typename AF>
unsigned PrintfFormatter<Char, AF>::parse_header( unsigned PrintfFormatter<Char, AF>::parse_header(const Char *&s, FormatSpec &spec)
const Char *&s, FormatSpec &spec)
{ {
unsigned arg_index = std::numeric_limits<unsigned>::max(); unsigned arg_index = std::numeric_limits<unsigned>::max();
Char c = *s; Char c = *s;
@ -507,7 +517,8 @@ void PrintfFormatter<Char, AF>::format(BasicCStringRef<Char> format_str)
while (*s) while (*s)
{ {
Char c = *s++; Char c = *s++;
if (c != '%') continue; if (c != '%')
continue;
if (*s == c) if (*s == c)
{ {
write(writer_, start, s); write(writer_, start, s);

@ -19,11 +19,9 @@
#pragma warning(disable : 4996) // "deprecated" functions #pragma warning(disable : 4996) // "deprecated" functions
#endif #endif
namespace fmt namespace fmt {
{
template<typename ArgFormatter> template<typename ArgFormatter>
void format_arg(BasicFormatter<char, ArgFormatter> &f, void format_arg(BasicFormatter<char, ArgFormatter> &f, const char *&format_str, const std::tm &tm)
const char *&format_str, const std::tm &tm)
{ {
if (*format_str == ':') if (*format_str == ':')
++format_str; ++format_str;
@ -60,8 +58,7 @@ void format_arg(BasicFormatter<char, ArgFormatter> &f,
format_str = end + 1; format_str = end + 1;
} }
namespace internal namespace internal {
{
inline Null<> localtime_r(...) inline Null<> localtime_r(...)
{ {
return Null<>(); return Null<>();
@ -78,7 +75,7 @@ inline Null<> gmtime_s(...)
{ {
return Null<>(); return Null<>();
} }
} } // namespace internal
// Thread-safe replacement for std::localtime // Thread-safe replacement for std::localtime
inline std::tm localtime(std::time_t time) inline std::tm localtime(std::time_t time)
@ -88,7 +85,10 @@ inline std::tm localtime(std::time_t time)
std::time_t time_; std::time_t time_;
std::tm tm_; std::tm tm_;
LocalTime(std::time_t t): time_(t) {} LocalTime(std::time_t t)
: time_(t)
{
}
bool run() bool run()
{ {
@ -116,7 +116,8 @@ inline std::tm localtime(std::time_t time)
{ {
using namespace fmt::internal; using namespace fmt::internal;
std::tm *tm = std::localtime(&time_); std::tm *tm = std::localtime(&time_);
if (tm) tm_ = *tm; if (tm)
tm_ = *tm;
return tm != FMT_NULL; return tm != FMT_NULL;
} }
}; };
@ -136,7 +137,10 @@ inline std::tm gmtime(std::time_t time)
std::time_t time_; std::time_t time_;
std::tm tm_; std::tm tm_;
GMTime(std::time_t t): time_(t) {} GMTime(std::time_t t)
: time_(t)
{
}
bool run() bool run()
{ {
@ -163,7 +167,8 @@ inline std::tm gmtime(std::time_t time)
bool fallback(internal::Null<>) bool fallback(internal::Null<>)
{ {
std::tm *tm = std::gmtime(&time_); std::tm *tm = std::gmtime(&time_);
if (tm != FMT_NULL) tm_ = *tm; if (tm != FMT_NULL)
tm_ = *tm;
return tm != FMT_NULL; return tm != FMT_NULL;
} }
}; };

@ -31,4 +31,3 @@
#endif #endif
#endif #endif

@ -4,14 +4,15 @@
// //
#pragma once #pragma once
//
// include external or bundled copy of fmtlib's ostream support // include bundled or external copy of fmtlib's ostream support
// //
#if !defined(SPDLOG_FMT_EXTERNAL) #if !defined(SPDLOG_FMT_EXTERNAL)
#include "fmt.h" #ifndef FMT_HEADER_ONLY
#define FMT_HEADER_ONLY
#endif
#include "bundled/ostream.h" #include "bundled/ostream.h"
#include "fmt.h"
#else #else
#include <fmt/ostream.h> #include <fmt/ostream.h>
#endif #endif

@ -7,14 +7,12 @@
#include "details/log_msg.h" #include "details/log_msg.h"
#include <vector>
#include <string>
#include <memory> #include <memory>
#include <string>
#include <vector>
namespace spdlog namespace spdlog {
{ namespace details {
namespace details
{
class flag_formatter; class flag_formatter;
} }
@ -28,7 +26,8 @@ public:
class pattern_formatter SPDLOG_FINAL : public formatter class pattern_formatter SPDLOG_FINAL : public formatter
{ {
public: public:
explicit pattern_formatter(const std::string& pattern, pattern_time_type pattern_time = pattern_time_type::local, std::string eol = spdlog::details::os::default_eol); explicit pattern_formatter(const std::string &pattern, pattern_time_type pattern_time = pattern_time_type::local,
std::string eol = spdlog::details::os::default_eol);
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;
@ -42,6 +41,6 @@ private:
void handle_flag(char flag); void handle_flag(char flag);
void compile_pattern(const std::string &pattern); void compile_pattern(const std::string &pattern);
}; };
} } // namespace spdlog
#include "details/pattern_formatter_impl.h" #include "details/pattern_formatter_impl.h"

@ -12,16 +12,15 @@
// 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 "sinks/base_sink.h"
#include "common.h" #include "common.h"
#include "sinks/base_sink.h"
#include <vector>
#include <memory> #include <memory>
#include <string> #include <string>
#include <unordered_map> #include <unordered_map>
#include <vector>
namespace spdlog namespace spdlog {
{
class logger class logger
{ {
@ -37,33 +36,76 @@ public:
logger(const logger &) = delete; logger(const logger &) = delete;
logger &operator=(const logger &) = delete; logger &operator=(const logger &) = delete;
template <typename... Args> void log(level::level_enum lvl, const char* fmt, const Args&... args); template<typename... Args>
template <typename... Args> void log(level::level_enum lvl, const char* msg); void log(level::level_enum lvl, const char *fmt, const Args &... args);
template <typename Arg1, typename... Args> void trace(const char* fmt, const Arg1&, const Args&... args);
template <typename Arg1, typename... Args> void debug(const char* fmt, const Arg1&, const Args&... args); template<typename... Args>
template <typename Arg1, typename... Args> void info(const char* fmt, const Arg1&, const Args&... args); void log(level::level_enum lvl, const char *msg);
template <typename Arg1, typename... Args> void warn(const char* fmt, const Arg1&, const Args&... args);
template <typename Arg1, typename... Args> void error(const char* fmt, const Arg1&, const Args&... args); template<typename Arg1, typename... Args>
template <typename Arg1, typename... Args> void critical(const char* fmt, const Arg1&, const Args&... args); void trace(const char *fmt, const Arg1 &, const Args &... args);
template<typename Arg1, typename... Args>
void debug(const char *fmt, const Arg1 &, const Args &... args);
template<typename Arg1, typename... Args>
void info(const char *fmt, const Arg1 &, const Args &... args);
template<typename Arg1, typename... Args>
void warn(const char *fmt, const Arg1 &, const Args &... args);
template<typename Arg1, typename... Args>
void error(const char *fmt, const Arg1 &, const Args &... args);
template<typename Arg1, typename... Args>
void critical(const char *fmt, const Arg1 &, const Args &... args);
#ifdef SPDLOG_WCHAR_TO_UTF8_SUPPORT #ifdef SPDLOG_WCHAR_TO_UTF8_SUPPORT
template <typename... Args> void log(level::level_enum lvl, const wchar_t* msg); template<typename... Args>
template <typename... Args> void log(level::level_enum lvl, const wchar_t* fmt, const Args&... args); void log(level::level_enum lvl, const wchar_t *msg);
template <typename... Args> void trace(const wchar_t* fmt, const Args&... args);
template <typename... Args> void debug(const wchar_t* fmt, const Args&... args); template<typename... Args>
template <typename... Args> void info(const wchar_t* fmt, const Args&... args); void log(level::level_enum lvl, const wchar_t *fmt, const Args &... args);
template <typename... Args> void warn(const wchar_t* fmt, const Args&... args);
template <typename... Args> void error(const wchar_t* fmt, const Args&... args); template<typename... Args>
template <typename... Args> void critical(const wchar_t* fmt, const Args&... args); void trace(const wchar_t *fmt, const Args &... args);
template<typename... Args>
void debug(const wchar_t *fmt, const Args &... args);
template<typename... Args>
void info(const wchar_t *fmt, const Args &... args);
template<typename... Args>
void warn(const wchar_t *fmt, const Args &... args);
template<typename... Args>
void error(const wchar_t *fmt, const Args &... args);
template<typename... Args>
void critical(const wchar_t *fmt, const Args &... args);
#endif // SPDLOG_WCHAR_TO_UTF8_SUPPORT #endif // SPDLOG_WCHAR_TO_UTF8_SUPPORT
template <typename T> void log(level::level_enum lvl, const T&); template<typename T>
template <typename T> void trace(const T& msg); void log(level::level_enum lvl, const T &);
template <typename T> void debug(const T& msg);
template <typename T> void info(const T& msg); template<typename T>
template <typename T> void warn(const T& msg); void trace(const T &msg);
template <typename T> void error(const T& msg);
template <typename T> void critical(const T& msg); template<typename T>
void debug(const T &msg);
template<typename T>
void info(const T &msg);
template<typename T>
void warn(const T &msg);
template<typename T>
void error(const T &msg);
template<typename T>
void critical(const T &msg);
bool should_log(level::level_enum msg_level) const; bool should_log(level::level_enum msg_level) const;
void set_level(level::level_enum log_level); void set_level(level::level_enum log_level);
@ -110,6 +152,6 @@ protected:
std::atomic<size_t> _msg_counter; std::atomic<size_t> _msg_counter;
std::unordered_map<char, std::string> _custom_flags; std::unordered_map<char, std::string> _custom_flags;
}; };
} } // namespace spdlog
#include "details/logger_impl.h" #include "details/logger_impl.h"

@ -7,23 +7,21 @@
#if defined(__ANDROID__) #if defined(__ANDROID__)
#include "sink.h"
#include "../details/os.h" #include "../details/os.h"
#include "sink.h"
#include <android/log.h>
#include <chrono>
#include <mutex> #include <mutex>
#include <string> #include <string>
#include <android/log.h>
#include <thread> #include <thread>
#include <chrono>
#if !defined(SPDLOG_ANDROID_RETRIES) #if !defined(SPDLOG_ANDROID_RETRIES)
#define SPDLOG_ANDROID_RETRIES 2 #define SPDLOG_ANDROID_RETRIES 2
#endif #endif
namespace spdlog namespace spdlog {
{ namespace sinks {
namespace sinks
{
/* /*
* Android sink (logging using __android_log_write) * Android sink (logging using __android_log_write)
@ -32,7 +30,11 @@ namespace sinks
class android_sink : public sink class android_sink : public sink
{ {
public: public:
explicit android_sink(const std::string& tag = "spdlog", bool use_raw_msg = false): _tag(tag), _use_raw_msg(use_raw_msg) {} explicit android_sink(const std::string &tag = "spdlog", bool use_raw_msg = false)
: _tag(tag)
, _use_raw_msg(use_raw_msg)
{
}
void log(const details::log_msg &msg) override void log(const details::log_msg &msg) override
{ {
@ -55,9 +57,7 @@ public:
} }
} }
void flush() override void flush() override {}
{
}
private: private:
static android_LogPriority convert_to_android(spdlog::level::level_enum level) static android_LogPriority convert_to_android(spdlog::level::level_enum level)
@ -85,7 +85,7 @@ private:
bool _use_raw_msg; bool _use_raw_msg;
}; };
} } // namespace sinks
} } // namespace spdlog
#endif #endif

@ -5,17 +5,15 @@
#pragma once #pragma once
#include "base_sink.h"
#include "../common.h" #include "../common.h"
#include "../details/os.h" #include "../details/os.h"
#include "base_sink.h"
#include <string> #include <string>
#include <unordered_map> #include <unordered_map>
namespace spdlog namespace spdlog {
{ namespace sinks {
namespace sinks
{
/** /**
* This sink prefixes the output with an ANSI escape sequence color code depending on the severity * This sink prefixes the output with an ANSI escape sequence color code depending on the severity
@ -26,12 +24,13 @@ template <class Mutex>
class ansicolor_sink : public base_sink<Mutex> class ansicolor_sink : public base_sink<Mutex>
{ {
public: public:
explicit ansicolor_sink(FILE* file) : target_file_(file) explicit ansicolor_sink(FILE *file)
: target_file_(file)
{ {
should_do_colors_ = details::os::in_terminal(file) && details::os::is_color_terminal(); should_do_colors_ = details::os::in_terminal(file) && details::os::is_color_terminal();
colors_[level::trace] = cyan; colors_[level::trace] = white;
colors_[level::debug] = cyan; colors_[level::debug] = cyan;
colors_[level::info] = reset; colors_[level::info] = green;
colors_[level::warn] = yellow + bold; colors_[level::warn] = yellow + bold;
colors_[level::err] = red + bold; colors_[level::err] = red + bold;
colors_[level::critical] = bold + on_red; colors_[level::critical] = bold + on_red;
@ -84,17 +83,20 @@ protected:
{ {
// Wrap the originally formatted message in color codes. // Wrap the originally formatted message in color codes.
// If color is not supported in the terminal, log as is instead. // If color is not supported in the terminal, log as is instead.
if (should_do_colors_) if (should_do_colors_ && msg.color_range_end > msg.color_range_start)
{ {
const std::string& prefix = colors_[msg.level]; // before color range
fwrite(prefix.data(), sizeof(char), prefix.size(), target_file_); _print_range(msg, 0, msg.color_range_start);
fwrite(msg.formatted.data(), sizeof(char), msg.formatted.size(), target_file_); // in color range
fwrite(reset.data(), sizeof(char), reset.size(), target_file_); _print_ccode(colors_[msg.level]);
fwrite(clear_line.data(), sizeof(char), clear_line.size(), target_file_); _print_range(msg, msg.color_range_start, msg.color_range_end);
_print_ccode(reset);
// after color range
_print_range(msg, msg.color_range_end, msg.formatted.size());
} }
else else
{ {
fwrite(msg.formatted.data(), sizeof(char), msg.formatted.size(), target_file_); _print_range(msg, 0, msg.formatted.size());
} }
_flush(); _flush();
} }
@ -104,18 +106,28 @@ protected:
fflush(target_file_); fflush(target_file_);
} }
private:
void _print_ccode(const std::string &color_code)
{
fwrite(color_code.data(), sizeof(char), color_code.size(), target_file_);
}
void _print_range(const details::log_msg &msg, size_t start, size_t end)
{
fwrite(msg.formatted.data() + start, sizeof(char), end - start, target_file_);
}
FILE *target_file_; FILE *target_file_;
bool should_do_colors_; bool should_do_colors_;
std::unordered_map<level::level_enum, std::string, level::level_hasher> colors_; std::unordered_map<level::level_enum, std::string, level::level_hasher> colors_;
}; };
template<class Mutex> template<class Mutex>
class ansicolor_stdout_sink : public ansicolor_sink<Mutex> class ansicolor_stdout_sink : public ansicolor_sink<Mutex>
{ {
public: public:
ansicolor_stdout_sink(): ansicolor_sink<Mutex>(stdout) ansicolor_stdout_sink()
{} : ansicolor_sink<Mutex>(stdout)
{
}
}; };
using ansicolor_stdout_sink_mt = ansicolor_stdout_sink<std::mutex>; using ansicolor_stdout_sink_mt = ansicolor_stdout_sink<std::mutex>;
@ -125,8 +137,10 @@ template<class Mutex>
class ansicolor_stderr_sink : public ansicolor_sink<Mutex> class ansicolor_stderr_sink : public ansicolor_sink<Mutex>
{ {
public: public:
ansicolor_stderr_sink(): ansicolor_sink<Mutex>(stderr) ansicolor_stderr_sink()
{} : ansicolor_sink<Mutex>(stderr)
{
}
}; };
using ansicolor_stderr_sink_mt = ansicolor_stderr_sink<std::mutex>; using ansicolor_stderr_sink_mt = ansicolor_stderr_sink<std::mutex>;
@ -134,4 +148,3 @@ using ansicolor_stderr_sink_st = ansicolor_stderr_sink<details::null_mutex>;
} // namespace sinks } // namespace sinks
} // namespace spdlog } // namespace spdlog

@ -10,17 +10,15 @@
// all locking is taken care of here so no locking needed by the implementers.. // all locking is taken care of here so no locking needed by the implementers..
// //
#include "sink.h"
#include "../formatter.h"
#include "../common.h" #include "../common.h"
#include "../details/log_msg.h" #include "../details/log_msg.h"
#include "../formatter.h"
#include "sink.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
{ {
@ -47,5 +45,5 @@ protected:
virtual void _flush() = 0; virtual void _flush() = 0;
Mutex _mutex; Mutex _mutex;
}; };
} } // namespace sinks
} } // namespace spdlog

@ -11,21 +11,22 @@
#include "sink.h" #include "sink.h"
#include <algorithm> #include <algorithm>
#include <mutex>
#include <memory> #include <memory>
#include <mutex>
#include <vector> #include <vector>
// Distribution sink (mux). Stores a vector of sinks which get called when log is called // Distribution sink (mux). Stores a vector of sinks which get called when log is called
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;
@ -66,5 +67,5 @@ public:
using dist_sink_mt = dist_sink<std::mutex>; using dist_sink_mt = dist_sink<std::mutex>;
using dist_sink_st = dist_sink<details::null_mutex>; using dist_sink_st = dist_sink<details::null_mutex>;
} } // namespace sinks
} } // namespace spdlog

@ -5,23 +5,21 @@
#pragma once #pragma once
#include "base_sink.h"
#include "../details/null_mutex.h"
#include "../details/file_helper.h" #include "../details/file_helper.h"
#include "../details/null_mutex.h"
#include "../fmt/fmt.h" #include "../fmt/fmt.h"
#include "base_sink.h"
#include <algorithm> #include <algorithm>
#include <cerrno>
#include <chrono> #include <chrono>
#include <cstdio> #include <cstdio>
#include <ctime> #include <ctime>
#include <mutex> #include <mutex>
#include <string> #include <string>
#include <cerrno>
namespace spdlog namespace spdlog {
{ namespace sinks {
namespace sinks
{
/* /*
* Trivial file sink with single file as target * Trivial file sink with single file as target
*/ */
@ -29,7 +27,8 @@ template <class Mutex>
class simple_file_sink SPDLOG_FINAL : public base_sink<Mutex> class simple_file_sink SPDLOG_FINAL : public base_sink<Mutex>
{ {
public: public:
explicit simple_file_sink(const filename_t &filename, bool truncate = false):_force_flush(false) explicit simple_file_sink(const filename_t &filename, bool truncate = false)
: _force_flush(false)
{ {
_file_helper.open(filename, truncate); _file_helper.open(filename, truncate);
} }
@ -44,8 +43,10 @@ protected:
{ {
_file_helper.write(msg); _file_helper.write(msg);
if (_force_flush) if (_force_flush)
{
_file_helper.flush(); _file_helper.flush();
} }
}
void _flush() override void _flush() override
{ {
@ -67,11 +68,10 @@ template <class Mutex>
class rotating_file_sink SPDLOG_FINAL : public base_sink<Mutex> class rotating_file_sink SPDLOG_FINAL : public base_sink<Mutex>
{ {
public: public:
rotating_file_sink(filename_t base_filename, rotating_file_sink(filename_t base_filename, std::size_t max_size, std::size_t max_files)
std::size_t max_size, std::size_t max_files) : : _base_filename(std::move(base_filename))
_base_filename(std::move(base_filename)), , _max_size(max_size)
_max_size(max_size), , _max_files(max_files)
_max_files(max_files)
{ {
_file_helper.open(calc_filename(_base_filename, 0)); _file_helper.open(calc_filename(_base_filename, 0));
_current_size = _file_helper.size(); // expensive. called only once _current_size = _file_helper.size(); // expensive. called only once
@ -164,7 +164,8 @@ struct default_daily_file_name_calculator
filename_t basename, ext; filename_t basename, ext;
std::tie(basename, ext) = details::file_helper::split_by_extenstion(filename); std::tie(basename, ext) = details::file_helper::split_by_extenstion(filename);
std::conditional<std::is_same<filename_t::value_type, char>::value, fmt::MemoryWriter, fmt::WMemoryWriter>::type w; std::conditional<std::is_same<filename_t::value_type, char>::value, fmt::MemoryWriter, fmt::WMemoryWriter>::type w;
w.write(SPDLOG_FILENAME_T("{}_{:04d}-{:02d}-{:02d}_{:02d}-{:02d}{}"), basename, tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, ext); w.write(SPDLOG_FILENAME_T("{}_{:04d}-{:02d}-{:02d}_{:02d}-{:02d}{}"), basename, tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
tm.tm_hour, tm.tm_min, ext);
return w.str(); return w.str();
} }
}; };
@ -194,21 +195,19 @@ class daily_file_sink SPDLOG_FINAL :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(filename_t base_filename, int rotation_hour, int rotation_minute)
filename_t base_filename, : _base_filename(std::move(base_filename))
int rotation_hour, , _rotation_h(rotation_hour)
int rotation_minute) : , _rotation_m(rotation_minute)
_base_filename(std::move(base_filename)),
_rotation_h(rotation_hour),
_rotation_m(rotation_minute)
{ {
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(FileNameCalc::calc_filename(_base_filename)); _file_helper.open(FileNameCalc::calc_filename(_base_filename));
} }
protected: protected:
void _sink_it(const details::log_msg &msg) override void _sink_it(const details::log_msg &msg) override
{ {
@ -252,5 +251,5 @@ private:
using daily_file_sink_mt = daily_file_sink<std::mutex>; using daily_file_sink_mt = daily_file_sink<std::mutex>;
using daily_file_sink_st = daily_file_sink<details::null_mutex>; using daily_file_sink_st = daily_file_sink<details::null_mutex>;
} } // namespace sinks
} } // namespace spdlog

@ -7,18 +7,16 @@
#if defined(_WIN32) #if defined(_WIN32)
#include "base_sink.h"
#include "../details/null_mutex.h" #include "../details/null_mutex.h"
#include "base_sink.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)
*/ */
@ -26,9 +24,7 @@ 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() {}
{
}
protected: protected:
void _sink_it(const details::log_msg &msg) override void _sink_it(const details::log_msg &msg) override
@ -36,14 +32,13 @@ protected:
OutputDebugStringA(msg.formatted.c_str()); OutputDebugStringA(msg.formatted.c_str());
} }
void _flush() override void _flush() override {}
{}
}; };
using msvc_sink_mt = msvc_sink<std::mutex>; using msvc_sink_mt = msvc_sink<std::mutex>;
using msvc_sink_st = msvc_sink<details::null_mutex>; using msvc_sink_st = msvc_sink<details::null_mutex>;
} } // namespace sinks
} } // namespace spdlog
#endif #endif

@ -5,31 +5,25 @@
#pragma once #pragma once
#include "base_sink.h"
#include "../details/null_mutex.h" #include "../details/null_mutex.h"
#include "base_sink.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 {}
}; };
using null_sink_mt = null_sink<details::null_mutex>; using null_sink_mt = null_sink<details::null_mutex>;
using null_sink_st = null_sink<details::null_mutex>; using null_sink_st = null_sink<details::null_mutex>;
} } // namespace sinks
} } // namespace spdlog

@ -8,18 +8,20 @@
#include "../details/null_mutex.h" #include "../details/null_mutex.h"
#include "base_sink.h" #include "base_sink.h"
#include <ostream>
#include <mutex> #include <mutex>
#include <ostream>
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;
@ -43,5 +45,5 @@ protected:
using ostream_sink_mt = ostream_sink<std::mutex>; using ostream_sink_mt = ostream_sink<std::mutex>;
using ostream_sink_st = ostream_sink<details::null_mutex>; using ostream_sink_st = ostream_sink<details::null_mutex>;
} } // namespace sinks
} } // namespace spdlog

@ -7,10 +7,8 @@
#include "../details/log_msg.h" #include "../details/log_msg.h"
namespace spdlog namespace spdlog {
{ namespace sinks {
namespace sinks
{
class sink class sink
{ {
public: public:
@ -42,5 +40,5 @@ inline level::level_enum sink::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));
} }
} } // namespace sinks
} } // namespace spdlog

@ -12,10 +12,8 @@
#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 SPDLOG_FINAL : public base_sink<Mutex> class stdout_sink SPDLOG_FINAL : public base_sink<Mutex>
@ -77,5 +75,5 @@ protected:
using stderr_sink_mt = stderr_sink<std::mutex>; using stderr_sink_mt = stderr_sink<std::mutex>;
using stderr_sink_st = stderr_sink<details::null_mutex>; using stderr_sink_st = stderr_sink<details::null_mutex>;
} } // namespace sinks
} } // namespace spdlog

@ -9,18 +9,15 @@
#ifdef SPDLOG_ENABLE_SYSLOG #ifdef SPDLOG_ENABLE_SYSLOG
#include "sink.h"
#include "../details/log_msg.h" #include "../details/log_msg.h"
#include "sink.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.
* *
@ -30,8 +27,8 @@ 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<size_t>(level::trace)] = LOG_DEBUG; _priorities[static_cast<size_t>(level::trace)] = LOG_DEBUG;
_priorities[static_cast<size_t>(level::debug)] = LOG_DEBUG; _priorities[static_cast<size_t>(level::debug)] = LOG_DEBUG;
@ -58,10 +55,7 @@ public:
::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, 7> _priorities; std::array<int, 7> _priorities;
@ -76,7 +70,7 @@ private:
return _priorities[static_cast<size_t>(msg.level)]; return _priorities[static_cast<size_t>(msg.level)];
} }
}; };
} } // namespace sinks
} } // namespace spdlog
#endif #endif

@ -5,19 +5,17 @@
#pragma once #pragma once
#include "base_sink.h"
#include "../details/null_mutex.h"
#include "../common.h" #include "../common.h"
#include "../details/null_mutex.h"
#include "base_sink.h"
#include <mutex> #include <mutex>
#include <string> #include <string>
#include <unordered_map> #include <unordered_map>
#include <wincon.h> #include <wincon.h>
namespace spdlog namespace spdlog {
{ namespace sinks {
namespace sinks
{
/* /*
* Windows color console sink. Uses WriteConsoleA to write to the console with colors * Windows color console sink. Uses WriteConsoleA to write to the console with colors
*/ */
@ -27,15 +25,17 @@ class wincolor_sink : public base_sink<Mutex>
public: public:
const WORD BOLD = FOREGROUND_INTENSITY; const WORD BOLD = FOREGROUND_INTENSITY;
const WORD RED = FOREGROUND_RED; const WORD RED = FOREGROUND_RED;
const WORD GREEN = FOREGROUND_GREEN;
const WORD CYAN = FOREGROUND_GREEN | FOREGROUND_BLUE; const WORD CYAN = FOREGROUND_GREEN | FOREGROUND_BLUE;
const WORD WHITE = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE; const WORD WHITE = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE;
const WORD YELLOW = FOREGROUND_RED | FOREGROUND_GREEN; const WORD YELLOW = FOREGROUND_RED | FOREGROUND_GREEN;
wincolor_sink(HANDLE std_handle): out_handle_(std_handle) wincolor_sink(HANDLE std_handle)
: out_handle_(std_handle)
{ {
colors_[level::trace] = CYAN; colors_[level::trace] = WHITE;
colors_[level::debug] = CYAN; colors_[level::debug] = CYAN;
colors_[level::info] = WHITE | BOLD; colors_[level::info] = GREEN;
colors_[level::warn] = YELLOW | BOLD; colors_[level::warn] = YELLOW | BOLD;
colors_[level::err] = RED | BOLD; // red bold colors_[level::err] = RED | BOLD; // red bold
colors_[level::critical] = BACKGROUND_RED | WHITE | BOLD; // white bold on red background colors_[level::critical] = BACKGROUND_RED | WHITE | BOLD; // white bold on red background
@ -60,10 +60,22 @@ public:
protected: protected:
void _sink_it(const details::log_msg &msg) override void _sink_it(const details::log_msg &msg) override
{ {
auto color = colors_[msg.level]; if (msg.color_range_end > msg.color_range_start)
auto orig_attribs = set_console_attribs(color); {
WriteConsoleA(out_handle_, msg.formatted.data(), static_cast<DWORD>(msg.formatted.size()), nullptr, nullptr); // before color range
SetConsoleTextAttribute(out_handle_, orig_attribs); //reset to orig colors _print_range(msg, 0, msg.color_range_start);
// in color range
auto orig_attribs = set_console_attribs(colors_[msg.level]);
_print_range(msg, msg.color_range_start, msg.color_range_end);
::SetConsoleTextAttribute(out_handle_, orig_attribs); // reset to orig colors
// after color range
_print_range(msg, msg.color_range_end, msg.formatted.size());
}
else // print without colors if color range is invalid
{
_print_range(msg, 0, msg.formatted.size());
}
} }
void _flush() override void _flush() override
@ -87,6 +99,13 @@ private:
SetConsoleTextAttribute(out_handle_, attribs | back_color); SetConsoleTextAttribute(out_handle_, attribs | back_color);
return orig_buffer_info.wAttributes; // return orig attribs return orig_buffer_info.wAttributes; // return orig attribs
} }
// print a range of formatted message to console
void _print_range(const details::log_msg &msg, size_t start, size_t end)
{
DWORD size = static_cast<DWORD>(end - start);
WriteConsoleA(out_handle_, msg.formatted.data() + start, size, nullptr, nullptr);
}
}; };
// //
@ -96,8 +115,10 @@ template <class Mutex>
class wincolor_stdout_sink : public wincolor_sink<Mutex> class wincolor_stdout_sink : public wincolor_sink<Mutex>
{ {
public: public:
wincolor_stdout_sink() : wincolor_sink<Mutex>(GetStdHandle(STD_OUTPUT_HANDLE)) wincolor_stdout_sink()
{} : wincolor_sink<Mutex>(GetStdHandle(STD_OUTPUT_HANDLE))
{
}
}; };
using wincolor_stdout_sink_mt = wincolor_stdout_sink<std::mutex>; using wincolor_stdout_sink_mt = wincolor_stdout_sink<std::mutex>;
@ -110,12 +131,14 @@ template <class Mutex>
class wincolor_stderr_sink : public wincolor_sink<Mutex> class wincolor_stderr_sink : public wincolor_sink<Mutex>
{ {
public: public:
wincolor_stderr_sink() : wincolor_sink<Mutex>(GetStdHandle(STD_ERROR_HANDLE)) wincolor_stderr_sink()
{} : wincolor_sink<Mutex>(GetStdHandle(STD_ERROR_HANDLE))
{
}
}; };
using wincolor_stderr_sink_mt = wincolor_stderr_sink<std::mutex>; using wincolor_stderr_sink_mt = wincolor_stderr_sink<std::mutex>;
using wincolor_stderr_sink_st = wincolor_stderr_sink<details::null_mutex>; using wincolor_stderr_sink_st = wincolor_stderr_sink<details::null_mutex>;
} } // namespace sinks
} } // namespace spdlog

@ -9,10 +9,8 @@
#include "msvc_sink.h" #include "msvc_sink.h"
namespace spdlog namespace spdlog {
{ namespace sinks {
namespace sinks
{
/* /*
* Windows debug sink (logging using OutputDebugStringA, synonym for msvc_sink) * Windows debug sink (logging using OutputDebugStringA, synonym for msvc_sink)
@ -23,7 +21,7 @@ using windebug_sink = msvc_sink<Mutex>;
using windebug_sink_mt = msvc_sink_mt; using windebug_sink_mt = msvc_sink_mt;
using windebug_sink_st = msvc_sink_st; using windebug_sink_st = msvc_sink_st;
} } // namespace sinks
} } // namespace spdlog
#endif #endif

@ -7,17 +7,15 @@
#pragma once #pragma once
#include "common.h" #include "common.h"
#include "logger.h" #include "logger.h"
#include <memory>
#include <functional>
#include <chrono> #include <chrono>
#include <functional>
#include <memory>
#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.
@ -25,7 +23,6 @@ namespace spdlog
// //
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");
@ -73,12 +70,14 @@ const std::string& value_custom_flag(char flag);
// worker_teardown_cb (optional): // worker_teardown_cb (optional):
// callback function that will be called in worker thread upon exit // callback function that will be called in worker thread upon exit
// //
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(), const std::function<void()>& worker_teardown_cb = nullptr); 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(),
const std::function<void()> &worker_teardown_cb = nullptr);
// Turn off async mode // Turn off async mode
void set_sync_mode(); void set_sync_mode();
// //
// Create and register multi/single threaded basic file logger. // Create and register multi/single threaded basic file logger.
// Basic logger simply writes to given file without any limitations or rotations. // Basic logger simply writes to given file without any limitations or rotations.
@ -89,8 +88,11 @@ std::shared_ptr<logger> basic_logger_st(const std::string& logger_name, const fi
// //
// 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 filename_t& filename, size_t max_file_size, size_t max_files); std::shared_ptr<logger> rotating_logger_mt(
std::shared_ptr<logger> rotating_logger_st(const std::string& logger_name, const filename_t& filename, size_t max_file_size, size_t max_files); const std::string &logger_name, const filename_t &filename, size_t max_file_size, size_t max_files);
std::shared_ptr<logger> rotating_logger_st(
const std::string &logger_name, const filename_t &filename, size_t max_file_size, size_t max_files);
// //
// 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):
@ -113,12 +115,12 @@ std::shared_ptr<logger> stdout_color_st(const std::string& logger_name);
std::shared_ptr<logger> stderr_color_mt(const std::string &logger_name); std::shared_ptr<logger> stderr_color_mt(const std::string &logger_name);
std::shared_ptr<logger> stderr_color_st(const std::string &logger_name); std::shared_ptr<logger> stderr_color_st(const std::string &logger_name);
// //
// Create and register a syslog logger // Create and register a syslog logger
// //
#ifdef SPDLOG_ENABLE_SYSLOG #ifdef SPDLOG_ENABLE_SYSLOG
std::shared_ptr<logger> syslog_logger(const std::string& logger_name, const std::string& ident = "", int syslog_option = 0, int syslog_facilty = (1<<3)); std::shared_ptr<logger> syslog_logger(
const std::string &logger_name, const std::string &ident = "", int syslog_option = 0, int syslog_facilty = (1 << 3));
#endif #endif
#if defined(__ANDROID__) #if defined(__ANDROID__)
@ -130,10 +132,10 @@ std::shared_ptr<logger> create(const std::string& logger_name, const sink_ptr& s
// 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: // Example:
// spdlog::create<daily_file_sink_st>("mylog", "dailylog_filename"); // spdlog::create<daily_file_sink_st>("mylog", "dailylog_filename");
@ -141,12 +143,25 @@ template <typename Sink, typename... Args>
std::shared_ptr<spdlog::logger> create(const std::string &logger_name, Args... args); std::shared_ptr<spdlog::logger> create(const std::string &logger_name, Args... args);
// Create and register an async logger with a single sink // Create and register an async logger with a single sink
std::shared_ptr<logger> create_async(const std::string& logger_name, const sink_ptr& sink, 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(), const std::function<void()>& worker_teardown_cb = nullptr); std::shared_ptr<logger> create_async(const std::string &logger_name, const sink_ptr &sink, 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(),
const std::function<void()> &worker_teardown_cb = nullptr);
// Create and register an async logger with multiple sinks // Create and register an async logger with multiple sinks
std::shared_ptr<logger> create_async(const std::string& logger_name, sinks_init_list sinks, 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(), const std::function<void()>& worker_teardown_cb = nullptr); std::shared_ptr<logger> create_async(const std::string &logger_name, sinks_init_list sinks, 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(),
const std::function<void()> &worker_teardown_cb = nullptr);
template<class It> template<class It>
std::shared_ptr<logger> create_async(const std::string& logger_name, const It& sinks_begin, const It& sinks_end, 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(), const std::function<void()>& worker_teardown_cb = nullptr); std::shared_ptr<logger> create_async(const std::string &logger_name, const It &sinks_begin, const It &sinks_end, 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(),
const std::function<void()> &worker_teardown_cb = nullptr);
// 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);
@ -162,7 +177,6 @@ void drop(const std::string &name);
// Drop all references from the registry // Drop all references from the registry
void drop_all(); void drop_all();
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// //
// 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.
@ -194,6 +208,6 @@ void drop_all();
#define SPDLOG_DEBUG(logger, ...) (void)0 #define SPDLOG_DEBUG(logger, ...) (void)0
#endif #endif
} } // namespace spdlog
#include "details/spdlog_impl.h" #include "details/spdlog_impl.h"

@ -11,7 +11,6 @@
// //
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// Under Linux, the much faster CLOCK_REALTIME_COARSE clock can be used. // Under Linux, the much faster CLOCK_REALTIME_COARSE clock can be used.
// This clock is less accurate - can be off by dozens of millis - depending on the kernel HZ. // This clock is less accurate - can be off by dozens of millis - depending on the kernel HZ.
@ -20,7 +19,6 @@
// #define SPDLOG_CLOCK_COARSE // #define SPDLOG_CLOCK_COARSE
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// Uncomment if date/time logging is not needed and never appear in the log pattern. // Uncomment if date/time logging is not needed and never appear in the log pattern.
// This will prevent spdlog from querying the clock on each log call. // This will prevent spdlog from querying the clock on each log call.
@ -31,7 +29,6 @@
// #define SPDLOG_NO_DATETIME // #define SPDLOG_NO_DATETIME
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// Uncomment if thread id logging is not needed (i.e. no %t in the log pattern). // Uncomment if thread id logging is not needed (i.e. no %t in the log pattern).
// This will prevent spdlog from querying the thread id on each log call. // This will prevent spdlog from querying the thread id on each log call.
@ -41,7 +38,6 @@
// #define SPDLOG_NO_THREAD_ID // #define SPDLOG_NO_THREAD_ID
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// Uncomment to prevent spdlog from caching thread ids in thread local storage. // Uncomment to prevent spdlog from caching thread ids in thread local storage.
// By default spdlog saves thread ids in tls to gain a few micros for each call. // By default spdlog saves thread ids in tls to gain a few micros for each call.
@ -51,7 +47,6 @@
// #define SPDLOG_DISABLE_TID_CACHING // #define SPDLOG_DISABLE_TID_CACHING
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// Uncomment if logger name logging is not needed. // Uncomment if logger name logging is not needed.
// This will prevent spdlog from copying the logger name on each log call. // This will prevent spdlog from copying the logger name on each log call.
@ -66,7 +61,6 @@
// #define SPDLOG_TRACE_ON // #define SPDLOG_TRACE_ON
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// Uncomment to avoid locking in the registry operations (spdlog::get(), spdlog::drop() spdlog::register()). // Uncomment to avoid locking in the registry operations (spdlog::get(), spdlog::drop() spdlog::register()).
// Use only if your code never modifies concurrently the registry. // Use only if your code never modifies concurrently the registry.
@ -75,7 +69,6 @@
// #define SPDLOG_NO_REGISTRY_MUTEX // #define SPDLOG_NO_REGISTRY_MUTEX
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// Uncomment to avoid spdlog's usage of atomic log levels // Uncomment to avoid spdlog's usage of atomic log levels
// Use only if your code never modifies a logger's log levels concurrently by different threads. // Use only if your code never modifies a logger's log levels concurrently by different threads.
@ -83,21 +76,18 @@
// #define SPDLOG_NO_ATOMIC_LEVELS // #define SPDLOG_NO_ATOMIC_LEVELS
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// Uncomment to enable usage of wchar_t for file names on Windows. // Uncomment to enable usage of wchar_t for file names on Windows.
// //
// #define SPDLOG_WCHAR_FILENAMES // #define SPDLOG_WCHAR_FILENAMES
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// Uncomment to override default eol ("\n" or "\r\n" under Linux/Windows) // Uncomment to override default eol ("\n" or "\r\n" under Linux/Windows)
// //
// #define SPDLOG_EOL ";-)\n" // #define SPDLOG_EOL ";-)\n"
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// Uncomment to use your own copy of the fmt library instead of spdlog's copy. // Uncomment to use your own copy of the fmt library instead of spdlog's copy.
// In this case spdlog will try to include <fmt/format.h> so set your -I flag accordingly. // In this case spdlog will try to include <fmt/format.h> so set your -I flag accordingly.
@ -105,7 +95,6 @@
// #define SPDLOG_FMT_EXTERNAL // #define SPDLOG_FMT_EXTERNAL
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// Uncomment to use printf-style messages in your logs instead of the usual // Uncomment to use printf-style messages in your logs instead of the usual
// format-style used by default. // format-style used by default.
@ -113,28 +102,24 @@
// #define SPDLOG_FMT_PRINTF // #define SPDLOG_FMT_PRINTF
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// Uncomment to enable syslog (disabled by default) // Uncomment to enable syslog (disabled by default)
// //
// #define SPDLOG_ENABLE_SYSLOG // #define SPDLOG_ENABLE_SYSLOG
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// Uncomment to enable wchar_t support (convert to utf8) // Uncomment to enable wchar_t support (convert to utf8)
// //
// #define SPDLOG_WCHAR_TO_UTF8_SUPPORT // #define SPDLOG_WCHAR_TO_UTF8_SUPPORT
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// Uncomment to prevent child processes from inheriting log file descriptors // Uncomment to prevent child processes from inheriting log file descriptors
// //
// #define SPDLOG_PREVENT_CHILD_FD // #define SPDLOG_PREVENT_CHILD_FD
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// Uncomment if your compiler doesn't support the "final" keyword. // Uncomment if your compiler doesn't support the "final" keyword.
// The final keyword allows more optimizations in release // The final keyword allows more optimizations in release
@ -144,7 +129,6 @@
// #define SPDLOG_NO_FINAL // #define SPDLOG_NO_FINAL
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// Uncomment to enable message counting feature. // Uncomment to enable message counting feature.
// Use the %i in the logger pattern to display log message sequence id. // Use the %i in the logger pattern to display log message sequence id.
@ -152,7 +136,6 @@
// #define SPDLOG_ENABLE_MESSAGE_COUNTER // #define SPDLOG_ENABLE_MESSAGE_COUNTER
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// Uncomment to customize level names (e.g. "MT TRACE") // Uncomment to customize level names (e.g. "MT TRACE")
// //

@ -5,9 +5,6 @@
#include <iostream> #include <iostream>
class failing_sink : public spdlog::sinks::sink class failing_sink : public spdlog::sinks::sink
{ {
void log(const spdlog::details::log_msg &msg) override void log(const spdlog::details::log_msg &msg) override
@ -15,8 +12,7 @@ class failing_sink: public spdlog::sinks::sink
throw std::runtime_error("some error happened during log"); throw std::runtime_error("some error happened during log");
} }
void flush() override void flush() override {}
{}
}; };
TEST_CASE("default_error_handler", "[errors]]") TEST_CASE("default_error_handler", "[errors]]")
@ -39,21 +35,16 @@ TEST_CASE("default_error_handler", "[errors]]")
REQUIRE(count_lines(filename) == 1); REQUIRE(count_lines(filename) == 1);
} }
struct custom_ex struct custom_ex
{}; {
};
TEST_CASE("custom_error_handler", "[errors]]") TEST_CASE("custom_error_handler", "[errors]]")
{ {
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, true); auto logger = spdlog::create<spdlog::sinks::simple_file_sink_mt>("logger", filename, true);
logger->flush_on(spdlog::level::info); logger->flush_on(spdlog::level::info);
logger->set_error_handler([=](const std::string& msg) logger->set_error_handler([=](const std::string &msg) { throw custom_ex(); });
{
throw custom_ex();
});
logger->info("Good message #1"); logger->info("Good message #1");
#if !defined(SPDLOG_FMT_PRINTF) #if !defined(SPDLOG_FMT_PRINTF)
REQUIRE_THROWS_AS(logger->info("Bad format msg {} {}", "xxx"), custom_ex); REQUIRE_THROWS_AS(logger->info("Bad format msg {} {}", "xxx"), custom_ex);
@ -68,10 +59,7 @@ TEST_CASE("default_error_handler2", "[errors]]")
{ {
auto logger = spdlog::create<failing_sink>("failed_logger"); auto logger = spdlog::create<failing_sink>("failed_logger");
logger->set_error_handler([=](const std::string& msg) logger->set_error_handler([=](const std::string &msg) { throw custom_ex(); });
{
throw custom_ex();
});
REQUIRE_THROWS_AS(logger->info("Some message"), custom_ex); REQUIRE_THROWS_AS(logger->info("Some message"), custom_ex);
} }
@ -83,10 +71,10 @@ TEST_CASE("async_error_handler", "[errors]]")
std::string filename = "logs/simple_async_log.txt"; std::string filename = "logs/simple_async_log.txt";
{ {
auto logger = spdlog::create<spdlog::sinks::simple_file_sink_mt>("logger", filename, true); auto logger = spdlog::create<spdlog::sinks::simple_file_sink_mt>("logger", filename, true);
logger->set_error_handler([=](const std::string& msg) logger->set_error_handler([=](const std::string &msg) {
{
std::ofstream ofs("logs/custom_err.txt"); std::ofstream ofs("logs/custom_err.txt");
if (!ofs) throw std::runtime_error("Failed open logs/custom_err.txt"); if (!ofs)
throw std::runtime_error("Failed open logs/custom_err.txt");
ofs << err_msg; ofs << err_msg;
}); });
logger->info("Good message #1"); logger->info("Good message #1");
@ -111,10 +99,10 @@ TEST_CASE("async_error_handler2", "[errors]]")
spdlog::set_async_mode(128); spdlog::set_async_mode(128);
{ {
auto logger = spdlog::create<failing_sink>("failed_logger"); auto logger = spdlog::create<failing_sink>("failed_logger");
logger->set_error_handler([=](const std::string& msg) logger->set_error_handler([=](const std::string &msg) {
{
std::ofstream ofs("logs/custom_err2.txt"); std::ofstream ofs("logs/custom_err2.txt");
if (!ofs) throw std::runtime_error("Failed open logs/custom_err2.txt"); if (!ofs)
throw std::runtime_error("Failed open logs/custom_err2.txt");
ofs << err_msg; ofs << err_msg;
}); });
logger->info("Hello failure"); logger->info("Hello failure");

@ -3,8 +3,8 @@
*/ */
#include "includes.h" #include "includes.h"
using spdlog::details::log_msg;
using spdlog::details::file_helper; using spdlog::details::file_helper;
using spdlog::details::log_msg;
static const std::string target_filename = "logs/file_helper_test.txt"; static const std::string target_filename = "logs/file_helper_test.txt";

@ -3,7 +3,6 @@
*/ */
#include "includes.h" #include "includes.h"
TEST_CASE("simple_file_logger", "[simple_logger]]") TEST_CASE("simple_file_logger", "[simple_logger]]")
{ {
prepare_logdir(); prepare_logdir();
@ -24,7 +23,6 @@ TEST_CASE("simple_file_logger", "[simple_logger]]")
REQUIRE(count_lines(filename) == 2); REQUIRE(count_lines(filename) == 2);
} }
TEST_CASE("flush_on", "[flush_on]]") TEST_CASE("flush_on", "[flush_on]]")
{ {
prepare_logdir(); prepare_logdir();
@ -69,7 +67,6 @@ TEST_CASE("rotating_file_logger1", "[rotating_logger]]")
REQUIRE(count_lines(filename) == 10); REQUIRE(count_lines(filename) == 10);
} }
TEST_CASE("rotating_file_logger2", "[rotating_logger]]") TEST_CASE("rotating_file_logger2", "[rotating_logger]]")
{ {
prepare_logdir(); prepare_logdir();
@ -96,7 +93,6 @@ TEST_CASE("rotating_file_logger2", "[rotating_logger]]")
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();
@ -121,12 +117,9 @@ TEST_CASE("daily_logger", "[daily_logger]]")
REQUIRE(count_lines(filename) == 10); REQUIRE(count_lines(filename) == 10);
} }
TEST_CASE("daily_logger with dateonly calculator", "[daily_logger_dateonly]]") TEST_CASE("daily_logger with dateonly calculator", "[daily_logger_dateonly]]")
{ {
using sink_type = spdlog::sinks::daily_file_sink< using sink_type = spdlog::sinks::daily_file_sink<std::mutex, spdlog::sinks::dateonly_daily_file_name_calculator>;
std::mutex,
spdlog::sinks::dateonly_daily_file_name_calculator>;
prepare_logdir(); prepare_logdir();
// calculate filename (time based) // calculate filename (time based)
@ -162,9 +155,7 @@ struct custom_daily_file_name_calculator
TEST_CASE("daily_logger with custom calculator", "[daily_logger_custom]]") TEST_CASE("daily_logger with custom calculator", "[daily_logger_custom]]")
{ {
using sink_type = spdlog::sinks::daily_file_sink< using sink_type = spdlog::sinks::daily_file_sink<std::mutex, custom_daily_file_name_calculator>;
std::mutex,
custom_daily_file_name_calculator>;
prepare_logdir(); prepare_logdir();
// calculate filename (time based) // calculate filename (time based)
@ -188,7 +179,6 @@ TEST_CASE("daily_logger with custom calculator", "[daily_logger_custom]]")
REQUIRE(count_lines(filename) == 10); REQUIRE(count_lines(filename) == 10);
} }
/* /*
* File name calculations * File name calculations
*/ */
@ -211,10 +201,6 @@ TEST_CASE("rotating_file_sink::calc_filename3", "[rotating_file_sink]]")
REQUIRE(filename == "rotated.txt"); REQUIRE(filename == "rotated.txt");
} }
// regex supported only from gcc 4.9 and above // regex supported only from gcc 4.9 and above
#if defined(_MSC_VER) || !(__GNUC__ <= 4 && __GNUC_MINOR__ < 9) #if defined(_MSC_VER) || !(__GNUC__ <= 4 && __GNUC_MINOR__ < 9)
#include <regex> #include <regex>

@ -1,18 +1,17 @@
#pragma once #pragma once
#include "catch.hpp"
#include "utils.h"
#include <chrono>
#include <cstdio> #include <cstdio>
#include <exception>
#include <fstream> #include <fstream>
#include <string>
#include <ostream> #include <ostream>
#include <chrono> #include <string>
#include <exception>
#include "catch.hpp"
#include "utils.h"
#define SPDLOG_TRACE_ON #define SPDLOG_TRACE_ON
#define SPDLOG_DEBUG_ON #define SPDLOG_DEBUG_ON
#include "../include/spdlog/spdlog.h"
#include "../include/spdlog/sinks/null_sink.h" #include "../include/spdlog/sinks/null_sink.h"
#include "../include/spdlog/sinks/ostream_sink.h" #include "../include/spdlog/sinks/ostream_sink.h"
#include "../include/spdlog/spdlog.h"

@ -12,8 +12,8 @@ TEST_CASE("register_drop", "[registry]")
REQUIRE_THROWS_AS(spdlog::create<spdlog::sinks::null_sink_mt>(tested_logger_name), spdlog::spdlog_ex); REQUIRE_THROWS_AS(spdlog::create<spdlog::sinks::null_sink_mt>(tested_logger_name), spdlog::spdlog_ex);
} }
TEST_CASE("explicit register"
TEST_CASE("explicit register" "[registry]") "[registry]")
{ {
spdlog::drop_all(); spdlog::drop_all();
auto logger = std::make_shared<spdlog::logger>(tested_logger_name, std::make_shared<spdlog::sinks::null_sink_st>()); auto logger = std::make_shared<spdlog::logger>(tested_logger_name, std::make_shared<spdlog::sinks::null_sink_st>());
@ -23,7 +23,8 @@ TEST_CASE("explicit register" "[registry]")
REQUIRE_THROWS_AS(spdlog::create<spdlog::sinks::null_sink_mt>(tested_logger_name), spdlog::spdlog_ex); REQUIRE_THROWS_AS(spdlog::create<spdlog::sinks::null_sink_mt>(tested_logger_name), spdlog::spdlog_ex);
} }
TEST_CASE("apply_all" "[registry]") TEST_CASE("apply_all"
"[registry]")
{ {
spdlog::drop_all(); spdlog::drop_all();
auto logger = std::make_shared<spdlog::logger>(tested_logger_name, std::make_shared<spdlog::sinks::null_sink_st>()); auto logger = std::make_shared<spdlog::logger>(tested_logger_name, std::make_shared<spdlog::sinks::null_sink_st>());
@ -32,26 +33,20 @@ TEST_CASE("apply_all" "[registry]")
spdlog::register_logger(logger2); spdlog::register_logger(logger2);
int counter = 0; int counter = 0;
spdlog::apply_all([&counter](std::shared_ptr<spdlog::logger> l) spdlog::apply_all([&counter](std::shared_ptr<spdlog::logger> l) { counter++; });
{
counter++;
});
REQUIRE(counter == 2); REQUIRE(counter == 2);
counter = 0; counter = 0;
spdlog::drop(tested_logger_name2); spdlog::drop(tested_logger_name2);
spdlog::apply_all([&counter](std::shared_ptr<spdlog::logger> l) spdlog::apply_all([&counter](std::shared_ptr<spdlog::logger> l) {
{
REQUIRE(l->name() == tested_logger_name); REQUIRE(l->name() == tested_logger_name);
counter++; counter++;
} });
);
REQUIRE(counter == 1); REQUIRE(counter == 1);
} }
TEST_CASE("drop"
"[registry]")
TEST_CASE("drop" "[registry]")
{ {
spdlog::drop_all(); spdlog::drop_all();
spdlog::create<spdlog::sinks::null_sink_mt>(tested_logger_name); spdlog::create<spdlog::sinks::null_sink_mt>(tested_logger_name);
@ -59,7 +54,8 @@ TEST_CASE("drop" "[registry]")
REQUIRE_FALSE(spdlog::get(tested_logger_name)); REQUIRE_FALSE(spdlog::get(tested_logger_name));
} }
TEST_CASE("drop_all" "[registry]") TEST_CASE("drop_all"
"[registry]")
{ {
spdlog::drop_all(); spdlog::drop_all();
spdlog::create<spdlog::sinks::null_sink_mt>(tested_logger_name); spdlog::create<spdlog::sinks::null_sink_mt>(tested_logger_name);
@ -69,8 +65,8 @@ TEST_CASE("drop_all" "[registry]")
REQUIRE_FALSE(spdlog::get(tested_logger_name)); REQUIRE_FALSE(spdlog::get(tested_logger_name));
} }
TEST_CASE("drop non existing"
TEST_CASE("drop non existing" "[registry]") "[registry]")
{ {
spdlog::drop_all(); spdlog::drop_all();
spdlog::create<spdlog::sinks::null_sink_mt>(tested_logger_name); spdlog::create<spdlog::sinks::null_sink_mt>(tested_logger_name);
@ -79,6 +75,3 @@ TEST_CASE("drop non existing" "[registry]")
REQUIRE(spdlog::get(tested_logger_name)); REQUIRE(spdlog::get(tested_logger_name));
spdlog::drop_all(); spdlog::drop_all();
} }

@ -22,7 +22,6 @@ TEST_CASE("debug and trace w/o format string", "[macros]]")
REQUIRE(count_lines(filename) == 2); REQUIRE(count_lines(filename) == 2);
} }
TEST_CASE("debug and trace with format strings", "[macros]]") TEST_CASE("debug and trace with format strings", "[macros]]")
{ {
prepare_logdir(); prepare_logdir();
@ -47,4 +46,3 @@ TEST_CASE("debug and trace with format strings", "[macros]]")
REQUIRE(ends_with(file_contents(filename), "Test message 222\n")); REQUIRE(ends_with(file_contents(filename), "Test message 222\n"));
REQUIRE(count_lines(filename) == 2); REQUIRE(count_lines(filename) == 2);
} }

@ -42,11 +42,36 @@ TEST_CASE("log_levels", "[log_levels]")
REQUIRE(log_info("Hello", spdlog::level::trace) == "Hello"); REQUIRE(log_info("Hello", spdlog::level::trace) == "Hello");
} }
TEST_CASE("to_str", "[convert_to_str]")
{
REQUIRE(std::string(spdlog::level::to_str(spdlog::level::trace)) == "trace");
REQUIRE(std::string(spdlog::level::to_str(spdlog::level::debug)) == "debug");
REQUIRE(std::string(spdlog::level::to_str(spdlog::level::info)) == "info");
REQUIRE(std::string(spdlog::level::to_str(spdlog::level::warn)) == "warning");
REQUIRE(std::string(spdlog::level::to_str(spdlog::level::err)) == "error");
REQUIRE(std::string(spdlog::level::to_str(spdlog::level::critical)) == "critical");
REQUIRE(std::string(spdlog::level::to_str(spdlog::level::off)) == "off");
}
TEST_CASE("to_short_str", "[convert_to_short_str]")
{
REQUIRE(std::string(spdlog::level::to_short_str(spdlog::level::trace)) == "T");
REQUIRE(std::string(spdlog::level::to_short_str(spdlog::level::debug)) == "D");
REQUIRE(std::string(spdlog::level::to_short_str(spdlog::level::info)) == "I");
REQUIRE(std::string(spdlog::level::to_short_str(spdlog::level::warn)) == "W");
REQUIRE(std::string(spdlog::level::to_short_str(spdlog::level::err)) == "E");
REQUIRE(std::string(spdlog::level::to_short_str(spdlog::level::critical)) == "C");
REQUIRE(std::string(spdlog::level::to_short_str(spdlog::level::off)) == "O");
}
TEST_CASE("to_level_enum", "[convert_to_level_enum]")
{
REQUIRE(spdlog::level::from_str("trace") == spdlog::level::trace);
REQUIRE(spdlog::level::from_str("debug") == spdlog::level::debug);
REQUIRE(spdlog::level::from_str("info") == spdlog::level::info);
REQUIRE(spdlog::level::from_str("warning") == spdlog::level::warn);
REQUIRE(spdlog::level::from_str("error") == spdlog::level::err);
REQUIRE(spdlog::level::from_str("critical") == spdlog::level::critical);
REQUIRE(spdlog::level::from_str("off") == spdlog::level::off);
REQUIRE(spdlog::level::from_str("null") == spdlog::level::off);
}

@ -7,7 +7,10 @@ static std::string log_to_str(const std::string& msg, const std::shared_ptr<spdl
auto oss_sink = std::make_shared<spdlog::sinks::ostream_sink_mt>(oss); auto oss_sink = std::make_shared<spdlog::sinks::ostream_sink_mt>(oss);
spdlog::logger oss_logger("pattern_tester", oss_sink); spdlog::logger oss_logger("pattern_tester", oss_sink);
oss_logger.set_level(spdlog::level::info); oss_logger.set_level(spdlog::level::info);
if (formatter) oss_logger.set_formatter(formatter); if (formatter)
{
oss_logger.set_formatter(formatter);
}
oss_logger.info(msg); oss_logger.info(msg);
return oss.str(); return oss.str();
} }
@ -56,6 +59,66 @@ TEST_CASE("date MM/DD/YY ", "[pattern_formatter]")
auto formatter = std::make_shared<spdlog::pattern_formatter>("%D %v", spdlog::pattern_time_type::local, "\n"); auto formatter = std::make_shared<spdlog::pattern_formatter>("%D %v", spdlog::pattern_time_type::local, "\n");
auto now_tm = spdlog::details::os::localtime(); auto now_tm = spdlog::details::os::localtime();
std::stringstream oss; std::stringstream oss;
oss << std::setfill('0') << std::setw(2) << now_tm.tm_mon + 1 << "/" << std::setw(2) << now_tm.tm_mday << "/" << std::setw(2) << (now_tm.tm_year + 1900) % 1000 << " Some message\n"; oss << std::setfill('0') << std::setw(2) << now_tm.tm_mon + 1 << "/" << std::setw(2) << now_tm.tm_mday << "/" << std::setw(2)
<< (now_tm.tm_year + 1900) % 1000 << " Some message\n";
REQUIRE(log_to_str("Some message", formatter) == oss.str()); REQUIRE(log_to_str("Some message", formatter) == oss.str());
} }
TEST_CASE("color range test1", "[pattern_formatter]")
{
auto formatter = std::make_shared<spdlog::pattern_formatter>("%^%v%$", spdlog::pattern_time_type::local, "\n");
spdlog::details::log_msg msg;
msg.raw << "Hello";
formatter->format(msg);
REQUIRE(msg.color_range_start == 0);
REQUIRE(msg.color_range_end == 5);
REQUIRE(log_to_str("hello", formatter) == "hello\n");
}
TEST_CASE("color range test2", "[pattern_formatter]")
{
auto formatter = std::make_shared<spdlog::pattern_formatter>("%^%$", spdlog::pattern_time_type::local, "\n");
spdlog::details::log_msg msg;
formatter->format(msg);
REQUIRE(msg.color_range_start == 0);
REQUIRE(msg.color_range_end == 0);
REQUIRE(log_to_str("", formatter) == "\n");
}
TEST_CASE("color range test3", "[pattern_formatter]")
{
auto formatter = std::make_shared<spdlog::pattern_formatter>("%^***%$");
spdlog::details::log_msg msg;
formatter->format(msg);
REQUIRE(msg.color_range_start == 0);
REQUIRE(msg.color_range_end == 3);
}
TEST_CASE("color range test4", "[pattern_formatter]")
{
auto formatter = std::make_shared<spdlog::pattern_formatter>("XX%^YYY%$", spdlog::pattern_time_type::local, "\n");
spdlog::details::log_msg msg;
msg.raw << "ignored";
formatter->format(msg);
REQUIRE(msg.color_range_start == 2);
REQUIRE(msg.color_range_end == 5);
REQUIRE(log_to_str("ignored", formatter) == "XXYYY\n");
}
TEST_CASE("color range test5", "[pattern_formatter]")
{
auto formatter = std::make_shared<spdlog::pattern_formatter>("**%^");
spdlog::details::log_msg msg;
formatter->format(msg);
REQUIRE(msg.color_range_start == 2);
REQUIRE(msg.color_range_end == 0);
}
TEST_CASE("color range test6", "[pattern_formatter]")
{
auto formatter = std::make_shared<spdlog::pattern_formatter>("**%$");
spdlog::details::log_msg msg;
formatter->format(msg);
REQUIRE(msg.color_range_start == 0);
REQUIRE(msg.color_range_end == 2);
}

@ -1,6 +1,5 @@
#include "includes.h" #include "includes.h"
void prepare_logdir() void prepare_logdir()
{ {
spdlog::drop_all(); spdlog::drop_all();
@ -9,20 +8,18 @@ void prepare_logdir()
system("del /F /Q logs\\*"); system("del /F /Q logs\\*");
#else #else
auto rv = system("mkdir -p logs"); auto rv = system("mkdir -p logs");
(void)rv;
rv = system("rm -f logs/*"); rv = system("rm -f logs/*");
(void)rv; (void)rv;
#endif #endif
} }
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)
@ -47,10 +44,10 @@ std::size_t get_filesize(const std::string& filename)
return static_cast<std::size_t>(ifs.tellg()); return static_cast<std::size_t>(ifs.tellg());
} }
// source: https://stackoverflow.com/a/2072890/192001 // source: https://stackoverflow.com/a/2072890/192001
bool ends_with(std::string const &value, std::string const &ending) bool ends_with(std::string const &value, std::string const &ending)
{ {
if (ending.size() > value.size()) return false; if (ending.size() > value.size())
return false;
return std::equal(ending.rbegin(), ending.rend(), value.rbegin()); return std::equal(ending.rbegin(), ending.rend(), value.rbegin());
} }

@ -1,7 +1,7 @@
#pragma once #pragma once
#include <string>
#include <cstddef> #include <cstddef>
#include <string>
std::size_t count_lines(const std::string &filename); std::size_t count_lines(const std::string &filename);

Loading…
Cancel
Save