This commit is contained in:
gabime 2016-04-20 11:57:49 +03:00
parent 0f88996974
commit 0d26359856
39 changed files with 8951 additions and 8951 deletions

View File

@ -1,62 +1,62 @@
// //
// Copyright(c) 2015 Gabi Melman. // Copyright(c) 2015 Gabi Melman.
// Distributed under the MIT License (http://opensource.org/licenses/MIT) // Distributed under the MIT License (http://opensource.org/licenses/MIT)
// //
#include <thread> #include <thread>
#include <vector> #include <vector>
#include <atomic> #include <atomic>
#include <iostream> #include <iostream>
#include <chrono> #include <chrono>
#include <cstdlib> #include <cstdlib>
#include "spdlog/spdlog.h" #include "spdlog/spdlog.h"
using namespace std; using namespace std;
int main(int argc, char* argv[]) int main(int argc, char* argv[])
{ {
using namespace std::chrono; using namespace std::chrono;
using clock=steady_clock; using clock=steady_clock;
namespace spd = spdlog; namespace spd = spdlog;
int thread_count = 10; int thread_count = 10;
if(argc > 1) if(argc > 1)
thread_count = ::atoi(argv[1]); thread_count = ::atoi(argv[1]);
int howmany = 1000000; int howmany = 1000000;
spd::set_async_mode(1048576); spd::set_async_mode(1048576);
auto logger = spdlog::create<spd::sinks::simple_file_sink_mt>("file_logger", "logs/spd-bench-async.txt", false); auto logger = spdlog::create<spd::sinks::simple_file_sink_mt>("file_logger", "logs/spd-bench-async.txt", false);
logger->set_pattern("[%Y-%b-%d %T.%e]: %v"); logger->set_pattern("[%Y-%b-%d %T.%e]: %v");
std::atomic<int > msg_counter {0}; std::atomic<int > msg_counter {0};
vector<thread> threads; vector<thread> threads;
auto start = clock::now(); auto start = clock::now();
for (int t = 0; t < thread_count; ++t) for (int t = 0; t < thread_count; ++t)
{ {
threads.push_back(std::thread([&]() threads.push_back(std::thread([&]()
{ {
while (true) while (true)
{ {
int counter = ++msg_counter; int counter = ++msg_counter;
if (counter > howmany) break; if (counter > howmany) break;
logger->info() << "spdlog message #" << counter << ": This is some text for your pleasure"; logger->info() << "spdlog message #" << counter << ": This is some text for your pleasure";
} }
})); }));
} }
for(auto &t:threads) for(auto &t:threads)
{ {
t.join(); t.join();
}; };
duration<float> delta = clock::now() - start; duration<float> delta = clock::now() - start;
float deltaf = delta.count(); float deltaf = delta.count();
auto rate = howmany/deltaf; auto rate = howmany/deltaf;
cout << "Total: " << howmany << std::endl; cout << "Total: " << howmany << std::endl;
cout << "Threads: " << thread_count << std::endl; cout << "Threads: " << thread_count << std::endl;
std::cout << "Delta = " << deltaf << " seconds" << std::endl; std::cout << "Delta = " << deltaf << " seconds" << std::endl;
std::cout << "Rate = " << rate << "/sec" << std::endl; std::cout << "Rate = " << rate << "/sec" << std::endl;
} }

View File

@ -1,56 +1,56 @@
#include <thread> #include <thread>
#include <vector> #include <vector>
#include <atomic> #include <atomic>
#include <cstdlib> #include <cstdlib>
#include <unistd.h> #include <unistd.h>
#include <fcntl.h> #include <fcntl.h>
#include <zf_log.c> #include <zf_log.c>
const char g_path[] = "logs/zf_log.txt"; const char g_path[] = "logs/zf_log.txt";
int g_fd; int g_fd;
static void output_callback(zf_log_message *msg) static void output_callback(zf_log_message *msg)
{ {
*msg->p = '\n'; *msg->p = '\n';
write(g_fd, msg->buf, msg->p - msg->buf + 1); write(g_fd, msg->buf, msg->p - msg->buf + 1);
} }
using namespace std; using namespace std;
int main(int argc, char* argv[]) int main(int argc, char* argv[])
{ {
g_fd = open(g_path, O_APPEND|O_CREAT|O_WRONLY); g_fd = open(g_path, O_APPEND|O_CREAT|O_WRONLY);
if (0 > g_fd) if (0 > g_fd)
{ {
ZF_LOGE_AUX(ZF_LOG_STDERR, "Failed to open log file: %s", g_path); ZF_LOGE_AUX(ZF_LOG_STDERR, "Failed to open log file: %s", g_path);
return -1; return -1;
} }
zf_log_set_output_callback(ZF_LOG_PUT_STD, output_callback); zf_log_set_output_callback(ZF_LOG_PUT_STD, output_callback);
int thread_count = 10; int thread_count = 10;
if(argc > 1) if(argc > 1)
thread_count = std::atoi(argv[1]); thread_count = std::atoi(argv[1]);
int howmany = 1000000; int howmany = 1000000;
std::atomic<int > msg_counter {0}; std::atomic<int > msg_counter {0};
vector<thread> threads; vector<thread> threads;
for (int t = 0; t < thread_count; ++t) for (int t = 0; t < thread_count; ++t)
{ {
threads.push_back(std::thread([&]() threads.push_back(std::thread([&]()
{ {
while (true) while (true)
{ {
int counter = ++msg_counter; int counter = ++msg_counter;
if (counter > howmany) break; if (counter > howmany) break;
ZF_LOGI("zf_log message #%i: This is some text for your pleasure", counter); ZF_LOGI("zf_log message #%i: This is some text for your pleasure", counter);
} }
})); }));
} }
for (auto &t:threads) for (auto &t:threads)
{ {
t.join(); t.join();
}; };
close(g_fd); close(g_fd);
return 0; return 0;
} }

View File

@ -1,28 +1,28 @@
#include <stdio.h> #include <stdio.h>
#include <zf_log.c> #include <zf_log.c>
const char g_path[] = "logs/zf_log.txt"; const char g_path[] = "logs/zf_log.txt";
static FILE *g_f; static FILE *g_f;
static void output_callback(zf_log_message *msg) static void output_callback(zf_log_message *msg)
{ {
*msg->p = '\n'; *msg->p = '\n';
fwrite(msg->buf, msg->p - msg->buf + 1, 1, g_f); fwrite(msg->buf, msg->p - msg->buf + 1, 1, g_f);
} }
int main(int, char* []) int main(int, char* [])
{ {
g_f = fopen(g_path, "wb"); g_f = fopen(g_path, "wb");
if (!g_f) if (!g_f)
{ {
ZF_LOGE_AUX(ZF_LOG_STDERR, "Failed to open log file: %s", g_path); ZF_LOGE_AUX(ZF_LOG_STDERR, "Failed to open log file: %s", g_path);
return -1; return -1;
} }
zf_log_set_output_callback(ZF_LOG_PUT_STD, output_callback); zf_log_set_output_callback(ZF_LOG_PUT_STD, output_callback);
const int howmany = 1000000; const int howmany = 1000000;
for(int i = 0 ; i < howmany; ++i) for(int i = 0 ; i < howmany; ++i)
ZF_LOGI("zf_log message #%i: This is some text for your pleasure", i); ZF_LOGI("zf_log message #%i: This is some text for your pleasure", i);
fclose(g_f); fclose(g_f);
return 0; return 0;
} }

View File

@ -1,118 +1,118 @@
// //
// Copyright(c) 2015 Gabi Melman. // Copyright(c) 2015 Gabi Melman.
// Distributed under the MIT License (http://opensource.org/licenses/MIT) // Distributed under the MIT License (http://opensource.org/licenses/MIT)
// //
// //
// spdlog usage example // spdlog usage example
// //
#include "spdlog/spdlog.h" #include "spdlog/spdlog.h"
#include <cstdlib> // EXIT_FAILURE #include <cstdlib> // EXIT_FAILURE
#include <iostream> #include <iostream>
#include <memory> #include <memory>
void async_example(); void async_example();
void syslog_example(); void syslog_example();
namespace spd = spdlog; namespace spd = spdlog;
int main(int, char*[]) int main(int, char*[])
{ {
try try
{ {
// Multithreaded color console // Multithreaded color console
auto console = spd::stdout_logger_mt("console", true); auto console = spd::stdout_logger_mt("console", true);
console->info("Welcome to spdlog!"); console->info("Welcome to spdlog!");
console->info("An info message example {}..", 1); console->info("An info message example {}..", 1);
console->info() << "Streams are supported too " << 1; console->info() << "Streams are supported too " << 1;
// Formatting examples // Formatting examples
console->info("Easy padding in numbers like {:08d}", 12); console->info("Easy padding in numbers like {:08d}", 12);
console->info("Support for int: {0:d}; hex: {0:x}; oct: {0:o}; bin: {0:b}", 42); console->info("Support for int: {0:d}; hex: {0:x}; oct: {0:o}; bin: {0:b}", 42);
console->info("Support for floats {:03.2f}", 1.23456); console->info("Support for floats {:03.2f}", 1.23456);
console->info("Positional args are {1} {0}..", "too", "supported"); console->info("Positional args are {1} {0}..", "too", "supported");
console->info("{:<30}", "left aligned"); console->info("{:<30}", "left aligned");
console->info("{:>30}", "right aligned"); console->info("{:>30}", "right aligned");
console->info("{:^30}", "centered"); console->info("{:^30}", "centered");
spd::get("console")->info("loggers can be retrieved from a global registry using the spdlog::get(logger_name) function"); spd::get("console")->info("loggers can be retrieved from a global registry using the spdlog::get(logger_name) function");
// Runtime log levels // Runtime log levels
spd::set_level(spd::level::info); //Set global log level to info spd::set_level(spd::level::info); //Set global log level to info
console->debug("This message shold not be displayed!"); console->debug("This message shold not be displayed!");
console->set_level(spd::level::debug); // Set specific logger's log level console->set_level(spd::level::debug); // Set specific logger's log level
console->debug("This message shold be displayed.."); console->debug("This message shold be displayed..");
// Create a file rotating logger with 5mb size max and 3 rotated files // Create a file rotating logger with 5mb size max and 3 rotated files
auto file_logger = spd::rotating_logger_mt("file_logger", "logs/mylogfile", 1048576 * 5, 3); auto file_logger = spd::rotating_logger_mt("file_logger", "logs/mylogfile", 1048576 * 5, 3);
for (int i = 0; i < 10; ++i) for (int i = 0; i < 10; ++i)
file_logger->info("{} * {} equals {:>10}", i, i, i*i); file_logger->info("{} * {} equals {:>10}", i, i, i*i);
// Create a daily logger - a new file is created every day on 2:30am // Create a daily logger - a new file is created every day on 2:30am
auto daily_logger = spd::daily_logger_mt("daily_logger", "logs/daily", 2, 30); auto daily_logger = spd::daily_logger_mt("daily_logger", "logs/daily", 2, 30);
// Customize msg format for all messages // Customize msg format for all messages
spd::set_pattern("*** [%H:%M:%S %z] [thread %t] %v ***"); spd::set_pattern("*** [%H:%M:%S %z] [thread %t] %v ***");
file_logger->info("This is another message with custom format"); file_logger->info("This is another message with custom format");
// Compile time debug or trace macros. // Compile time debug or trace macros.
// Enabled #ifdef SPDLOG_DEBUG_ON or #ifdef SPDLOG_TRACE_ON // Enabled #ifdef SPDLOG_DEBUG_ON or #ifdef SPDLOG_TRACE_ON
SPDLOG_TRACE(console, "Enabled only #ifdef SPDLOG_TRACE_ON..{} ,{}", 1, 3.23); SPDLOG_TRACE(console, "Enabled only #ifdef SPDLOG_TRACE_ON..{} ,{}", 1, 3.23);
SPDLOG_DEBUG(console, "Enabled only #ifdef SPDLOG_DEBUG_ON.. {} ,{}", 1, 3.23); SPDLOG_DEBUG(console, "Enabled only #ifdef SPDLOG_DEBUG_ON.. {} ,{}", 1, 3.23);
// Asynchronous logging is very fast.. // Asynchronous logging is very fast..
// Just call spdlog::set_async_mode(q_size) and all created loggers from now on will be asynchronous.. // Just call spdlog::set_async_mode(q_size) and all created loggers from now on will be asynchronous..
async_example(); async_example();
// syslog example. linux/osx only.. // syslog example. linux/osx only..
syslog_example(); syslog_example();
// Release and close all loggers // Release and close all loggers
spdlog::drop_all(); spdlog::drop_all();
} }
catch (const spd::spdlog_ex& ex) catch (const spd::spdlog_ex& ex)
{ {
std::cout << "Log failed: " << ex.what() << std::endl; std::cout << "Log failed: " << ex.what() << std::endl;
return EXIT_FAILURE; return EXIT_FAILURE;
} }
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }
void async_example() void async_example()
{ {
size_t q_size = 4096; //queue size must be power of 2 size_t q_size = 4096; //queue size must be power of 2
spdlog::set_async_mode(q_size); spdlog::set_async_mode(q_size);
auto async_file = spd::daily_logger_st("async_file_logger", "logs/async_log.txt"); auto async_file = spd::daily_logger_st("async_file_logger", "logs/async_log.txt");
for (int i = 0; i < 100; ++i) for (int i = 0; i < 100; ++i)
async_file->info("Async message #{}", i); async_file->info("Async message #{}", i);
} }
//syslog example (linux/osx only) //syslog example (linux/osx only)
void syslog_example() void syslog_example()
{ {
#if defined (__linux__) || defined(__APPLE__) #if defined (__linux__) || defined(__APPLE__)
std::string ident = "spdlog-example"; std::string ident = "spdlog-example";
auto syslog_logger = spd::syslog_logger("syslog", ident, LOG_PID); auto syslog_logger = spd::syslog_logger("syslog", ident, LOG_PID);
syslog_logger->warn("This is warning that will end up in syslog. This is Linux only!"); syslog_logger->warn("This is warning that will end up in syslog. This is Linux only!");
#endif #endif
} }
// Example of user defined class with operator<< // Example of user defined class with operator<<
class some_class {}; class some_class {};
std::ostream& operator<<(std::ostream& os, const some_class&) std::ostream& operator<<(std::ostream& os, const some_class&)
{ {
return os << "some_class"; return os << "some_class";
} }
void custom_class_example() void custom_class_example()
{ {
some_class c; some_class c;
spdlog::get("console")->info("custom class with operator<<: {}..", c); spdlog::get("console")->info("custom class with operator<<: {}..", c);
spdlog::get("console")->info() << "custom class with operator<<: " << c << ".."; spdlog::get("console")->info() << "custom class with operator<<: " << c << "..";
} }

View File

@ -1,74 +1,74 @@
// //
// Copyright(c) 2015 Gabi Melman. // Copyright(c) 2015 Gabi Melman.
// Distributed under the MIT License (http://opensource.org/licenses/MIT) // Distributed under the MIT License (http://opensource.org/licenses/MIT)
// //
#pragma once #pragma once
// Very fast asynchronous logger (millions of logs per second on an average desktop) // Very fast asynchronous logger (millions of logs per second on an average desktop)
// Uses pre allocated lockfree queue for maximum throughput even under large number of threads. // Uses pre allocated lockfree queue for maximum throughput even under large number of threads.
// Creates a single back thread to pop messages from the queue and log them. // Creates a single back thread to pop messages from the queue and log them.
// //
// Upon each log write the logger: // Upon each log write the logger:
// 1. Checks if its log level is enough to log the message // 1. Checks if its log level is enough to log the message
// 2. Push a new copy of the message to a queue (or block the caller until space is available in the queue) // 2. Push a new copy of the message to a queue (or block the caller until space is available in the queue)
// 3. will throw spdlog_ex upon log exceptions // 3. will throw spdlog_ex upon log exceptions
// Upong destruction, logs all remaining messages in the queue before destructing.. // Upong destruction, logs all remaining messages in the queue before destructing..
#include <spdlog/common.h> #include <spdlog/common.h>
#include <spdlog/logger.h> #include <spdlog/logger.h>
#include <chrono> #include <chrono>
#include <functional> #include <functional>
#include <string> #include <string>
#include <memory> #include <memory>
namespace spdlog namespace spdlog
{ {
namespace details namespace details
{ {
class async_log_helper; class async_log_helper;
} }
class async_logger :public logger class async_logger :public logger
{ {
public: public:
template<class It> template<class It>
async_logger(const std::string& name, async_logger(const std::string& name,
const It& begin, const It& begin,
const It& end, const It& end,
size_t queue_size, size_t queue_size,
const async_overflow_policy overflow_policy = async_overflow_policy::block_retry, const async_overflow_policy overflow_policy = async_overflow_policy::block_retry,
const std::function<void()>& worker_warmup_cb = nullptr, const std::function<void()>& worker_warmup_cb = nullptr,
const std::chrono::milliseconds& flush_interval_ms = std::chrono::milliseconds::zero()); const std::chrono::milliseconds& flush_interval_ms = std::chrono::milliseconds::zero());
async_logger(const std::string& logger_name, async_logger(const std::string& logger_name,
sinks_init_list sinks, sinks_init_list sinks,
size_t queue_size, size_t queue_size,
const async_overflow_policy overflow_policy = async_overflow_policy::block_retry, const async_overflow_policy overflow_policy = async_overflow_policy::block_retry,
const std::function<void()>& worker_warmup_cb = nullptr, const std::function<void()>& worker_warmup_cb = nullptr,
const std::chrono::milliseconds& flush_interval_ms = std::chrono::milliseconds::zero()); const std::chrono::milliseconds& flush_interval_ms = std::chrono::milliseconds::zero());
async_logger(const std::string& logger_name, async_logger(const std::string& logger_name,
sink_ptr single_sink, sink_ptr single_sink,
size_t queue_size, size_t queue_size,
const async_overflow_policy overflow_policy = async_overflow_policy::block_retry, const async_overflow_policy overflow_policy = async_overflow_policy::block_retry,
const std::function<void()>& worker_warmup_cb = nullptr, const std::function<void()>& worker_warmup_cb = nullptr,
const std::chrono::milliseconds& flush_interval_ms = std::chrono::milliseconds::zero()); const std::chrono::milliseconds& flush_interval_ms = std::chrono::milliseconds::zero());
void flush() override; void flush() override;
protected: protected:
void _log_msg(details::log_msg& msg) override; void _log_msg(details::log_msg& msg) override;
void _set_formatter(spdlog::formatter_ptr msg_formatter) override; void _set_formatter(spdlog::formatter_ptr msg_formatter) override;
void _set_pattern(const std::string& pattern) override; void _set_pattern(const std::string& pattern) override;
private: private:
std::unique_ptr<details::async_log_helper> _async_log_helper; std::unique_ptr<details::async_log_helper> _async_log_helper;
}; };
} }
#include <spdlog/details/async_logger_impl.h> #include <spdlog/details/async_logger_impl.h>

View File

@ -1,130 +1,130 @@
// //
// Copyright(c) 2015 Gabi Melman. // Copyright(c) 2015 Gabi Melman.
// Distributed under the MIT License (http://opensource.org/licenses/MIT) // Distributed under the MIT License (http://opensource.org/licenses/MIT)
// //
#pragma once #pragma once
#include <string> #include <string>
#include <initializer_list> #include <initializer_list>
#include <chrono> #include <chrono>
#include <memory> #include <memory>
#include <atomic> #include <atomic>
#include <exception> #include <exception>
#if defined(_WIN32) && defined(SPDLOG_WCHAR_FILENAMES) #if defined(_WIN32) && defined(SPDLOG_WCHAR_FILENAMES)
#include <codecvt> #include <codecvt>
#include <locale> #include <locale>
#endif #endif
#include <spdlog/details/null_mutex.h> #include <spdlog/details/null_mutex.h>
//visual studio does not support noexcept yet //visual studio does not support noexcept yet
#ifndef _MSC_VER #ifndef _MSC_VER
#define SPDLOG_NOEXCEPT noexcept #define SPDLOG_NOEXCEPT noexcept
#else #else
#define SPDLOG_NOEXCEPT throw() #define SPDLOG_NOEXCEPT throw()
#endif #endif
namespace spdlog namespace spdlog
{ {
class formatter; class formatter;
namespace sinks namespace sinks
{ {
class sink; class sink;
} }
// Common types across the lib // Common types across the lib
using log_clock = std::chrono::system_clock; using log_clock = std::chrono::system_clock;
using sink_ptr = std::shared_ptr < sinks::sink >; using sink_ptr = std::shared_ptr < sinks::sink >;
using sinks_init_list = std::initializer_list < sink_ptr >; using sinks_init_list = std::initializer_list < sink_ptr >;
using formatter_ptr = std::shared_ptr<spdlog::formatter>; using formatter_ptr = std::shared_ptr<spdlog::formatter>;
#if defined(SPDLOG_NO_ATOMIC_LEVELS) #if defined(SPDLOG_NO_ATOMIC_LEVELS)
using level_t = details::null_atomic_int; using level_t = details::null_atomic_int;
#else #else
using level_t = std::atomic_int; using level_t = std::atomic_int;
#endif #endif
//Log level enum //Log level enum
namespace level namespace level
{ {
typedef enum typedef enum
{ {
trace = 0, trace = 0,
debug = 1, debug = 1,
info = 2, info = 2,
notice = 3, notice = 3,
warn = 4, warn = 4,
err = 5, err = 5,
critical = 6, critical = 6,
alert = 7, alert = 7,
emerg = 8, emerg = 8,
off = 9 off = 9
} level_enum; } level_enum;
static const char* level_names[] { "trace", "debug", "info", "notice", "warning", "error", "critical", "alert", "emerg", "off"}; static const char* level_names[] { "trace", "debug", "info", "notice", "warning", "error", "critical", "alert", "emerg", "off"};
static const char* short_level_names[] { "T", "D", "I", "N", "W", "E", "C", "A", "M", "O"}; static const char* short_level_names[] { "T", "D", "I", "N", "W", "E", "C", "A", "M", "O"};
inline const char* to_str(spdlog::level::level_enum l) inline const char* to_str(spdlog::level::level_enum l)
{ {
return level_names[l]; return level_names[l];
} }
inline const char* to_short_str(spdlog::level::level_enum l) inline const char* to_short_str(spdlog::level::level_enum l)
{ {
return short_level_names[l]; return short_level_names[l];
} }
} //level } //level
// //
// Async overflow policy - block by default. // Async overflow policy - block by default.
// //
enum class async_overflow_policy enum class async_overflow_policy
{ {
block_retry, // Block / yield / sleep until message can be enqueued block_retry, // Block / yield / sleep until message can be enqueued
discard_log_msg // Discard the message it enqueue fails discard_log_msg // Discard the message it enqueue fails
}; };
// //
// Log exception // Log exception
// //
class spdlog_ex : public std::exception class spdlog_ex : public std::exception
{ {
public: public:
spdlog_ex(const std::string& msg) :_msg(msg) {} spdlog_ex(const std::string& msg) :_msg(msg) {}
const char* what() const SPDLOG_NOEXCEPT override const char* what() const SPDLOG_NOEXCEPT override
{ {
return _msg.c_str(); return _msg.c_str();
} }
private: private:
std::string _msg; std::string _msg;
}; };
// //
// wchar support for windows file names (SPDLOG_WCHAR_FILENAMES must be defined) // wchar support for windows file names (SPDLOG_WCHAR_FILENAMES must be defined)
// //
#if defined(_WIN32) && defined(SPDLOG_WCHAR_FILENAMES) #if defined(_WIN32) && defined(SPDLOG_WCHAR_FILENAMES)
#define SPDLOG_FILENAME_T(s) L ## s #define SPDLOG_FILENAME_T(s) L ## s
using filename_t = std::wstring; using filename_t = std::wstring;
inline std::string filename_to_str(const filename_t& filename) inline std::string filename_to_str(const filename_t& filename)
{ {
std::wstring_convert<std::codecvt_utf8<wchar_t>, wchar_t> c; std::wstring_convert<std::codecvt_utf8<wchar_t>, wchar_t> c;
return c.to_bytes(filename); return c.to_bytes(filename);
} }
#else #else
#define SPDLOG_FILENAME_T(s) s #define SPDLOG_FILENAME_T(s) s
using filename_t = std::string; using filename_t = std::string;
inline std::string filename_to_str(const filename_t& filename) inline std::string filename_to_str(const filename_t& filename)
{ {
return filename; return filename;
} }
#endif #endif
} //spdlog } //spdlog

View File

@ -1,368 +1,368 @@
// //
// Copyright(c) 2015 Gabi Melman. // Copyright(c) 2015 Gabi Melman.
// Distributed under the MIT License (http://opensource.org/licenses/MIT) // Distributed under the MIT License (http://opensource.org/licenses/MIT)
// //
// async log helper : // async log helper :
// Process logs asynchronously using a back thread. // Process logs asynchronously using a back thread.
// //
// If the internal queue of log messages reaches its max size, // If the internal queue of log messages reaches its max size,
// then the client call will block until there is more room. // then the client call will block until there is more room.
// //
// If the back thread throws during logging, a spdlog::spdlog_ex exception // If the back thread throws during logging, a spdlog::spdlog_ex exception
// will be thrown in client's thread when tries to log the next message // will be thrown in client's thread when tries to log the next message
#pragma once #pragma once
#include <spdlog/common.h> #include <spdlog/common.h>
#include <spdlog/sinks/sink.h> #include <spdlog/sinks/sink.h>
#include <spdlog/details/mpmc_bounded_q.h> #include <spdlog/details/mpmc_bounded_q.h>
#include <spdlog/details/log_msg.h> #include <spdlog/details/log_msg.h>
#include <spdlog/details/os.h> #include <spdlog/details/os.h>
#include <spdlog/formatter.h> #include <spdlog/formatter.h>
#include <chrono> #include <chrono>
#include <exception> #include <exception>
#include <functional> #include <functional>
#include <memory> #include <memory>
#include <string> #include <string>
#include <thread> #include <thread>
#include <utility> #include <utility>
#include <vector> #include <vector>
namespace spdlog namespace spdlog
{ {
namespace details namespace details
{ {
class async_log_helper class async_log_helper
{ {
// Async msg to move to/from the queue // Async msg to move to/from the queue
// Movable only. should never be copied // Movable only. should never be copied
enum class async_msg_type enum class async_msg_type
{ {
log, log,
flush, flush,
terminate terminate
}; };
struct async_msg struct async_msg
{ {
std::string logger_name; std::string logger_name;
level::level_enum level; level::level_enum level;
log_clock::time_point time; log_clock::time_point time;
size_t thread_id; size_t thread_id;
std::string txt; std::string txt;
async_msg_type msg_type; async_msg_type msg_type;
async_msg() = default; async_msg() = default;
~async_msg() = default; ~async_msg() = default;
async_msg(async_msg&& other) SPDLOG_NOEXCEPT: async_msg(async_msg&& other) SPDLOG_NOEXCEPT:
logger_name(std::move(other.logger_name)), logger_name(std::move(other.logger_name)),
level(std::move(other.level)), level(std::move(other.level)),
time(std::move(other.time)), time(std::move(other.time)),
txt(std::move(other.txt)), txt(std::move(other.txt)),
msg_type(std::move(other.msg_type)) msg_type(std::move(other.msg_type))
{} {}
async_msg(async_msg_type m_type) :msg_type(m_type) async_msg(async_msg_type m_type) :msg_type(m_type)
{}; {};
async_msg& operator=(async_msg&& other) SPDLOG_NOEXCEPT async_msg& operator=(async_msg&& other) SPDLOG_NOEXCEPT
{ {
logger_name = std::move(other.logger_name); logger_name = std::move(other.logger_name);
level = other.level; level = other.level;
time = std::move(other.time); time = std::move(other.time);
thread_id = other.thread_id; thread_id = other.thread_id;
txt = std::move(other.txt); txt = std::move(other.txt);
msg_type = other.msg_type; msg_type = other.msg_type;
return *this; return *this;
} }
// never copy or assign. should only be moved.. // never copy or assign. should only be moved..
async_msg(const async_msg&) = delete; async_msg(const async_msg&) = delete;
async_msg& operator=(async_msg& other) = delete; async_msg& operator=(async_msg& other) = delete;
// construct from log_msg // construct from log_msg
async_msg(const details::log_msg& m) : async_msg(const details::log_msg& m) :
logger_name(m.logger_name), logger_name(m.logger_name),
level(m.level), level(m.level),
time(m.time), time(m.time),
thread_id(m.thread_id), thread_id(m.thread_id),
txt(m.raw.data(), m.raw.size()), txt(m.raw.data(), m.raw.size()),
msg_type(async_msg_type::log) msg_type(async_msg_type::log)
{} {}
// copy into log_msg // copy into log_msg
void fill_log_msg(log_msg &msg) void fill_log_msg(log_msg &msg)
{ {
msg.clear(); msg.clear();
msg.logger_name = logger_name; msg.logger_name = logger_name;
msg.level = level; msg.level = level;
msg.time = time; msg.time = time;
msg.thread_id = thread_id; msg.thread_id = thread_id;
msg.raw << txt; msg.raw << txt;
} }
}; };
public: public:
using item_type = async_msg; using item_type = async_msg;
using q_type = details::mpmc_bounded_queue<item_type>; using q_type = details::mpmc_bounded_queue<item_type>;
using clock = std::chrono::steady_clock; using clock = std::chrono::steady_clock;
async_log_helper(formatter_ptr formatter, async_log_helper(formatter_ptr formatter,
const std::vector<sink_ptr>& sinks, const std::vector<sink_ptr>& sinks,
size_t queue_size, size_t queue_size,
const async_overflow_policy overflow_policy = async_overflow_policy::block_retry, const async_overflow_policy overflow_policy = async_overflow_policy::block_retry,
const std::function<void()>& worker_warmup_cb = nullptr, const std::function<void()>& worker_warmup_cb = nullptr,
const std::chrono::milliseconds& flush_interval_ms = std::chrono::milliseconds::zero()); const std::chrono::milliseconds& flush_interval_ms = std::chrono::milliseconds::zero());
void log(const details::log_msg& msg); void log(const details::log_msg& msg);
// stop logging and join the back thread // stop logging and join the back thread
~async_log_helper(); ~async_log_helper();
void set_formatter(formatter_ptr); void set_formatter(formatter_ptr);
void flush(); void flush();
private: private:
formatter_ptr _formatter; formatter_ptr _formatter;
std::vector<std::shared_ptr<sinks::sink>> _sinks; std::vector<std::shared_ptr<sinks::sink>> _sinks;
// queue of messages to log // queue of messages to log
q_type _q; q_type _q;
bool _flush_requested; bool _flush_requested;
bool _terminate_requested; bool _terminate_requested;
// last exception thrown from the worker thread // last exception thrown from the worker thread
std::shared_ptr<spdlog_ex> _last_workerthread_ex; std::shared_ptr<spdlog_ex> _last_workerthread_ex;
// overflow policy // overflow policy
const async_overflow_policy _overflow_policy; const async_overflow_policy _overflow_policy;
// worker thread warmup callback - one can set thread priority, affinity, etc // worker thread warmup callback - one can set thread priority, affinity, etc
const std::function<void()> _worker_warmup_cb; const std::function<void()> _worker_warmup_cb;
// auto periodic sink flush parameter // auto periodic sink flush parameter
const std::chrono::milliseconds _flush_interval_ms; const std::chrono::milliseconds _flush_interval_ms;
// worker thread // worker thread
std::thread _worker_thread; std::thread _worker_thread;
void push_msg(async_msg&& new_msg); void push_msg(async_msg&& new_msg);
// throw last worker thread exception or if worker thread is not active // throw last worker thread exception or if worker thread is not active
void throw_if_bad_worker(); void throw_if_bad_worker();
// worker thread main loop // worker thread main loop
void worker_loop(); void worker_loop();
// pop next message from the queue and process it. will set the last_pop to the pop time // pop next message from the queue and process it. will set the last_pop to the pop time
// return false if termination of the queue is required // return false if termination of the queue is required
bool process_next_msg(log_clock::time_point& last_pop, log_clock::time_point& last_flush); bool process_next_msg(log_clock::time_point& last_pop, log_clock::time_point& last_flush);
void handle_flush_interval(log_clock::time_point& now, log_clock::time_point& last_flush); void handle_flush_interval(log_clock::time_point& now, log_clock::time_point& last_flush);
// sleep,yield or return immediatly using the time passed since last message as a hint // sleep,yield or return immediatly using the time passed since last message as a hint
static void sleep_or_yield(const spdlog::log_clock::time_point& now, const log_clock::time_point& last_op_time); static void sleep_or_yield(const spdlog::log_clock::time_point& now, const log_clock::time_point& last_op_time);
}; };
} }
} }
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// async_sink class implementation // async_sink class implementation
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
inline spdlog::details::async_log_helper::async_log_helper( inline spdlog::details::async_log_helper::async_log_helper(
formatter_ptr formatter, formatter_ptr formatter,
const std::vector<sink_ptr>& sinks, const std::vector<sink_ptr>& sinks,
size_t queue_size, size_t queue_size,
const async_overflow_policy overflow_policy, const async_overflow_policy overflow_policy,
const std::function<void()>& worker_warmup_cb, const std::function<void()>& worker_warmup_cb,
const std::chrono::milliseconds& flush_interval_ms): const std::chrono::milliseconds& flush_interval_ms):
_formatter(formatter), _formatter(formatter),
_sinks(sinks), _sinks(sinks),
_q(queue_size), _q(queue_size),
_flush_requested(false), _flush_requested(false),
_terminate_requested(false), _terminate_requested(false),
_overflow_policy(overflow_policy), _overflow_policy(overflow_policy),
_worker_warmup_cb(worker_warmup_cb), _worker_warmup_cb(worker_warmup_cb),
_flush_interval_ms(flush_interval_ms), _flush_interval_ms(flush_interval_ms),
_worker_thread(&async_log_helper::worker_loop, this) _worker_thread(&async_log_helper::worker_loop, this)
{} {}
// Send to the worker thread termination message(level=off) // Send to the worker thread termination message(level=off)
// and wait for it to finish gracefully // and wait for it to finish gracefully
inline spdlog::details::async_log_helper::~async_log_helper() inline spdlog::details::async_log_helper::~async_log_helper()
{ {
try try
{ {
push_msg(async_msg(async_msg_type::terminate)); push_msg(async_msg(async_msg_type::terminate));
_worker_thread.join(); _worker_thread.join();
} }
catch (...) // don't crash in destructor catch (...) // don't crash in destructor
{} {}
} }
//Try to push and block until succeeded //Try to push and block until succeeded
inline void spdlog::details::async_log_helper::log(const details::log_msg& msg) inline void spdlog::details::async_log_helper::log(const details::log_msg& msg)
{ {
push_msg(async_msg(msg)); push_msg(async_msg(msg));
} }
//Try to push and block until succeeded //Try to push and block until succeeded
inline void spdlog::details::async_log_helper::push_msg(details::async_log_helper::async_msg&& new_msg) inline void spdlog::details::async_log_helper::push_msg(details::async_log_helper::async_msg&& new_msg)
{ {
throw_if_bad_worker(); throw_if_bad_worker();
if (!_q.enqueue(std::move(new_msg)) && _overflow_policy != async_overflow_policy::discard_log_msg) if (!_q.enqueue(std::move(new_msg)) && _overflow_policy != async_overflow_policy::discard_log_msg)
{ {
auto last_op_time = details::os::now(); auto last_op_time = details::os::now();
auto now = last_op_time; auto now = last_op_time;
do do
{ {
now = details::os::now(); now = details::os::now();
sleep_or_yield(now, last_op_time); sleep_or_yield(now, last_op_time);
} }
while (!_q.enqueue(std::move(new_msg))); while (!_q.enqueue(std::move(new_msg)));
} }
} }
inline void spdlog::details::async_log_helper::flush() inline void spdlog::details::async_log_helper::flush()
{ {
push_msg(async_msg(async_msg_type::flush)); push_msg(async_msg(async_msg_type::flush));
} }
inline void spdlog::details::async_log_helper::worker_loop() inline void spdlog::details::async_log_helper::worker_loop()
{ {
try try
{ {
if (_worker_warmup_cb) _worker_warmup_cb(); if (_worker_warmup_cb) _worker_warmup_cb();
auto last_pop = details::os::now(); auto last_pop = details::os::now();
auto last_flush = last_pop; auto last_flush = last_pop;
while(process_next_msg(last_pop, last_flush)); while(process_next_msg(last_pop, last_flush));
} }
catch (const std::exception& ex) catch (const std::exception& ex)
{ {
_last_workerthread_ex = std::make_shared<spdlog_ex>(std::string("async_logger worker thread exception: ") + ex.what()); _last_workerthread_ex = std::make_shared<spdlog_ex>(std::string("async_logger worker thread exception: ") + ex.what());
} }
catch (...) catch (...)
{ {
_last_workerthread_ex = std::make_shared<spdlog_ex>("async_logger worker thread exception"); _last_workerthread_ex = std::make_shared<spdlog_ex>("async_logger worker thread exception");
} }
} }
// process next message in the queue // process next message in the queue
// return true if this thread should still be active (no msg with level::off was received) // return true if this thread should still be active (no msg with level::off was received)
inline bool spdlog::details::async_log_helper::process_next_msg(log_clock::time_point& last_pop, log_clock::time_point& last_flush) inline bool spdlog::details::async_log_helper::process_next_msg(log_clock::time_point& last_pop, log_clock::time_point& last_flush)
{ {
async_msg incoming_async_msg; async_msg incoming_async_msg;
log_msg incoming_log_msg; log_msg incoming_log_msg;
if (_q.dequeue(incoming_async_msg)) if (_q.dequeue(incoming_async_msg))
{ {
last_pop = details::os::now(); last_pop = details::os::now();
switch (incoming_async_msg.msg_type) switch (incoming_async_msg.msg_type)
{ {
case async_msg_type::flush: case async_msg_type::flush:
_flush_requested = true; _flush_requested = true;
break; break;
case async_msg_type::terminate: case async_msg_type::terminate:
_flush_requested = true; _flush_requested = true;
_terminate_requested = true; _terminate_requested = true;
break; break;
default: default:
incoming_async_msg.fill_log_msg(incoming_log_msg); incoming_async_msg.fill_log_msg(incoming_log_msg);
_formatter->format(incoming_log_msg); _formatter->format(incoming_log_msg);
for (auto &s : _sinks) for (auto &s : _sinks)
s->log(incoming_log_msg); s->log(incoming_log_msg);
} }
return true; return true;
} }
// Handle empty queue.. // Handle empty queue..
// This is the only place where the queue can terminate or flush to avoid losing messages already in the queue // This is the only place where the queue can terminate or flush to avoid losing messages already in the queue
else else
{ {
auto now = details::os::now(); auto now = details::os::now();
handle_flush_interval(now, last_flush); handle_flush_interval(now, last_flush);
sleep_or_yield(now, last_pop); sleep_or_yield(now, last_pop);
return !_terminate_requested; return !_terminate_requested;
} }
} }
inline void spdlog::details::async_log_helper::handle_flush_interval(log_clock::time_point& now, log_clock::time_point& last_flush) inline void spdlog::details::async_log_helper::handle_flush_interval(log_clock::time_point& now, log_clock::time_point& last_flush)
{ {
auto should_flush = _flush_requested || (_flush_interval_ms != std::chrono::milliseconds::zero() && now - last_flush >= _flush_interval_ms); auto should_flush = _flush_requested || (_flush_interval_ms != std::chrono::milliseconds::zero() && now - last_flush >= _flush_interval_ms);
if (should_flush) if (should_flush)
{ {
for (auto &s : _sinks) for (auto &s : _sinks)
s->flush(); s->flush();
now = last_flush = details::os::now(); now = last_flush = details::os::now();
_flush_requested = false; _flush_requested = false;
} }
} }
inline void spdlog::details::async_log_helper::set_formatter(formatter_ptr msg_formatter) inline void spdlog::details::async_log_helper::set_formatter(formatter_ptr msg_formatter)
{ {
_formatter = msg_formatter; _formatter = msg_formatter;
} }
// sleep,yield or return immediatly using the time passed since last message as a hint // sleep,yield or return immediatly using the time passed since last message as a hint
inline void spdlog::details::async_log_helper::sleep_or_yield(const spdlog::log_clock::time_point& now, const spdlog::log_clock::time_point& last_op_time) inline void spdlog::details::async_log_helper::sleep_or_yield(const spdlog::log_clock::time_point& now, const spdlog::log_clock::time_point& last_op_time)
{ {
using std::chrono::milliseconds; using std::chrono::milliseconds;
using namespace std::this_thread; using namespace std::this_thread;
auto time_since_op = now - last_op_time; auto time_since_op = now - last_op_time;
// spin upto 1 ms // spin upto 1 ms
if (time_since_op <= milliseconds(1)) if (time_since_op <= milliseconds(1))
return; return;
// yield upto 10ms // yield upto 10ms
if (time_since_op <= milliseconds(10)) if (time_since_op <= milliseconds(10))
return yield(); return yield();
// sleep for half of duration since last op // sleep for half of duration since last op
if (time_since_op <= milliseconds(100)) if (time_since_op <= milliseconds(100))
return sleep_for(time_since_op / 2); return sleep_for(time_since_op / 2);
return sleep_for(milliseconds(100)); return sleep_for(milliseconds(100));
} }
// throw if the worker thread threw an exception or not active // throw if the worker thread threw an exception or not active
inline void spdlog::details::async_log_helper::throw_if_bad_worker() inline void spdlog::details::async_log_helper::throw_if_bad_worker()
{ {
if (_last_workerthread_ex) if (_last_workerthread_ex)
{ {
auto ex = std::move(_last_workerthread_ex); auto ex = std::move(_last_workerthread_ex);
throw *ex; throw *ex;
} }
} }

View File

@ -1,74 +1,74 @@
// //
// Copyright(c) 2015 Gabi Melman. // Copyright(c) 2015 Gabi Melman.
// Distributed under the MIT License (http://opensource.org/licenses/MIT) // Distributed under the MIT License (http://opensource.org/licenses/MIT)
// //
#pragma once #pragma once
// Async Logger implementation // Async Logger implementation
// Use an async_sink (queue per logger) to perform the logging in a worker thread // Use an async_sink (queue per logger) to perform the logging in a worker thread
#include <spdlog/details/async_log_helper.h> #include <spdlog/details/async_log_helper.h>
#include <spdlog/async_logger.h> #include <spdlog/async_logger.h>
#include <string> #include <string>
#include <functional> #include <functional>
#include <chrono> #include <chrono>
#include <memory> #include <memory>
template<class It> template<class It>
inline spdlog::async_logger::async_logger(const std::string& logger_name, inline spdlog::async_logger::async_logger(const std::string& logger_name,
const It& begin, const It& begin,
const It& end, const It& end,
size_t queue_size, size_t queue_size,
const async_overflow_policy overflow_policy, const async_overflow_policy overflow_policy,
const std::function<void()>& worker_warmup_cb, const std::function<void()>& worker_warmup_cb,
const std::chrono::milliseconds& flush_interval_ms) : const std::chrono::milliseconds& flush_interval_ms) :
logger(logger_name, begin, end), logger(logger_name, begin, end),
_async_log_helper(new details::async_log_helper(_formatter, _sinks, queue_size, overflow_policy, worker_warmup_cb, flush_interval_ms)) _async_log_helper(new details::async_log_helper(_formatter, _sinks, queue_size, overflow_policy, worker_warmup_cb, flush_interval_ms))
{ {
} }
inline spdlog::async_logger::async_logger(const std::string& logger_name, inline spdlog::async_logger::async_logger(const std::string& logger_name,
sinks_init_list sinks, sinks_init_list sinks,
size_t queue_size, size_t queue_size,
const async_overflow_policy overflow_policy, const async_overflow_policy overflow_policy,
const std::function<void()>& worker_warmup_cb, const std::function<void()>& worker_warmup_cb,
const std::chrono::milliseconds& flush_interval_ms) : const std::chrono::milliseconds& flush_interval_ms) :
async_logger(logger_name, sinks.begin(), sinks.end(), queue_size, overflow_policy, worker_warmup_cb, flush_interval_ms) {} async_logger(logger_name, sinks.begin(), sinks.end(), queue_size, overflow_policy, worker_warmup_cb, flush_interval_ms) {}
inline spdlog::async_logger::async_logger(const std::string& logger_name, inline spdlog::async_logger::async_logger(const std::string& logger_name,
sink_ptr single_sink, sink_ptr single_sink,
size_t queue_size, size_t queue_size,
const async_overflow_policy overflow_policy, const async_overflow_policy overflow_policy,
const std::function<void()>& worker_warmup_cb, const std::function<void()>& worker_warmup_cb,
const std::chrono::milliseconds& flush_interval_ms) : const std::chrono::milliseconds& flush_interval_ms) :
async_logger(logger_name, async_logger(logger_name,
{ {
single_sink single_sink
}, queue_size, overflow_policy, worker_warmup_cb, flush_interval_ms) {} }, queue_size, overflow_policy, worker_warmup_cb, flush_interval_ms) {}
inline void spdlog::async_logger::flush() inline void spdlog::async_logger::flush()
{ {
_async_log_helper->flush(); _async_log_helper->flush();
} }
inline void spdlog::async_logger::_set_formatter(spdlog::formatter_ptr msg_formatter) inline void spdlog::async_logger::_set_formatter(spdlog::formatter_ptr msg_formatter)
{ {
_formatter = msg_formatter; _formatter = msg_formatter;
_async_log_helper->set_formatter(_formatter); _async_log_helper->set_formatter(_formatter);
} }
inline void spdlog::async_logger::_set_pattern(const std::string& pattern) inline void spdlog::async_logger::_set_pattern(const std::string& pattern)
{ {
_formatter = std::make_shared<pattern_formatter>(pattern); _formatter = std::make_shared<pattern_formatter>(pattern);
_async_log_helper->set_formatter(_formatter); _async_log_helper->set_formatter(_formatter);
} }
inline void spdlog::async_logger::_log_msg(details::log_msg& msg) inline void spdlog::async_logger::_log_msg(details::log_msg& msg)
{ {
_async_log_helper->log(msg); _async_log_helper->log(msg);
} }

View File

@ -1,142 +1,142 @@
// //
// Copyright(c) 2015 Gabi Melman. // Copyright(c) 2015 Gabi Melman.
// Distributed under the MIT License (http://opensource.org/licenses/MIT) // Distributed under the MIT License (http://opensource.org/licenses/MIT)
// //
#pragma once #pragma once
// Helper class for file sink // Helper class for file sink
// When failing to open a file, retry several times(5) with small delay between the tries(10 ms) // When failing to open a file, retry several times(5) with small delay between the tries(10 ms)
// Can be set to auto flush on every line // Can be set to auto flush on every line
// Throw spdlog_ex exception on errors // Throw spdlog_ex exception on errors
#include <spdlog/details/os.h> #include <spdlog/details/os.h>
#include <spdlog/details/log_msg.h> #include <spdlog/details/log_msg.h>
#include <chrono> #include <chrono>
#include <cstdio> #include <cstdio>
#include <string> #include <string>
#include <thread> #include <thread>
namespace spdlog namespace spdlog
{ {
namespace details namespace details
{ {
class file_helper class file_helper
{ {
public: public:
const int open_tries = 5; const int open_tries = 5;
const int open_interval = 10; const int open_interval = 10;
explicit file_helper(bool force_flush) : explicit file_helper(bool force_flush) :
_fd(nullptr), _fd(nullptr),
_force_flush(force_flush) _force_flush(force_flush)
{} {}
file_helper(const file_helper&) = delete; file_helper(const file_helper&) = delete;
file_helper& operator=(const file_helper&) = delete; file_helper& operator=(const file_helper&) = delete;
~file_helper() ~file_helper()
{ {
close(); close();
} }
void open(const filename_t& fname, bool truncate = false) void open(const filename_t& fname, bool truncate = false)
{ {
close(); close();
auto *mode = truncate ? SPDLOG_FILENAME_T("wb") : SPDLOG_FILENAME_T("ab"); auto *mode = truncate ? SPDLOG_FILENAME_T("wb") : SPDLOG_FILENAME_T("ab");
_filename = fname; _filename = fname;
for (int tries = 0; tries < open_tries; ++tries) for (int tries = 0; tries < open_tries; ++tries)
{ {
if (!os::fopen_s(&_fd, fname, mode)) if (!os::fopen_s(&_fd, fname, mode))
return; return;
std::this_thread::sleep_for(std::chrono::milliseconds(open_interval)); std::this_thread::sleep_for(std::chrono::milliseconds(open_interval));
} }
throw spdlog_ex("Failed opening file " + filename_to_str(_filename) + " for writing"); throw spdlog_ex("Failed opening file " + filename_to_str(_filename) + " for writing");
} }
void reopen(bool truncate) void reopen(bool truncate)
{ {
if (_filename.empty()) if (_filename.empty())
throw spdlog_ex("Failed re opening file - was not opened before"); throw spdlog_ex("Failed re opening file - was not opened before");
open(_filename, truncate); open(_filename, truncate);
} }
void flush() void flush()
{ {
std::fflush(_fd); std::fflush(_fd);
} }
void close() void close()
{ {
if (_fd) if (_fd)
{ {
std::fclose(_fd); std::fclose(_fd);
_fd = nullptr; _fd = nullptr;
} }
} }
void write(const log_msg& msg) void write(const log_msg& msg)
{ {
size_t msg_size = msg.formatted.size(); size_t msg_size = msg.formatted.size();
auto data = msg.formatted.data(); auto data = msg.formatted.data();
if (std::fwrite(data, 1, msg_size, _fd) != msg_size) if (std::fwrite(data, 1, msg_size, _fd) != msg_size)
throw spdlog_ex("Failed writing to file " + filename_to_str(_filename)); throw spdlog_ex("Failed writing to file " + filename_to_str(_filename));
if (_force_flush) if (_force_flush)
std::fflush(_fd); std::fflush(_fd);
} }
long size() long size()
{ {
if (!_fd) if (!_fd)
throw spdlog_ex("Cannot use size() on closed file " + filename_to_str(_filename)); throw spdlog_ex("Cannot use size() on closed file " + filename_to_str(_filename));
auto pos = ftell(_fd); auto pos = ftell(_fd);
if (fseek(_fd, 0, SEEK_END) != 0) if (fseek(_fd, 0, SEEK_END) != 0)
throw spdlog_ex("fseek failed on file " + filename_to_str(_filename)); throw spdlog_ex("fseek failed on file " + filename_to_str(_filename));
auto file_size = ftell(_fd); auto file_size = ftell(_fd);
if(fseek(_fd, pos, SEEK_SET) !=0) if(fseek(_fd, pos, SEEK_SET) !=0)
throw spdlog_ex("fseek failed on file " + filename_to_str(_filename)); throw spdlog_ex("fseek failed on file " + filename_to_str(_filename));
if (file_size == -1) if (file_size == -1)
throw spdlog_ex("ftell failed on file " + filename_to_str(_filename)); throw spdlog_ex("ftell failed on file " + filename_to_str(_filename));
return file_size; return file_size;
} }
const filename_t& filename() const const filename_t& filename() const
{ {
return _filename; return _filename;
} }
static bool file_exists(const filename_t& name) static bool file_exists(const filename_t& name)
{ {
return os::file_exists(name); return os::file_exists(name);
} }
private: private:
FILE* _fd; FILE* _fd;
filename_t _filename; filename_t _filename;
bool _force_flush; bool _force_flush;
}; };
} }
} }

File diff suppressed because it is too large Load Diff

View File

@ -1,78 +1,78 @@
// //
// Copyright(c) 2015 Gabi Melman. // Copyright(c) 2015 Gabi Melman.
// Distributed under the MIT License (http://opensource.org/licenses/MIT) // Distributed under the MIT License (http://opensource.org/licenses/MIT)
// //
#pragma once #pragma once
#include <spdlog/common.h> #include <spdlog/common.h>
#include <spdlog/details/log_msg.h> #include <spdlog/details/log_msg.h>
#include <string> #include <string>
// Line logger class - aggregates operator<< calls to fast ostream // Line logger class - aggregates operator<< calls to fast ostream
// and logs upon destruction // and logs upon destruction
namespace spdlog namespace spdlog
{ {
// Forward declaration // Forward declaration
class logger; class logger;
namespace details namespace details
{ {
class line_logger class line_logger
{ {
public: public:
line_logger(logger* callback_logger, level::level_enum msg_level, bool enabled); line_logger(logger* callback_logger, level::level_enum msg_level, bool enabled);
// No copy intended. Only move // No copy intended. Only move
line_logger(const line_logger& other) = delete; line_logger(const line_logger& other) = delete;
line_logger& operator=(const line_logger&) = delete; line_logger& operator=(const line_logger&) = delete;
line_logger& operator=(line_logger&&) = delete; line_logger& operator=(line_logger&&) = delete;
line_logger(line_logger&& other); line_logger(line_logger&& other);
//Log the log message using the callback logger //Log the log message using the callback logger
~line_logger(); ~line_logger();
// //
// Support for format string with variadic args // Support for format string with variadic args
// //
void write(const char* what); void write(const char* what);
template <typename... Args> template <typename... Args>
void write(const char* fmt, const Args&... args); void write(const char* fmt, const Args&... args);
// //
// Support for operator<< // Support for operator<<
// //
line_logger& operator<<(const char* what); line_logger& operator<<(const char* what);
line_logger& operator<<(const std::string& what); line_logger& operator<<(const std::string& what);
line_logger& operator<<(int what); line_logger& operator<<(int what);
line_logger& operator<<(unsigned int what); line_logger& operator<<(unsigned int what);
line_logger& operator<<(long what); line_logger& operator<<(long what);
line_logger& operator<<(unsigned long what); line_logger& operator<<(unsigned long what);
line_logger& operator<<(long long what); line_logger& operator<<(long long what);
line_logger& operator<<(unsigned long long what); line_logger& operator<<(unsigned long long what);
line_logger& operator<<(double what); line_logger& operator<<(double what);
line_logger& operator<<(long double what); line_logger& operator<<(long double what);
line_logger& operator<<(float what); line_logger& operator<<(float what);
line_logger& operator<<(char what); line_logger& operator<<(char what);
//Support user types which implements operator<< //Support user types which implements operator<<
template<typename T> template<typename T>
line_logger& operator<<(const T& what); line_logger& operator<<(const T& what);
void disable(); void disable();
bool is_enabled() const; bool is_enabled() const;
private: private:
logger* _callback_logger; logger* _callback_logger;
log_msg _log_msg; log_msg _log_msg;
bool _enabled; bool _enabled;
}; };
} //Namespace details } //Namespace details
} // Namespace spdlog } // Namespace spdlog

View File

@ -1,185 +1,185 @@
// //
// Copyright(c) 2015 Gabi Melman. // Copyright(c) 2015 Gabi Melman.
// Distributed under the MIT License (http://opensource.org/licenses/MIT) // Distributed under the MIT License (http://opensource.org/licenses/MIT)
// //
#pragma once #pragma once
#include <type_traits> #include <type_traits>
#include <spdlog/details/line_logger_fwd.h> #include <spdlog/details/line_logger_fwd.h>
#include <spdlog/common.h> #include <spdlog/common.h>
#include <spdlog/logger.h> #include <spdlog/logger.h>
#include <string> #include <string>
#include <utility> #include <utility>
// Line logger class - aggregates operator<< calls to fast ostream // Line logger class - aggregates operator<< calls to fast ostream
// and logs upon destruction // and logs upon destruction
inline spdlog::details::line_logger::line_logger(logger* callback_logger, level::level_enum msg_level, bool enabled): inline spdlog::details::line_logger::line_logger(logger* callback_logger, level::level_enum msg_level, bool enabled):
_callback_logger(callback_logger), _callback_logger(callback_logger),
_log_msg(msg_level), _log_msg(msg_level),
_enabled(enabled) _enabled(enabled)
{} {}
inline spdlog::details::line_logger::line_logger(line_logger&& other) : inline spdlog::details::line_logger::line_logger(line_logger&& other) :
_callback_logger(other._callback_logger), _callback_logger(other._callback_logger),
_log_msg(std::move(other._log_msg)), _log_msg(std::move(other._log_msg)),
_enabled(other._enabled) _enabled(other._enabled)
{ {
other.disable(); other.disable();
} }
//Log the log message using the callback logger //Log the log message using the callback logger
inline spdlog::details::line_logger::~line_logger() inline spdlog::details::line_logger::~line_logger()
{ {
if (_enabled) if (_enabled)
{ {
#ifndef SPDLOG_NO_NAME #ifndef SPDLOG_NO_NAME
_log_msg.logger_name = _callback_logger->name(); _log_msg.logger_name = _callback_logger->name();
#endif #endif
#ifndef SPDLOG_NO_DATETIME #ifndef SPDLOG_NO_DATETIME
_log_msg.time = os::now(); _log_msg.time = os::now();
#endif #endif
#ifndef SPDLOG_NO_THREAD_ID #ifndef SPDLOG_NO_THREAD_ID
_log_msg.thread_id = os::thread_id(); _log_msg.thread_id = os::thread_id();
#endif #endif
_callback_logger->_log_msg(_log_msg); _callback_logger->_log_msg(_log_msg);
} }
} }
// //
// Support for format string with variadic args // Support for format string with variadic args
// //
inline void spdlog::details::line_logger::write(const char* what) inline void spdlog::details::line_logger::write(const char* what)
{ {
if (_enabled) if (_enabled)
_log_msg.raw << what; _log_msg.raw << what;
} }
template <typename... Args> template <typename... Args>
inline void spdlog::details::line_logger::write(const char* fmt, const Args&... args) inline void spdlog::details::line_logger::write(const char* fmt, const Args&... args)
{ {
if (!_enabled) if (!_enabled)
return; return;
try try
{ {
_log_msg.raw.write(fmt, args...); _log_msg.raw.write(fmt, args...);
} }
catch (const fmt::FormatError& e) catch (const fmt::FormatError& e)
{ {
throw spdlog_ex(fmt::format("formatting error while processing format string '{}': {}", fmt, e.what())); throw spdlog_ex(fmt::format("formatting error while processing format string '{}': {}", fmt, e.what()));
} }
} }
// //
// Support for operator<< // Support for operator<<
// //
inline spdlog::details::line_logger& spdlog::details::line_logger::operator<<(const char* what) inline spdlog::details::line_logger& spdlog::details::line_logger::operator<<(const char* what)
{ {
if (_enabled) if (_enabled)
_log_msg.raw << what; _log_msg.raw << what;
return *this; return *this;
} }
inline spdlog::details::line_logger& spdlog::details::line_logger::operator<<(const std::string& what) inline spdlog::details::line_logger& spdlog::details::line_logger::operator<<(const std::string& what)
{ {
if (_enabled) if (_enabled)
_log_msg.raw << what; _log_msg.raw << what;
return *this; return *this;
} }
inline spdlog::details::line_logger& spdlog::details::line_logger::operator<<(int what) inline spdlog::details::line_logger& spdlog::details::line_logger::operator<<(int what)
{ {
if (_enabled) if (_enabled)
_log_msg.raw << what; _log_msg.raw << what;
return *this; return *this;
} }
inline spdlog::details::line_logger& spdlog::details::line_logger::operator<<(unsigned int what) inline spdlog::details::line_logger& spdlog::details::line_logger::operator<<(unsigned int what)
{ {
if (_enabled) if (_enabled)
_log_msg.raw << what; _log_msg.raw << what;
return *this; return *this;
} }
inline spdlog::details::line_logger& spdlog::details::line_logger::operator<<(long what) inline spdlog::details::line_logger& spdlog::details::line_logger::operator<<(long what)
{ {
if (_enabled) if (_enabled)
_log_msg.raw << what; _log_msg.raw << what;
return *this; return *this;
} }
inline spdlog::details::line_logger& spdlog::details::line_logger::operator<<(unsigned long what) inline spdlog::details::line_logger& spdlog::details::line_logger::operator<<(unsigned long what)
{ {
if (_enabled) if (_enabled)
_log_msg.raw << what; _log_msg.raw << what;
return *this; return *this;
} }
inline spdlog::details::line_logger& spdlog::details::line_logger::operator<<(long long what) inline spdlog::details::line_logger& spdlog::details::line_logger::operator<<(long long what)
{ {
if (_enabled) if (_enabled)
_log_msg.raw << what; _log_msg.raw << what;
return *this; return *this;
} }
inline spdlog::details::line_logger& spdlog::details::line_logger::operator<<(unsigned long long what) inline spdlog::details::line_logger& spdlog::details::line_logger::operator<<(unsigned long long what)
{ {
if (_enabled) if (_enabled)
_log_msg.raw << what; _log_msg.raw << what;
return *this; return *this;
} }
inline spdlog::details::line_logger& spdlog::details::line_logger::operator<<(double what) inline spdlog::details::line_logger& spdlog::details::line_logger::operator<<(double what)
{ {
if (_enabled) if (_enabled)
_log_msg.raw << what; _log_msg.raw << what;
return *this; return *this;
} }
inline spdlog::details::line_logger& spdlog::details::line_logger::operator<<(long double what) inline spdlog::details::line_logger& spdlog::details::line_logger::operator<<(long double what)
{ {
if (_enabled) if (_enabled)
_log_msg.raw << what; _log_msg.raw << what;
return *this; return *this;
} }
inline spdlog::details::line_logger& spdlog::details::line_logger::operator<<(float what) inline spdlog::details::line_logger& spdlog::details::line_logger::operator<<(float what)
{ {
if (_enabled) if (_enabled)
_log_msg.raw << what; _log_msg.raw << what;
return *this; return *this;
} }
inline spdlog::details::line_logger& spdlog::details::line_logger::operator<<(char what) inline spdlog::details::line_logger& spdlog::details::line_logger::operator<<(char what)
{ {
if (_enabled) if (_enabled)
_log_msg.raw << what; _log_msg.raw << what;
return *this; return *this;
} }
//Support user types which implements operator<< //Support user types which implements operator<<
template<typename T> template<typename T>
inline spdlog::details::line_logger& spdlog::details::line_logger::operator<<(const T& what) inline spdlog::details::line_logger& spdlog::details::line_logger::operator<<(const T& what)
{ {
if (_enabled) if (_enabled)
_log_msg.raw.write("{}", what); _log_msg.raw.write("{}", what);
return *this; return *this;
} }
inline void spdlog::details::line_logger::disable() inline void spdlog::details::line_logger::disable()
{ {
_enabled = false; _enabled = false;
} }
inline bool spdlog::details::line_logger::is_enabled() const inline bool spdlog::details::line_logger::is_enabled() const
{ {
return _enabled; return _enabled;
} }

View File

@ -1,81 +1,81 @@
// //
// Copyright(c) 2015 Gabi Melman. // Copyright(c) 2015 Gabi Melman.
// Distributed under the MIT License (http://opensource.org/licenses/MIT) // Distributed under the MIT License (http://opensource.org/licenses/MIT)
// //
#pragma once #pragma once
#include <spdlog/common.h> #include <spdlog/common.h>
#include <spdlog/details/format.h> #include <spdlog/details/format.h>
#include <string> #include <string>
#include <utility> #include <utility>
namespace spdlog namespace spdlog
{ {
namespace details namespace details
{ {
struct log_msg struct log_msg
{ {
log_msg() = default; log_msg() = default;
log_msg(level::level_enum l): log_msg(level::level_enum l):
logger_name(), logger_name(),
level(l), level(l),
raw(), raw(),
formatted() {} formatted() {}
log_msg(const log_msg& other) : log_msg(const log_msg& other) :
logger_name(other.logger_name), logger_name(other.logger_name),
level(other.level), level(other.level),
time(other.time), time(other.time),
thread_id(other.thread_id) thread_id(other.thread_id)
{ {
if (other.raw.size()) if (other.raw.size())
raw << fmt::BasicStringRef<char>(other.raw.data(), other.raw.size()); raw << fmt::BasicStringRef<char>(other.raw.data(), other.raw.size());
if (other.formatted.size()) if (other.formatted.size())
formatted << fmt::BasicStringRef<char>(other.formatted.data(), other.formatted.size()); formatted << fmt::BasicStringRef<char>(other.formatted.data(), other.formatted.size());
} }
log_msg(log_msg&& other) : log_msg(log_msg&& other) :
logger_name(std::move(other.logger_name)), logger_name(std::move(other.logger_name)),
level(other.level), level(other.level),
time(std::move(other.time)), time(std::move(other.time)),
thread_id(other.thread_id), thread_id(other.thread_id),
raw(std::move(other.raw)), raw(std::move(other.raw)),
formatted(std::move(other.formatted)) formatted(std::move(other.formatted))
{ {
other.clear(); other.clear();
} }
log_msg& operator=(log_msg&& other) log_msg& operator=(log_msg&& other)
{ {
if (this == &other) if (this == &other)
return *this; return *this;
logger_name = std::move(other.logger_name); logger_name = std::move(other.logger_name);
level = other.level; level = other.level;
time = std::move(other.time); time = std::move(other.time);
thread_id = other.thread_id; thread_id = other.thread_id;
raw = std::move(other.raw); raw = std::move(other.raw);
formatted = std::move(other.formatted); formatted = std::move(other.formatted);
other.clear(); other.clear();
return *this; return *this;
} }
void clear() void clear()
{ {
level = level::off; level = level::off;
raw.clear(); raw.clear();
formatted.clear(); formatted.clear();
} }
std::string logger_name; std::string logger_name;
level::level_enum level; level::level_enum level;
log_clock::time_point time; log_clock::time_point time;
size_t thread_id; size_t thread_id;
fmt::MemoryWriter raw; fmt::MemoryWriter raw;
fmt::MemoryWriter formatted; fmt::MemoryWriter formatted;
}; };
} }
} }

View File

@ -1,302 +1,302 @@
// //
// Copyright(c) 2015 Gabi Melman. // Copyright(c) 2015 Gabi Melman.
// Distributed under the MIT License (http://opensource.org/licenses/MIT) // Distributed under the MIT License (http://opensource.org/licenses/MIT)
// //
#pragma once #pragma once
#include <spdlog/logger.h> #include <spdlog/logger.h>
#include <memory> #include <memory>
#include <string> #include <string>
// create logger with given name, sinks and the default pattern formatter // create logger with given name, sinks and the default pattern formatter
// all other ctors will call this one // all other ctors will call this one
template<class It> template<class It>
inline spdlog::logger::logger(const std::string& logger_name, const It& begin, const It& end) : inline spdlog::logger::logger(const std::string& logger_name, const It& begin, const It& end) :
_name(logger_name), _name(logger_name),
_sinks(begin, end), _sinks(begin, end),
_formatter(std::make_shared<pattern_formatter>("%+")) _formatter(std::make_shared<pattern_formatter>("%+"))
{ {
// no support under vs2013 for member initialization for std::atomic // no support under vs2013 for member initialization for std::atomic
_level = level::info; _level = level::info;
} }
// ctor with sinks as init list // ctor with sinks as init list
inline spdlog::logger::logger(const std::string& logger_name, sinks_init_list sinks_list) : inline spdlog::logger::logger(const std::string& logger_name, sinks_init_list sinks_list) :
logger(logger_name, sinks_list.begin(), sinks_list.end()) {} logger(logger_name, sinks_list.begin(), sinks_list.end()) {}
// ctor with single sink // ctor with single sink
inline spdlog::logger::logger(const std::string& logger_name, spdlog::sink_ptr single_sink) : inline spdlog::logger::logger(const std::string& logger_name, spdlog::sink_ptr single_sink) :
logger(logger_name, logger(logger_name,
{ {
single_sink single_sink
}) {} }) {}
inline spdlog::logger::~logger() = default; inline spdlog::logger::~logger() = default;
inline void spdlog::logger::set_formatter(spdlog::formatter_ptr msg_formatter) inline void spdlog::logger::set_formatter(spdlog::formatter_ptr msg_formatter)
{ {
_set_formatter(msg_formatter); _set_formatter(msg_formatter);
} }
inline void spdlog::logger::set_pattern(const std::string& pattern) inline void spdlog::logger::set_pattern(const std::string& pattern)
{ {
_set_pattern(pattern); _set_pattern(pattern);
} }
// //
// log only if given level>=logger's log level // log only if given level>=logger's log level
// //
template <typename... Args> template <typename... Args>
inline spdlog::details::line_logger spdlog::logger::_log_if_enabled(level::level_enum lvl, const char* fmt, const Args&... args) inline spdlog::details::line_logger spdlog::logger::_log_if_enabled(level::level_enum lvl, const char* fmt, const Args&... args)
{ {
bool msg_enabled = should_log(lvl); bool msg_enabled = should_log(lvl);
details::line_logger l(this, lvl, msg_enabled); details::line_logger l(this, lvl, msg_enabled);
l.write(fmt, args...); l.write(fmt, args...);
return l; return l;
} }
inline spdlog::details::line_logger spdlog::logger::_log_if_enabled(level::level_enum lvl) inline spdlog::details::line_logger spdlog::logger::_log_if_enabled(level::level_enum lvl)
{ {
return details::line_logger(this, lvl, should_log(lvl)); return details::line_logger(this, lvl, should_log(lvl));
} }
template<typename T> template<typename T>
inline spdlog::details::line_logger spdlog::logger::_log_if_enabled(level::level_enum lvl, const T& msg) inline spdlog::details::line_logger spdlog::logger::_log_if_enabled(level::level_enum lvl, const T& msg)
{ {
bool msg_enabled = should_log(lvl); bool msg_enabled = should_log(lvl);
details::line_logger l(this, lvl, msg_enabled); details::line_logger l(this, lvl, msg_enabled);
l << msg; l << msg;
return l; return l;
} }
// //
// logger.info(cppformat_string, arg1, arg2, arg3, ...) call style // logger.info(cppformat_string, arg1, arg2, arg3, ...) call style
// //
template <typename... Args> template <typename... Args>
inline spdlog::details::line_logger spdlog::logger::trace(const char* fmt, const Args&... args) inline spdlog::details::line_logger spdlog::logger::trace(const char* fmt, const Args&... args)
{ {
return _log_if_enabled(level::trace, fmt, args...); return _log_if_enabled(level::trace, fmt, args...);
} }
template <typename... Args> template <typename... Args>
inline spdlog::details::line_logger spdlog::logger::debug(const char* fmt, const Args&... args) inline spdlog::details::line_logger spdlog::logger::debug(const char* fmt, const Args&... args)
{ {
return _log_if_enabled(level::debug, fmt, args...); return _log_if_enabled(level::debug, fmt, args...);
} }
template <typename... Args> template <typename... Args>
inline spdlog::details::line_logger spdlog::logger::info(const char* fmt, const Args&... args) inline spdlog::details::line_logger spdlog::logger::info(const char* fmt, const Args&... args)
{ {
return _log_if_enabled(level::info, fmt, args...); return _log_if_enabled(level::info, fmt, args...);
} }
template <typename... Args> template <typename... Args>
inline spdlog::details::line_logger spdlog::logger::notice(const char* fmt, const Args&... args) inline spdlog::details::line_logger spdlog::logger::notice(const char* fmt, const Args&... args)
{ {
return _log_if_enabled(level::notice, fmt, args...); return _log_if_enabled(level::notice, fmt, args...);
} }
template <typename... Args> template <typename... Args>
inline spdlog::details::line_logger spdlog::logger::warn(const char* fmt, const Args&... args) inline spdlog::details::line_logger spdlog::logger::warn(const char* fmt, const Args&... args)
{ {
return _log_if_enabled(level::warn, fmt, args...); return _log_if_enabled(level::warn, fmt, args...);
} }
template <typename... Args> template <typename... Args>
inline spdlog::details::line_logger spdlog::logger::error(const char* fmt, const Args&... args) inline spdlog::details::line_logger spdlog::logger::error(const char* fmt, const Args&... args)
{ {
return _log_if_enabled(level::err, fmt, args...); return _log_if_enabled(level::err, fmt, args...);
} }
template <typename... Args> template <typename... Args>
inline spdlog::details::line_logger spdlog::logger::critical(const char* fmt, const Args&... args) inline spdlog::details::line_logger spdlog::logger::critical(const char* fmt, const Args&... args)
{ {
return _log_if_enabled(level::critical, fmt, args...); return _log_if_enabled(level::critical, fmt, args...);
} }
template <typename... Args> template <typename... Args>
inline spdlog::details::line_logger spdlog::logger::alert(const char* fmt, const Args&... args) inline spdlog::details::line_logger spdlog::logger::alert(const char* fmt, const Args&... args)
{ {
return _log_if_enabled(level::alert, fmt, args...); return _log_if_enabled(level::alert, fmt, args...);
} }
template <typename... Args> template <typename... Args>
inline spdlog::details::line_logger spdlog::logger::emerg(const char* fmt, const Args&... args) inline spdlog::details::line_logger spdlog::logger::emerg(const char* fmt, const Args&... args)
{ {
return _log_if_enabled(level::emerg, fmt, args...); return _log_if_enabled(level::emerg, fmt, args...);
} }
// //
// logger.info(msg) << ".." call style // logger.info(msg) << ".." call style
// //
template<typename T> template<typename T>
inline spdlog::details::line_logger spdlog::logger::trace(const T& msg) inline spdlog::details::line_logger spdlog::logger::trace(const T& msg)
{ {
return _log_if_enabled(level::trace, msg); return _log_if_enabled(level::trace, msg);
} }
template<typename T> template<typename T>
inline spdlog::details::line_logger spdlog::logger::debug(const T& msg) inline spdlog::details::line_logger spdlog::logger::debug(const T& msg)
{ {
return _log_if_enabled(level::debug, msg); return _log_if_enabled(level::debug, msg);
} }
template<typename T> template<typename T>
inline spdlog::details::line_logger spdlog::logger::info(const T& msg) inline spdlog::details::line_logger spdlog::logger::info(const T& msg)
{ {
return _log_if_enabled(level::info, msg); return _log_if_enabled(level::info, msg);
} }
template<typename T> template<typename T>
inline spdlog::details::line_logger spdlog::logger::notice(const T& msg) inline spdlog::details::line_logger spdlog::logger::notice(const T& msg)
{ {
return _log_if_enabled(level::notice, msg); return _log_if_enabled(level::notice, msg);
} }
template<typename T> template<typename T>
inline spdlog::details::line_logger spdlog::logger::warn(const T& msg) inline spdlog::details::line_logger spdlog::logger::warn(const T& msg)
{ {
return _log_if_enabled(level::warn, msg); return _log_if_enabled(level::warn, msg);
} }
template<typename T> template<typename T>
inline spdlog::details::line_logger spdlog::logger::error(const T& msg) inline spdlog::details::line_logger spdlog::logger::error(const T& msg)
{ {
return _log_if_enabled(level::err, msg); return _log_if_enabled(level::err, msg);
} }
template<typename T> template<typename T>
inline spdlog::details::line_logger spdlog::logger::critical(const T& msg) inline spdlog::details::line_logger spdlog::logger::critical(const T& msg)
{ {
return _log_if_enabled(level::critical, msg); return _log_if_enabled(level::critical, msg);
} }
template<typename T> template<typename T>
inline spdlog::details::line_logger spdlog::logger::alert(const T& msg) inline spdlog::details::line_logger spdlog::logger::alert(const T& msg)
{ {
return _log_if_enabled(level::alert, msg); return _log_if_enabled(level::alert, msg);
} }
template<typename T> template<typename T>
inline spdlog::details::line_logger spdlog::logger::emerg(const T& msg) inline spdlog::details::line_logger spdlog::logger::emerg(const T& msg)
{ {
return _log_if_enabled(level::emerg, msg); return _log_if_enabled(level::emerg, msg);
} }
// //
// logger.info() << ".." call style // logger.info() << ".." call style
// //
inline spdlog::details::line_logger spdlog::logger::trace() inline spdlog::details::line_logger spdlog::logger::trace()
{ {
return _log_if_enabled(level::trace); return _log_if_enabled(level::trace);
} }
inline spdlog::details::line_logger spdlog::logger::debug() inline spdlog::details::line_logger spdlog::logger::debug()
{ {
return _log_if_enabled(level::debug); return _log_if_enabled(level::debug);
} }
inline spdlog::details::line_logger spdlog::logger::info() inline spdlog::details::line_logger spdlog::logger::info()
{ {
return _log_if_enabled(level::info); return _log_if_enabled(level::info);
} }
inline spdlog::details::line_logger spdlog::logger::notice() inline spdlog::details::line_logger spdlog::logger::notice()
{ {
return _log_if_enabled(level::notice); return _log_if_enabled(level::notice);
} }
inline spdlog::details::line_logger spdlog::logger::warn() inline spdlog::details::line_logger spdlog::logger::warn()
{ {
return _log_if_enabled(level::warn); return _log_if_enabled(level::warn);
} }
inline spdlog::details::line_logger spdlog::logger::error() inline spdlog::details::line_logger spdlog::logger::error()
{ {
return _log_if_enabled(level::err); return _log_if_enabled(level::err);
} }
inline spdlog::details::line_logger spdlog::logger::critical() inline spdlog::details::line_logger spdlog::logger::critical()
{ {
return _log_if_enabled(level::critical); return _log_if_enabled(level::critical);
} }
inline spdlog::details::line_logger spdlog::logger::alert() inline spdlog::details::line_logger spdlog::logger::alert()
{ {
return _log_if_enabled(level::alert); return _log_if_enabled(level::alert);
} }
inline spdlog::details::line_logger spdlog::logger::emerg() inline spdlog::details::line_logger spdlog::logger::emerg()
{ {
return _log_if_enabled(level::emerg); return _log_if_enabled(level::emerg);
} }
// always log, no matter what is the actual logger's log level // always log, no matter what is the actual logger's log level
template <typename... Args> template <typename... Args>
inline spdlog::details::line_logger spdlog::logger::force_log(level::level_enum lvl, const char* fmt, const Args&... args) inline spdlog::details::line_logger spdlog::logger::force_log(level::level_enum lvl, const char* fmt, const Args&... args)
{ {
details::line_logger l(this, lvl, true); details::line_logger l(this, lvl, true);
l.write(fmt, args...); l.write(fmt, args...);
return l; return l;
} }
// //
// name and level // name and level
// //
inline const std::string& spdlog::logger::name() const inline const std::string& spdlog::logger::name() const
{ {
return _name; return _name;
} }
inline void spdlog::logger::set_level(spdlog::level::level_enum log_level) inline void spdlog::logger::set_level(spdlog::level::level_enum log_level)
{ {
_level.store(log_level); _level.store(log_level);
} }
inline spdlog::level::level_enum spdlog::logger::level() const inline spdlog::level::level_enum spdlog::logger::level() const
{ {
return static_cast<spdlog::level::level_enum>(_level.load(std::memory_order_relaxed)); return static_cast<spdlog::level::level_enum>(_level.load(std::memory_order_relaxed));
} }
inline bool spdlog::logger::should_log(spdlog::level::level_enum msg_level) const inline bool spdlog::logger::should_log(spdlog::level::level_enum msg_level) const
{ {
return msg_level >= _level.load(std::memory_order_relaxed); return msg_level >= _level.load(std::memory_order_relaxed);
} }
// //
// protected virtual called at end of each user log call (if enabled) by the line_logger // protected virtual called at end of each user log call (if enabled) by the line_logger
// //
inline void spdlog::logger::_log_msg(details::log_msg& msg) inline void spdlog::logger::_log_msg(details::log_msg& msg)
{ {
_formatter->format(msg); _formatter->format(msg);
for (auto &sink : _sinks) for (auto &sink : _sinks)
sink->log(msg); sink->log(msg);
} }
inline void spdlog::logger::_set_pattern(const std::string& pattern) inline void spdlog::logger::_set_pattern(const std::string& pattern)
{ {
_formatter = std::make_shared<pattern_formatter>(pattern); _formatter = std::make_shared<pattern_formatter>(pattern);
} }
inline void spdlog::logger::_set_formatter(formatter_ptr msg_formatter) inline void spdlog::logger::_set_formatter(formatter_ptr msg_formatter)
{ {
_formatter = msg_formatter; _formatter = msg_formatter;
} }
inline void spdlog::logger::flush() inline void spdlog::logger::flush()
{ {
for (auto& sink : _sinks) for (auto& sink : _sinks)
sink->flush(); sink->flush();
} }

View File

@ -1,159 +1,159 @@
/* /*
A modified version of Bounded MPMC queue by Dmitry Vyukov. A modified version of Bounded MPMC queue by Dmitry Vyukov.
Original code from: Original code from:
http://www.1024cores.net/home/lock-free-algorithms/queues/bounded-mpmc-queue http://www.1024cores.net/home/lock-free-algorithms/queues/bounded-mpmc-queue
licensed by Dmitry Vyukov under the terms below: licensed by Dmitry Vyukov under the terms below:
Simplified BSD license Simplified BSD license
Copyright (c) 2010-2011 Dmitry Vyukov. All rights reserved. Copyright (c) 2010-2011 Dmitry Vyukov. All rights reserved.
Redistribution and use in source and binary forms, with or without modification, Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met: are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this list of 1. Redistributions of source code must retain the above copyright notice, this list of
conditions and the following disclaimer. conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice, this list 2. Redistributions in binary form must reproduce the above copyright notice, this list
of conditions and the following disclaimer in the documentation and/or other materials of conditions and the following disclaimer in the documentation and/or other materials
provided with the distribution. provided with the distribution.
THIS SOFTWARE IS PROVIDED BY DMITRY VYUKOV "AS IS" AND ANY EXPRESS OR IMPLIED THIS SOFTWARE IS PROVIDED BY DMITRY VYUKOV "AS IS" AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
SHALL DMITRY VYUKOV OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, SHALL DMITRY VYUKOV OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
The views and conclusions contained in the software and documentation are those of the authors and The views and conclusions contained in the software and documentation are those of the authors and
should not be interpreted as representing official policies, either expressed or implied, of Dmitry Vyukov. should not be interpreted as representing official policies, either expressed or implied, of Dmitry Vyukov.
*/ */
/* /*
The code in its current form adds the license below: The code in its current form adds the license below:
Copyright(c) 2015 Gabi Melman. Copyright(c) 2015 Gabi Melman.
Distributed under the MIT License (http://opensource.org/licenses/MIT) Distributed under the MIT License (http://opensource.org/licenses/MIT)
*/ */
#pragma once #pragma once
#include <spdlog/common.h> #include <spdlog/common.h>
#include <atomic> #include <atomic>
#include <utility> #include <utility>
namespace spdlog namespace spdlog
{ {
namespace details namespace details
{ {
template<typename T> template<typename T>
class mpmc_bounded_queue class mpmc_bounded_queue
{ {
public: public:
using item_type = T; using item_type = T;
mpmc_bounded_queue(size_t buffer_size) mpmc_bounded_queue(size_t buffer_size)
: buffer_(new cell_t [buffer_size]), : buffer_(new cell_t [buffer_size]),
buffer_mask_(buffer_size - 1) buffer_mask_(buffer_size - 1)
{ {
//queue size must be power of two //queue size must be power of two
if(!((buffer_size >= 2) && ((buffer_size & (buffer_size - 1)) == 0))) if(!((buffer_size >= 2) && ((buffer_size & (buffer_size - 1)) == 0)))
throw spdlog_ex("async logger queue size must be power of two"); throw spdlog_ex("async logger queue size must be power of two");
for (size_t i = 0; i != buffer_size; i += 1) for (size_t i = 0; i != buffer_size; i += 1)
buffer_[i].sequence_.store(i, std::memory_order_relaxed); buffer_[i].sequence_.store(i, std::memory_order_relaxed);
enqueue_pos_.store(0, std::memory_order_relaxed); enqueue_pos_.store(0, std::memory_order_relaxed);
dequeue_pos_.store(0, std::memory_order_relaxed); dequeue_pos_.store(0, std::memory_order_relaxed);
} }
~mpmc_bounded_queue() ~mpmc_bounded_queue()
{ {
delete [] buffer_; delete [] buffer_;
} }
bool enqueue(T&& data) bool enqueue(T&& data)
{ {
cell_t* cell; cell_t* cell;
size_t pos = enqueue_pos_.load(std::memory_order_relaxed); size_t pos = enqueue_pos_.load(std::memory_order_relaxed);
for (;;) for (;;)
{ {
cell = &buffer_[pos & buffer_mask_]; cell = &buffer_[pos & buffer_mask_];
size_t seq = cell->sequence_.load(std::memory_order_acquire); size_t seq = cell->sequence_.load(std::memory_order_acquire);
intptr_t dif = (intptr_t)seq - (intptr_t)pos; intptr_t dif = (intptr_t)seq - (intptr_t)pos;
if (dif == 0) if (dif == 0)
{ {
if (enqueue_pos_.compare_exchange_weak(pos, pos + 1, std::memory_order_relaxed)) if (enqueue_pos_.compare_exchange_weak(pos, pos + 1, std::memory_order_relaxed))
break; break;
} }
else if (dif < 0) else if (dif < 0)
{ {
return false; return false;
} }
else else
{ {
pos = enqueue_pos_.load(std::memory_order_relaxed); pos = enqueue_pos_.load(std::memory_order_relaxed);
} }
} }
cell->data_ = std::move(data); cell->data_ = std::move(data);
cell->sequence_.store(pos + 1, std::memory_order_release); cell->sequence_.store(pos + 1, std::memory_order_release);
return true; return true;
} }
bool dequeue(T& data) bool dequeue(T& data)
{ {
cell_t* cell; cell_t* cell;
size_t pos = dequeue_pos_.load(std::memory_order_relaxed); size_t pos = dequeue_pos_.load(std::memory_order_relaxed);
for (;;) for (;;)
{ {
cell = &buffer_[pos & buffer_mask_]; cell = &buffer_[pos & buffer_mask_];
size_t seq = size_t seq =
cell->sequence_.load(std::memory_order_acquire); cell->sequence_.load(std::memory_order_acquire);
intptr_t dif = (intptr_t)seq - (intptr_t)(pos + 1); intptr_t dif = (intptr_t)seq - (intptr_t)(pos + 1);
if (dif == 0) if (dif == 0)
{ {
if (dequeue_pos_.compare_exchange_weak(pos, pos + 1, std::memory_order_relaxed)) if (dequeue_pos_.compare_exchange_weak(pos, pos + 1, std::memory_order_relaxed))
break; break;
} }
else if (dif < 0) else if (dif < 0)
return false; return false;
else else
pos = dequeue_pos_.load(std::memory_order_relaxed); pos = dequeue_pos_.load(std::memory_order_relaxed);
} }
data = std::move(cell->data_); data = std::move(cell->data_);
cell->sequence_.store(pos + buffer_mask_ + 1, std::memory_order_release); cell->sequence_.store(pos + buffer_mask_ + 1, std::memory_order_release);
return true; return true;
} }
private: private:
struct cell_t struct cell_t
{ {
std::atomic<size_t> sequence_; std::atomic<size_t> sequence_;
T data_; T data_;
}; };
static size_t const cacheline_size = 64; static size_t const cacheline_size = 64;
typedef char cacheline_pad_t [cacheline_size]; typedef char cacheline_pad_t [cacheline_size];
cacheline_pad_t pad0_; cacheline_pad_t pad0_;
cell_t* const buffer_; cell_t* const buffer_;
size_t const buffer_mask_; size_t const buffer_mask_;
cacheline_pad_t pad1_; cacheline_pad_t pad1_;
std::atomic<size_t> enqueue_pos_; std::atomic<size_t> enqueue_pos_;
cacheline_pad_t pad2_; cacheline_pad_t pad2_;
std::atomic<size_t> dequeue_pos_; std::atomic<size_t> dequeue_pos_;
cacheline_pad_t pad3_; cacheline_pad_t pad3_;
mpmc_bounded_queue(mpmc_bounded_queue const&); mpmc_bounded_queue(mpmc_bounded_queue const&);
void operator = (mpmc_bounded_queue const&); void operator = (mpmc_bounded_queue const&);
}; };
} // ns details } // ns details
} // ns spdlog } // ns spdlog

View File

@ -24,21 +24,21 @@ struct null_mutex
struct null_atomic_int struct null_atomic_int
{ {
int value; int value;
null_atomic_int() = default; null_atomic_int() = default;
null_atomic_int(int val):value(val) null_atomic_int(int val):value(val)
{} {}
int load(std::memory_order) const int load(std::memory_order) const
{ {
return value; return value;
} }
void store(int val) void store(int val)
{ {
value = val; value = val;
} }
}; };
} }

View File

@ -1,246 +1,246 @@
// //
// Copyright(c) 2015 Gabi Melman. // Copyright(c) 2015 Gabi Melman.
// Distributed under the MIT License (http://opensource.org/licenses/MIT) // Distributed under the MIT License (http://opensource.org/licenses/MIT)
// //
#pragma once #pragma once
#include <spdlog/common.h> #include <spdlog/common.h>
#include <cstdio> #include <cstdio>
#include <ctime> #include <ctime>
#include <functional> #include <functional>
#include <string> #include <string>
#ifdef _WIN32 #ifdef _WIN32
#ifndef NOMINMAX #ifndef NOMINMAX
#define NOMINMAX //prevent windows redefining min/max #define NOMINMAX //prevent windows redefining min/max
#endif #endif
#ifndef WIN32_LEAN_AND_MEAN #ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN
#endif #endif
#include <windows.h> #include <windows.h>
#ifdef __MINGW32__ #ifdef __MINGW32__
#include <share.h> #include <share.h>
#endif #endif
#elif __linux__ #elif __linux__
#include <sys/syscall.h> //Use gettid() syscall under linux to get thread id #include <sys/syscall.h> //Use gettid() syscall under linux to get thread id
#include <sys/stat.h> #include <sys/stat.h>
#include <unistd.h> #include <unistd.h>
#include <chrono> #include <chrono>
#else #else
#include <thread> #include <thread>
#endif #endif
namespace spdlog namespace spdlog
{ {
namespace details namespace details
{ {
namespace os namespace os
{ {
inline spdlog::log_clock::time_point now() inline spdlog::log_clock::time_point now()
{ {
#if defined __linux__ && defined SPDLOG_CLOCK_COARSE #if defined __linux__ && defined SPDLOG_CLOCK_COARSE
timespec ts; timespec ts;
::clock_gettime(CLOCK_REALTIME_COARSE, &ts); ::clock_gettime(CLOCK_REALTIME_COARSE, &ts);
return std::chrono::time_point<log_clock, typename log_clock::duration>( return std::chrono::time_point<log_clock, typename log_clock::duration>(
std::chrono::duration_cast<typename log_clock::duration>( std::chrono::duration_cast<typename log_clock::duration>(
std::chrono::seconds(ts.tv_sec) + std::chrono::nanoseconds(ts.tv_nsec))); std::chrono::seconds(ts.tv_sec) + std::chrono::nanoseconds(ts.tv_nsec)));
#else #else
return log_clock::now(); return log_clock::now();
#endif #endif
} }
inline std::tm localtime(const std::time_t &time_tt) inline std::tm localtime(const std::time_t &time_tt)
{ {
#ifdef _WIN32 #ifdef _WIN32
std::tm tm; std::tm tm;
localtime_s(&tm, &time_tt); localtime_s(&tm, &time_tt);
#else #else
std::tm tm; std::tm tm;
localtime_r(&time_tt, &tm); localtime_r(&time_tt, &tm);
#endif #endif
return tm; return tm;
} }
inline std::tm localtime() inline std::tm localtime()
{ {
std::time_t now_t = time(nullptr); std::time_t now_t = time(nullptr);
return localtime(now_t); return localtime(now_t);
} }
inline std::tm gmtime(const std::time_t &time_tt) inline std::tm gmtime(const std::time_t &time_tt)
{ {
#ifdef _WIN32 #ifdef _WIN32
std::tm tm; std::tm tm;
gmtime_s(&tm, &time_tt); gmtime_s(&tm, &time_tt);
#else #else
std::tm tm; std::tm tm;
gmtime_r(&time_tt, &tm); gmtime_r(&time_tt, &tm);
#endif #endif
return tm; return tm;
} }
inline std::tm gmtime() inline std::tm gmtime()
{ {
std::time_t now_t = time(nullptr); std::time_t now_t = time(nullptr);
return gmtime(now_t); return gmtime(now_t);
} }
inline bool operator==(const std::tm& tm1, const std::tm& tm2) inline bool operator==(const std::tm& tm1, const std::tm& tm2)
{ {
return (tm1.tm_sec == tm2.tm_sec && return (tm1.tm_sec == tm2.tm_sec &&
tm1.tm_min == tm2.tm_min && tm1.tm_min == tm2.tm_min &&
tm1.tm_hour == tm2.tm_hour && tm1.tm_hour == tm2.tm_hour &&
tm1.tm_mday == tm2.tm_mday && tm1.tm_mday == tm2.tm_mday &&
tm1.tm_mon == tm2.tm_mon && tm1.tm_mon == tm2.tm_mon &&
tm1.tm_year == tm2.tm_year && tm1.tm_year == tm2.tm_year &&
tm1.tm_isdst == tm2.tm_isdst); tm1.tm_isdst == tm2.tm_isdst);
} }
inline bool operator!=(const std::tm& tm1, const std::tm& tm2) inline bool operator!=(const std::tm& tm1, const std::tm& tm2)
{ {
return !(tm1 == tm2); return !(tm1 == tm2);
} }
#ifdef _WIN32 #ifdef _WIN32
inline const char* eol() inline const char* eol()
{ {
return "\r\n"; return "\r\n";
} }
#else #else
constexpr inline const char* eol() constexpr inline const char* eol()
{ {
return "\n"; return "\n";
} }
#endif #endif
#ifdef _WIN32 #ifdef _WIN32
inline unsigned short eol_size() inline unsigned short eol_size()
{ {
return 2; return 2;
} }
#else #else
constexpr inline unsigned short eol_size() constexpr inline unsigned short eol_size()
{ {
return 1; return 1;
} }
#endif #endif
//fopen_s on non windows for writing //fopen_s on non windows for writing
inline int fopen_s(FILE** fp, const filename_t& filename, const filename_t& mode) inline int fopen_s(FILE** fp, const filename_t& filename, const filename_t& mode)
{ {
#ifdef _WIN32 #ifdef _WIN32
#ifdef SPDLOG_WCHAR_FILENAMES #ifdef SPDLOG_WCHAR_FILENAMES
*fp = _wfsopen((filename.c_str()), mode.c_str(), _SH_DENYWR); *fp = _wfsopen((filename.c_str()), mode.c_str(), _SH_DENYWR);
#else #else
*fp = _fsopen((filename.c_str()), mode.c_str(), _SH_DENYWR); *fp = _fsopen((filename.c_str()), mode.c_str(), _SH_DENYWR);
#endif #endif
return *fp == nullptr; return *fp == nullptr;
#else #else
*fp = fopen((filename.c_str()), mode.c_str()); *fp = fopen((filename.c_str()), mode.c_str());
return *fp == nullptr; return *fp == nullptr;
#endif #endif
} }
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)
return _wremove(filename.c_str()); return _wremove(filename.c_str());
#else #else
return std::remove(filename.c_str()); return std::remove(filename.c_str());
#endif #endif
} }
inline int rename(const filename_t& filename1, const filename_t& filename2) inline int rename(const filename_t& filename1, const filename_t& filename2)
{ {
#if defined(_WIN32) && defined(SPDLOG_WCHAR_FILENAMES) #if defined(_WIN32) && defined(SPDLOG_WCHAR_FILENAMES)
return _wrename(filename1.c_str(), filename2.c_str()); return _wrename(filename1.c_str(), filename2.c_str());
#else #else
return std::rename(filename1.c_str(), filename2.c_str()); return std::rename(filename1.c_str(), filename2.c_str());
#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)
{ {
#ifdef _WIN32 #ifdef _WIN32
#ifdef SPDLOG_WCHAR_FILENAMES #ifdef SPDLOG_WCHAR_FILENAMES
auto attribs = GetFileAttributesW(filename.c_str()); auto attribs = GetFileAttributesW(filename.c_str());
#else #else
auto attribs = GetFileAttributesA(filename.c_str()); auto attribs = GetFileAttributesA(filename.c_str());
#endif #endif
return (attribs != INVALID_FILE_ATTRIBUTES && !(attribs & FILE_ATTRIBUTE_DIRECTORY)); return (attribs != INVALID_FILE_ATTRIBUTES && !(attribs & FILE_ATTRIBUTE_DIRECTORY));
#elif __linux__ #elif __linux__
struct stat buffer; struct stat buffer;
return (stat (filename.c_str(), &buffer) == 0); return (stat (filename.c_str(), &buffer) == 0);
#else #else
auto *file = fopen(filename.c_str(), "r"); auto *file = fopen(filename.c_str(), "r");
if (file != nullptr) if (file != nullptr)
{ {
fclose(file); fclose(file);
return true; return true;
} }
return false; return false;
#endif #endif
} }
//Return utc offset in minutes or throw spdlog_ex on failure //Return utc offset in minutes or throw spdlog_ex on failure
inline int utc_minutes_offset(const std::tm& tm = details::os::localtime()) inline int utc_minutes_offset(const std::tm& tm = details::os::localtime())
{ {
#ifdef _WIN32 #ifdef _WIN32
#if _WIN32_WINNT < _WIN32_WINNT_WS08 #if _WIN32_WINNT < _WIN32_WINNT_WS08
TIME_ZONE_INFORMATION tzinfo; TIME_ZONE_INFORMATION tzinfo;
auto rv = GetTimeZoneInformation(&tzinfo); auto rv = GetTimeZoneInformation(&tzinfo);
#else #else
DYNAMIC_TIME_ZONE_INFORMATION tzinfo; DYNAMIC_TIME_ZONE_INFORMATION tzinfo;
auto rv = GetDynamicTimeZoneInformation(&tzinfo); auto rv = GetDynamicTimeZoneInformation(&tzinfo);
#endif #endif
if (rv == TIME_ZONE_ID_INVALID) if (rv == TIME_ZONE_ID_INVALID)
throw spdlog::spdlog_ex("Failed getting timezone info. Last error: " + GetLastError()); throw spdlog::spdlog_ex("Failed getting timezone info. Last error: " + GetLastError());
int offset = -tzinfo.Bias; int offset = -tzinfo.Bias;
if (tm.tm_isdst) if (tm.tm_isdst)
offset -= tzinfo.DaylightBias; offset -= tzinfo.DaylightBias;
else else
offset -= tzinfo.StandardBias; offset -= tzinfo.StandardBias;
return offset; return offset;
#else #else
return static_cast<int>(tm.tm_gmtoff / 60); return static_cast<int>(tm.tm_gmtoff / 60);
#endif #endif
} }
//Return current thread id as size_t //Return current thread id as size_t
//It exists because the std::this_thread::get_id() is much slower(espcially under VS 2013) //It exists because the std::this_thread::get_id() is much slower(espcially under VS 2013)
inline size_t thread_id() inline size_t thread_id()
{ {
#ifdef _WIN32 #ifdef _WIN32
return static_cast<size_t>(::GetCurrentThreadId()); return static_cast<size_t>(::GetCurrentThreadId());
#elif __linux__ #elif __linux__
# if defined(__ANDROID__) && defined(__ANDROID_API__) && (__ANDROID_API__ < 21) # if defined(__ANDROID__) && defined(__ANDROID_API__) && (__ANDROID_API__ < 21)
# define SYS_gettid __NR_gettid # define SYS_gettid __NR_gettid
# endif # endif
return static_cast<size_t>(syscall(SYS_gettid)); return static_cast<size_t>(syscall(SYS_gettid));
#else //Default to standard C++11 (OSX and other Unix) #else //Default to standard C++11 (OSX and other Unix)
return static_cast<size_t>(std::hash<std::thread::id>()(std::this_thread::get_id())); return static_cast<size_t>(std::hash<std::thread::id>()(std::this_thread::get_id()));
#endif #endif
} }
} //os } //os
} //details } //details
} //spdlog } //spdlog

File diff suppressed because it is too large Load Diff

View File

@ -1,163 +1,163 @@
// //
// Copyright(c) 2015 Gabi Melman. // Copyright(c) 2015 Gabi Melman.
// Distributed under the MIT License (http://opensource.org/licenses/MIT) // Distributed under the MIT License (http://opensource.org/licenses/MIT)
// //
#pragma once #pragma once
// Loggers registy of unique name->logger pointer // Loggers registy of unique name->logger pointer
// An attempt to create a logger with an already existing name will be ignored // An attempt to create a logger with an already existing name will be ignored
// If user requests a non existing logger, nullptr will be returned // If user requests a non existing logger, nullptr will be returned
// This class is thread safe // This class is thread safe
#include <spdlog/details/null_mutex.h> #include <spdlog/details/null_mutex.h>
#include <spdlog/logger.h> #include <spdlog/logger.h>
#include <spdlog/async_logger.h> #include <spdlog/async_logger.h>
#include <spdlog/common.h> #include <spdlog/common.h>
#include <chrono> #include <chrono>
#include <functional> #include <functional>
#include <memory> #include <memory>
#include <mutex> #include <mutex>
#include <string> #include <string>
#include <unordered_map> #include <unordered_map>
namespace spdlog namespace spdlog
{ {
namespace details namespace details
{ {
template <class Mutex> class registry_t template <class Mutex> class registry_t
{ {
public: public:
void register_logger(std::shared_ptr<logger> logger) void register_logger(std::shared_ptr<logger> logger)
{ {
std::lock_guard<Mutex> lock(_mutex); std::lock_guard<Mutex> lock(_mutex);
auto logger_name = logger->name(); auto logger_name = logger->name();
throw_if_exists(logger_name); throw_if_exists(logger_name);
_loggers[logger_name] = logger; _loggers[logger_name] = logger;
} }
std::shared_ptr<logger> get(const std::string& logger_name) std::shared_ptr<logger> get(const std::string& logger_name)
{ {
std::lock_guard<Mutex> lock(_mutex); std::lock_guard<Mutex> lock(_mutex);
auto found = _loggers.find(logger_name); auto found = _loggers.find(logger_name);
return found == _loggers.end() ? nullptr : found->second; return found == _loggers.end() ? nullptr : found->second;
} }
template<class It> template<class It>
std::shared_ptr<logger> create(const std::string& logger_name, const It& sinks_begin, const It& sinks_end) std::shared_ptr<logger> create(const std::string& logger_name, const It& sinks_begin, const It& sinks_end)
{ {
std::lock_guard<Mutex> lock(_mutex); std::lock_guard<Mutex> lock(_mutex);
throw_if_exists(logger_name); throw_if_exists(logger_name);
std::shared_ptr<logger> new_logger; std::shared_ptr<logger> new_logger;
if (_async_mode) if (_async_mode)
new_logger = std::make_shared<async_logger>(logger_name, sinks_begin, sinks_end, _async_q_size, _overflow_policy, _worker_warmup_cb, _flush_interval_ms); new_logger = std::make_shared<async_logger>(logger_name, sinks_begin, sinks_end, _async_q_size, _overflow_policy, _worker_warmup_cb, _flush_interval_ms);
else else
new_logger = std::make_shared<logger>(logger_name, sinks_begin, sinks_end); new_logger = std::make_shared<logger>(logger_name, sinks_begin, sinks_end);
if (_formatter) if (_formatter)
new_logger->set_formatter(_formatter); new_logger->set_formatter(_formatter);
new_logger->set_level(_level); new_logger->set_level(_level);
//Add to registry //Add to registry
_loggers[logger_name] = new_logger; _loggers[logger_name] = new_logger;
return new_logger; return new_logger;
} }
void drop(const std::string& logger_name) void drop(const std::string& logger_name)
{ {
std::lock_guard<Mutex> lock(_mutex); std::lock_guard<Mutex> lock(_mutex);
_loggers.erase(logger_name); _loggers.erase(logger_name);
} }
void drop_all() void drop_all()
{ {
std::lock_guard<Mutex> lock(_mutex); std::lock_guard<Mutex> lock(_mutex);
_loggers.clear(); _loggers.clear();
} }
std::shared_ptr<logger> create(const std::string& logger_name, sinks_init_list sinks) std::shared_ptr<logger> create(const std::string& logger_name, sinks_init_list sinks)
{ {
return create(logger_name, sinks.begin(), sinks.end()); return create(logger_name, sinks.begin(), sinks.end());
} }
std::shared_ptr<logger> create(const std::string& logger_name, sink_ptr sink) std::shared_ptr<logger> create(const std::string& logger_name, sink_ptr sink)
{ {
return create(logger_name, { sink }); return create(logger_name, { sink });
} }
void formatter(formatter_ptr f) void formatter(formatter_ptr f)
{ {
std::lock_guard<Mutex> lock(_mutex); std::lock_guard<Mutex> lock(_mutex);
_formatter = f; _formatter = f;
for (auto& l : _loggers) for (auto& l : _loggers)
l.second->set_formatter(_formatter); l.second->set_formatter(_formatter);
} }
void set_pattern(const std::string& pattern) void set_pattern(const std::string& pattern)
{ {
std::lock_guard<Mutex> lock(_mutex); std::lock_guard<Mutex> lock(_mutex);
_formatter = std::make_shared<pattern_formatter>(pattern); _formatter = std::make_shared<pattern_formatter>(pattern);
for (auto& l : _loggers) for (auto& l : _loggers)
l.second->set_formatter(_formatter); l.second->set_formatter(_formatter);
} }
void set_level(level::level_enum log_level) void set_level(level::level_enum log_level)
{ {
std::lock_guard<Mutex> lock(_mutex); std::lock_guard<Mutex> lock(_mutex);
for (auto& l : _loggers) for (auto& l : _loggers)
l.second->set_level(log_level); l.second->set_level(log_level);
_level = log_level; _level = log_level;
} }
void set_async_mode(size_t q_size, const async_overflow_policy overflow_policy, const std::function<void()>& worker_warmup_cb, const std::chrono::milliseconds& flush_interval_ms) void set_async_mode(size_t q_size, const async_overflow_policy overflow_policy, const std::function<void()>& worker_warmup_cb, const std::chrono::milliseconds& flush_interval_ms)
{ {
std::lock_guard<Mutex> lock(_mutex); std::lock_guard<Mutex> lock(_mutex);
_async_mode = true; _async_mode = true;
_async_q_size = q_size; _async_q_size = q_size;
_overflow_policy = overflow_policy; _overflow_policy = overflow_policy;
_worker_warmup_cb = worker_warmup_cb; _worker_warmup_cb = worker_warmup_cb;
_flush_interval_ms = flush_interval_ms; _flush_interval_ms = flush_interval_ms;
} }
void set_sync_mode() void set_sync_mode()
{ {
std::lock_guard<Mutex> lock(_mutex); std::lock_guard<Mutex> lock(_mutex);
_async_mode = false; _async_mode = false;
} }
static registry_t<Mutex>& instance() static registry_t<Mutex>& instance()
{ {
static registry_t<Mutex> s_instance; static registry_t<Mutex> s_instance;
return s_instance; return s_instance;
} }
private: private:
registry_t<Mutex>() {} registry_t<Mutex>() {}
registry_t<Mutex>(const registry_t<Mutex>&) = delete; registry_t<Mutex>(const registry_t<Mutex>&) = delete;
registry_t<Mutex>& operator=(const registry_t<Mutex>&) = delete; registry_t<Mutex>& operator=(const registry_t<Mutex>&) = delete;
void throw_if_exists(const std::string &logger_name) void throw_if_exists(const std::string &logger_name)
{ {
if (_loggers.find(logger_name) != _loggers.end()) if (_loggers.find(logger_name) != _loggers.end())
throw spdlog_ex("logger with name '" + logger_name + "' already exists"); throw spdlog_ex("logger with name '" + logger_name + "' already exists");
} }
Mutex _mutex; Mutex _mutex;
std::unordered_map <std::string, std::shared_ptr<logger>> _loggers; std::unordered_map <std::string, std::shared_ptr<logger>> _loggers;
formatter_ptr _formatter; formatter_ptr _formatter;
level::level_enum _level = level::info; level::level_enum _level = level::info;
bool _async_mode = false; bool _async_mode = false;
size_t _async_q_size = 0; size_t _async_q_size = 0;
async_overflow_policy _overflow_policy = async_overflow_policy::block_retry; async_overflow_policy _overflow_policy = async_overflow_policy::block_retry;
std::function<void()> _worker_warmup_cb = nullptr; std::function<void()> _worker_warmup_cb = nullptr;
std::chrono::milliseconds _flush_interval_ms; std::chrono::milliseconds _flush_interval_ms;
}; };
#ifdef SPDLOG_NO_REGISTRY_MUTEX #ifdef SPDLOG_NO_REGISTRY_MUTEX
typedef registry_t<spdlog::details::null_mutex> registry; typedef registry_t<spdlog::details::null_mutex> registry;
#else #else
typedef registry_t<std::mutex> registry; typedef registry_t<std::mutex> registry;
#endif #endif
} }
} }

View File

@ -1,149 +1,149 @@
// //
// Copyright(c) 2015 Gabi Melman. // Copyright(c) 2015 Gabi Melman.
// Distributed under the MIT License (http://opensource.org/licenses/MIT) // Distributed under the MIT License (http://opensource.org/licenses/MIT)
// //
#pragma once #pragma once
// //
// Global registry functions // Global registry functions
// //
#include <spdlog/spdlog.h> #include <spdlog/spdlog.h>
#include <spdlog/details/registry.h> #include <spdlog/details/registry.h>
#include <spdlog/sinks/file_sinks.h> #include <spdlog/sinks/file_sinks.h>
#include <spdlog/sinks/stdout_sinks.h> #include <spdlog/sinks/stdout_sinks.h>
#include <spdlog/sinks/syslog_sink.h> #include <spdlog/sinks/syslog_sink.h>
#include <spdlog/sinks/ansicolor_sink.h> #include <spdlog/sinks/ansicolor_sink.h>
#include <chrono> #include <chrono>
#include <functional> #include <functional>
#include <memory> #include <memory>
#include <string> #include <string>
inline void spdlog::register_logger(std::shared_ptr<logger> logger) inline void spdlog::register_logger(std::shared_ptr<logger> logger)
{ {
return details::registry::instance().register_logger(logger); return details::registry::instance().register_logger(logger);
} }
inline std::shared_ptr<spdlog::logger> spdlog::get(const std::string& name) inline std::shared_ptr<spdlog::logger> spdlog::get(const std::string& name)
{ {
return details::registry::instance().get(name); return details::registry::instance().get(name);
} }
inline void spdlog::drop(const std::string &name) inline void spdlog::drop(const std::string &name)
{ {
details::registry::instance().drop(name); details::registry::instance().drop(name);
} }
// Create multi/single threaded rotating file logger // Create multi/single threaded rotating file logger
inline std::shared_ptr<spdlog::logger> spdlog::rotating_logger_mt(const std::string& logger_name, const filename_t& filename, size_t max_file_size, size_t max_files, bool force_flush) inline std::shared_ptr<spdlog::logger> spdlog::rotating_logger_mt(const std::string& logger_name, const filename_t& filename, size_t max_file_size, size_t max_files, bool force_flush)
{ {
return create<spdlog::sinks::rotating_file_sink_mt>(logger_name, filename, SPDLOG_FILENAME_T("txt"), max_file_size, max_files, force_flush); return create<spdlog::sinks::rotating_file_sink_mt>(logger_name, filename, SPDLOG_FILENAME_T("txt"), max_file_size, max_files, force_flush);
} }
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, bool force_flush) 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, bool force_flush)
{ {
return create<spdlog::sinks::rotating_file_sink_st>(logger_name, filename, SPDLOG_FILENAME_T("txt"), max_file_size, max_files, force_flush); return create<spdlog::sinks::rotating_file_sink_st>(logger_name, filename, SPDLOG_FILENAME_T("txt"), max_file_size, max_files, force_flush);
} }
// Create file logger which creates new file at midnight): // Create file logger which creates new file at midnight):
inline std::shared_ptr<spdlog::logger> spdlog::daily_logger_mt(const std::string& logger_name, const filename_t& filename, int hour, int minute, bool force_flush) inline std::shared_ptr<spdlog::logger> spdlog::daily_logger_mt(const std::string& logger_name, const filename_t& filename, int hour, int minute, bool force_flush)
{ {
return create<spdlog::sinks::daily_file_sink_mt>(logger_name, filename, SPDLOG_FILENAME_T("txt"), hour, minute, force_flush); return create<spdlog::sinks::daily_file_sink_mt>(logger_name, filename, SPDLOG_FILENAME_T("txt"), hour, minute, force_flush);
} }
inline std::shared_ptr<spdlog::logger> spdlog::daily_logger_st(const std::string& logger_name, const filename_t& filename, int hour, int minute, bool force_flush) inline std::shared_ptr<spdlog::logger> spdlog::daily_logger_st(const std::string& logger_name, const filename_t& filename, int hour, int minute, bool force_flush)
{ {
return create<spdlog::sinks::daily_file_sink_st>(logger_name, filename, SPDLOG_FILENAME_T("txt"), hour, minute, force_flush); return create<spdlog::sinks::daily_file_sink_st>(logger_name, filename, SPDLOG_FILENAME_T("txt"), hour, minute, force_flush);
} }
// Create stdout/stderr loggers (with optinal color support) // Create stdout/stderr loggers (with optinal color support)
inline std::shared_ptr<spdlog::logger> create_console_logger(const std::string& logger_name, spdlog::sink_ptr sink, bool color) inline std::shared_ptr<spdlog::logger> create_console_logger(const std::string& logger_name, spdlog::sink_ptr sink, bool color)
{ {
if (color) //use color wrapper sink if (color) //use color wrapper sink
sink = std::make_shared<spdlog::sinks::ansicolor_sink>(sink); sink = std::make_shared<spdlog::sinks::ansicolor_sink>(sink);
return spdlog::details::registry::instance().create(logger_name, sink); return spdlog::details::registry::instance().create(logger_name, sink);
} }
inline std::shared_ptr<spdlog::logger> spdlog::stdout_logger_mt(const std::string& logger_name, bool color) inline std::shared_ptr<spdlog::logger> spdlog::stdout_logger_mt(const std::string& logger_name, bool color)
{ {
return create_console_logger(logger_name, sinks::stdout_sink_mt::instance(), color); return create_console_logger(logger_name, sinks::stdout_sink_mt::instance(), color);
} }
inline std::shared_ptr<spdlog::logger> spdlog::stdout_logger_st(const std::string& logger_name, bool color) inline std::shared_ptr<spdlog::logger> spdlog::stdout_logger_st(const std::string& logger_name, bool color)
{ {
return create_console_logger(logger_name, sinks::stdout_sink_st::instance(), color); return create_console_logger(logger_name, sinks::stdout_sink_st::instance(), color);
} }
inline std::shared_ptr<spdlog::logger> spdlog::stderr_logger_mt(const std::string& logger_name, bool color) inline std::shared_ptr<spdlog::logger> spdlog::stderr_logger_mt(const std::string& logger_name, bool color)
{ {
return create_console_logger(logger_name, sinks::stderr_sink_mt::instance(), color); return create_console_logger(logger_name, sinks::stderr_sink_mt::instance(), color);
} }
inline std::shared_ptr<spdlog::logger> spdlog::stderr_logger_st(const std::string& logger_name, bool color) inline std::shared_ptr<spdlog::logger> spdlog::stderr_logger_st(const std::string& logger_name, bool color)
{ {
return create_console_logger(logger_name, sinks::stderr_sink_st::instance(), color); return create_console_logger(logger_name, sinks::stderr_sink_st::instance(), color);
} }
#if defined(__linux__) || defined(__APPLE__) #if defined(__linux__) || defined(__APPLE__)
// Create syslog logger // Create syslog logger
inline std::shared_ptr<spdlog::logger> spdlog::syslog_logger(const std::string& logger_name, const std::string& syslog_ident, int syslog_option) inline std::shared_ptr<spdlog::logger> spdlog::syslog_logger(const std::string& logger_name, const std::string& syslog_ident, int syslog_option)
{ {
return create<spdlog::sinks::syslog_sink>(logger_name, syslog_ident, syslog_option); return create<spdlog::sinks::syslog_sink>(logger_name, syslog_ident, syslog_option);
} }
#endif #endif
//Create logger with multiple sinks //Create logger with multiple sinks
inline std::shared_ptr<spdlog::logger> spdlog::create(const std::string& logger_name, spdlog::sinks_init_list sinks) inline std::shared_ptr<spdlog::logger> spdlog::create(const std::string& logger_name, spdlog::sinks_init_list sinks)
{ {
return details::registry::instance().create(logger_name, sinks); return details::registry::instance().create(logger_name, sinks);
} }
template <typename Sink, typename... Args> template <typename Sink, typename... Args>
inline std::shared_ptr<spdlog::logger> spdlog::create(const std::string& logger_name, Args... args) inline std::shared_ptr<spdlog::logger> spdlog::create(const std::string& logger_name, Args... args)
{ {
sink_ptr sink = std::make_shared<Sink>(args...); sink_ptr sink = std::make_shared<Sink>(args...);
return details::registry::instance().create(logger_name, { sink }); return details::registry::instance().create(logger_name, { sink });
} }
template<class It> template<class It>
inline std::shared_ptr<spdlog::logger> spdlog::create(const std::string& logger_name, const It& sinks_begin, const It& sinks_end) inline std::shared_ptr<spdlog::logger> spdlog::create(const std::string& logger_name, const It& sinks_begin, const It& sinks_end)
{ {
return details::registry::instance().create(logger_name, sinks_begin, sinks_end); return details::registry::instance().create(logger_name, sinks_begin, sinks_end);
} }
inline void spdlog::set_formatter(spdlog::formatter_ptr f) inline void spdlog::set_formatter(spdlog::formatter_ptr f)
{ {
details::registry::instance().formatter(f); details::registry::instance().formatter(f);
} }
inline void spdlog::set_pattern(const std::string& format_string) inline void spdlog::set_pattern(const std::string& format_string)
{ {
return details::registry::instance().set_pattern(format_string); return details::registry::instance().set_pattern(format_string);
} }
inline void spdlog::set_level(level::level_enum log_level) inline void spdlog::set_level(level::level_enum log_level)
{ {
return details::registry::instance().set_level(log_level); return details::registry::instance().set_level(log_level);
} }
inline void spdlog::set_async_mode(size_t queue_size, const async_overflow_policy overflow_policy, const std::function<void()>& worker_warmup_cb, const std::chrono::milliseconds& flush_interval_ms) inline void spdlog::set_async_mode(size_t queue_size, const async_overflow_policy overflow_policy, const std::function<void()>& worker_warmup_cb, const std::chrono::milliseconds& flush_interval_ms)
{ {
details::registry::instance().set_async_mode(queue_size, overflow_policy, worker_warmup_cb, flush_interval_ms); details::registry::instance().set_async_mode(queue_size, overflow_policy, worker_warmup_cb, flush_interval_ms);
} }
inline void spdlog::set_sync_mode() inline void spdlog::set_sync_mode()
{ {
details::registry::instance().set_sync_mode(); details::registry::instance().set_sync_mode();
} }
inline void spdlog::drop_all() inline void spdlog::drop_all()
{ {
details::registry::instance().drop_all(); details::registry::instance().drop_all();
} }

View File

@ -1,45 +1,45 @@
// //
// Copyright(c) 2015 Gabi Melman. // Copyright(c) 2015 Gabi Melman.
// Distributed under the MIT License (http://opensource.org/licenses/MIT) // Distributed under the MIT License (http://opensource.org/licenses/MIT)
// //
#pragma once #pragma once
#include <spdlog/details/log_msg.h> #include <spdlog/details/log_msg.h>
#include <vector> #include <vector>
#include <string> #include <string>
#include <memory> #include <memory>
namespace spdlog namespace spdlog
{ {
namespace details namespace details
{ {
class flag_formatter; class flag_formatter;
} }
class formatter class formatter
{ {
public: public:
virtual ~formatter() {} virtual ~formatter() {}
virtual void format(details::log_msg& msg) = 0; virtual void format(details::log_msg& msg) = 0;
}; };
class pattern_formatter : public formatter class pattern_formatter : public formatter
{ {
public: public:
explicit pattern_formatter(const std::string& pattern); explicit pattern_formatter(const std::string& pattern);
pattern_formatter(const pattern_formatter&) = delete; pattern_formatter(const pattern_formatter&) = delete;
pattern_formatter& operator=(const pattern_formatter&) = delete; pattern_formatter& operator=(const pattern_formatter&) = delete;
void format(details::log_msg& msg) override; void format(details::log_msg& msg) override;
private: private:
const std::string _pattern; const std::string _pattern;
std::vector<std::unique_ptr<details::flag_formatter>> _formatters; std::vector<std::unique_ptr<details::flag_formatter>> _formatters;
void handle_flag(char flag); void handle_flag(char flag);
void compile_pattern(const std::string& pattern); void compile_pattern(const std::string& pattern);
}; };
} }
#include <spdlog/details/pattern_formatter_impl.h> #include <spdlog/details/pattern_formatter_impl.h>

View File

@ -1,112 +1,112 @@
// //
// Copyright(c) 2015 Gabi Melman. // Copyright(c) 2015 Gabi Melman.
// Distributed under the MIT License (http://opensource.org/licenses/MIT) // Distributed under the MIT License (http://opensource.org/licenses/MIT)
// //
#pragma once #pragma once
// Thread safe logger // Thread safe logger
// Has name, log level, vector of std::shared sink pointers and formatter // Has name, log level, vector of std::shared sink pointers and formatter
// Upon each log write the logger: // Upon each log write the logger:
// 1. Checks if its log level is enough to log the message // 1. Checks if its log level is enough to log the message
// 2. Format the message using the formatter function // 2. Format the message using the formatter function
// 3. Pass the formatted message to its sinks to performa the actual logging // 3. Pass the formatted message to its sinks to performa the actual logging
#include <spdlog/sinks/base_sink.h> #include <spdlog/sinks/base_sink.h>
#include <spdlog/common.h> #include <spdlog/common.h>
#include <spdlog/details/line_logger_fwd.h> #include <spdlog/details/line_logger_fwd.h>
#include <vector> #include <vector>
#include <memory> #include <memory>
#include <string> #include <string>
namespace spdlog namespace spdlog
{ {
class logger class logger
{ {
public: public:
logger(const std::string& logger_name, sink_ptr single_sink); logger(const std::string& logger_name, sink_ptr single_sink);
logger(const std::string& name, sinks_init_list); logger(const std::string& name, sinks_init_list);
template<class It> template<class It>
logger(const std::string& name, const It& begin, const It& end); logger(const std::string& name, const It& begin, const It& end);
virtual ~logger(); virtual ~logger();
logger(const logger&) = delete; logger(const logger&) = delete;
logger& operator=(const logger&) = delete; logger& operator=(const logger&) = delete;
void set_level(level::level_enum); void set_level(level::level_enum);
level::level_enum level() const; level::level_enum level() const;
const std::string& name() const; const std::string& name() const;
bool should_log(level::level_enum) const; bool should_log(level::level_enum) const;
// logger.info(cppformat_string, arg1, arg2, arg3, ...) call style // logger.info(cppformat_string, arg1, arg2, arg3, ...) call style
template <typename... Args> details::line_logger trace(const char* fmt, const Args&... args); template <typename... Args> details::line_logger trace(const char* fmt, const Args&... args);
template <typename... Args> details::line_logger debug(const char* fmt, const Args&... args); template <typename... Args> details::line_logger debug(const char* fmt, const Args&... args);
template <typename... Args> details::line_logger info(const char* fmt, const Args&... args); template <typename... Args> details::line_logger info(const char* fmt, const Args&... args);
template <typename... Args> details::line_logger notice(const char* fmt, const Args&... args); template <typename... Args> details::line_logger notice(const char* fmt, const Args&... args);
template <typename... Args> details::line_logger warn(const char* fmt, const Args&... args); template <typename... Args> details::line_logger warn(const char* fmt, const Args&... args);
template <typename... Args> details::line_logger error(const char* fmt, const Args&... args); template <typename... Args> details::line_logger error(const char* fmt, const Args&... args);
template <typename... Args> details::line_logger critical(const char* fmt, const Args&... args); template <typename... Args> details::line_logger critical(const char* fmt, const Args&... args);
template <typename... Args> details::line_logger alert(const char* fmt, const Args&... args); template <typename... Args> details::line_logger alert(const char* fmt, const Args&... args);
template <typename... Args> details::line_logger emerg(const char* fmt, const Args&... args); template <typename... Args> details::line_logger emerg(const char* fmt, const Args&... args);
// logger.info(msg) << ".." call style // logger.info(msg) << ".." call style
template <typename T> details::line_logger trace(const T&); template <typename T> details::line_logger trace(const T&);
template <typename T> details::line_logger debug(const T&); template <typename T> details::line_logger debug(const T&);
template <typename T> details::line_logger info(const T&); template <typename T> details::line_logger info(const T&);
template <typename T> details::line_logger notice(const T&); template <typename T> details::line_logger notice(const T&);
template <typename T> details::line_logger warn(const T&); template <typename T> details::line_logger warn(const T&);
template <typename T> details::line_logger error(const T&); template <typename T> details::line_logger error(const T&);
template <typename T> details::line_logger critical(const T&); template <typename T> details::line_logger critical(const T&);
template <typename T> details::line_logger alert(const T&); template <typename T> details::line_logger alert(const T&);
template <typename T> details::line_logger emerg(const T&); template <typename T> details::line_logger emerg(const T&);
// logger.info() << ".." call style // logger.info() << ".." call style
details::line_logger trace(); details::line_logger trace();
details::line_logger debug(); details::line_logger debug();
details::line_logger info(); details::line_logger info();
details::line_logger notice(); details::line_logger notice();
details::line_logger warn(); details::line_logger warn();
details::line_logger error(); details::line_logger error();
details::line_logger critical(); details::line_logger critical();
details::line_logger alert(); details::line_logger alert();
details::line_logger emerg(); details::line_logger emerg();
// Create log message with the given level, no matter what is the actual logger's level // Create log message with the given level, no matter what is the actual logger's level
template <typename... Args> template <typename... Args>
details::line_logger force_log(level::level_enum lvl, const char* fmt, const Args&... args); details::line_logger force_log(level::level_enum lvl, const char* fmt, const Args&... args);
// Set the format of the log messages from this logger // Set the format of the log messages from this logger
void set_pattern(const std::string&); void set_pattern(const std::string&);
void set_formatter(formatter_ptr); void set_formatter(formatter_ptr);
virtual void flush(); virtual void flush();
protected: protected:
virtual void _log_msg(details::log_msg&); virtual void _log_msg(details::log_msg&);
virtual void _set_pattern(const std::string&); virtual void _set_pattern(const std::string&);
virtual void _set_formatter(formatter_ptr); virtual void _set_formatter(formatter_ptr);
details::line_logger _log_if_enabled(level::level_enum lvl); details::line_logger _log_if_enabled(level::level_enum lvl);
template <typename... Args> template <typename... Args>
details::line_logger _log_if_enabled(level::level_enum lvl, const char* fmt, const Args&... args); details::line_logger _log_if_enabled(level::level_enum lvl, const char* fmt, const Args&... args);
template<typename T> template<typename T>
inline details::line_logger _log_if_enabled(level::level_enum lvl, const T& msg); inline details::line_logger _log_if_enabled(level::level_enum lvl, const T& msg);
friend details::line_logger; friend details::line_logger;
std::string _name; std::string _name;
std::vector<sink_ptr> _sinks; std::vector<sink_ptr> _sinks;
formatter_ptr _formatter; formatter_ptr _formatter;
spdlog::level_t _level; spdlog::level_t _level;
}; };
} }
#include <spdlog/details/logger_impl.h> #include <spdlog/details/logger_impl.h>
#include <spdlog/details/line_logger_impl.h> #include <spdlog/details/line_logger_impl.h>

View File

@ -1,92 +1,92 @@
// //
// Copyright(c) 2015 Gabi Melman. // Copyright(c) 2015 Gabi Melman.
// Distributed under the MIT License (http://opensource.org/licenses/MIT) // Distributed under the MIT License (http://opensource.org/licenses/MIT)
// //
#pragma once #pragma once
#if defined(__ANDROID__) #if defined(__ANDROID__)
#include <spdlog/sinks/base_sink.h> #include <spdlog/sinks/base_sink.h>
#include <spdlog/details/null_mutex.h> #include <spdlog/details/null_mutex.h>
#include <android/log.h> #include <android/log.h>
#include <mutex> #include <mutex>
#include <string> #include <string>
namespace spdlog namespace spdlog
{ {
namespace sinks namespace sinks
{ {
/* /*
* Android sink (logging using __android_log_write) * Android sink (logging using __android_log_write)
*/ */
template<class Mutex> template<class Mutex>
class base_android_sink : public base_sink < Mutex > class base_android_sink : public base_sink < Mutex >
{ {
public: public:
explicit base_android_sink(std::string tag="spdlog"): _tag(tag) explicit base_android_sink(std::string tag="spdlog"): _tag(tag)
{ {
} }
void flush() override void flush() override
{ {
} }
protected: protected:
void _sink_it(const details::log_msg& msg) override void _sink_it(const details::log_msg& msg) override
{ {
const android_LogPriority priority = convert_to_android(msg.level); const android_LogPriority priority = convert_to_android(msg.level);
const int expected_size = msg.formatted.size(); const int expected_size = msg.formatted.size();
const int size = __android_log_write( const int size = __android_log_write(
priority, _tag.c_str(), msg.formatted.c_str() priority, _tag.c_str(), msg.formatted.c_str()
); );
if (size > expected_size) if (size > expected_size)
{ {
// Will write a little bit more than original message // Will write a little bit more than original message
} }
else else
{ {
throw spdlog_ex("Send to Android logcat failed"); throw spdlog_ex("Send to Android logcat failed");
} }
} }
private: private:
static android_LogPriority convert_to_android(spdlog::level::level_enum level) static android_LogPriority convert_to_android(spdlog::level::level_enum level)
{ {
switch(level) switch(level)
{ {
case spdlog::level::trace: case spdlog::level::trace:
return ANDROID_LOG_VERBOSE; return ANDROID_LOG_VERBOSE;
case spdlog::level::debug: case spdlog::level::debug:
return ANDROID_LOG_DEBUG; return ANDROID_LOG_DEBUG;
case spdlog::level::info: case spdlog::level::info:
return ANDROID_LOG_INFO; return ANDROID_LOG_INFO;
case spdlog::level::notice: case spdlog::level::notice:
return ANDROID_LOG_INFO; return ANDROID_LOG_INFO;
case spdlog::level::warn: case spdlog::level::warn:
return ANDROID_LOG_WARN; return ANDROID_LOG_WARN;
case spdlog::level::err: case spdlog::level::err:
return ANDROID_LOG_ERROR; return ANDROID_LOG_ERROR;
case spdlog::level::critical: case spdlog::level::critical:
return ANDROID_LOG_FATAL; return ANDROID_LOG_FATAL;
case spdlog::level::alert: case spdlog::level::alert:
return ANDROID_LOG_FATAL; return ANDROID_LOG_FATAL;
case spdlog::level::emerg: case spdlog::level::emerg:
return ANDROID_LOG_FATAL; return ANDROID_LOG_FATAL;
default: default:
throw spdlog_ex("Incorrect level value"); throw spdlog_ex("Incorrect level value");
} }
} }
std::string _tag; std::string _tag;
}; };
typedef base_android_sink<std::mutex> android_sink_mt; typedef base_android_sink<std::mutex> android_sink_mt;
typedef base_android_sink<details::null_mutex> android_sink_st; typedef base_android_sink<details::null_mutex> android_sink_st;
} }
} }
#endif #endif

View File

@ -1,115 +1,115 @@
// //
// Copyright(c) 2016 Kevin M. Godby (a modified version by spdlog). // Copyright(c) 2016 Kevin M. Godby (a modified version by spdlog).
// Distributed under the MIT License (http://opensource.org/licenses/MIT) // Distributed under the MIT License (http://opensource.org/licenses/MIT)
// //
#pragma once #pragma once
#include <spdlog/sinks/base_sink.h> #include <spdlog/sinks/base_sink.h>
#include <spdlog/common.h> #include <spdlog/common.h>
#include <string> #include <string>
#include <map> #include <map>
namespace spdlog namespace spdlog
{ {
namespace sinks namespace sinks
{ {
/** /**
* @brief The ansi_color_sink is a decorator around another sink and prefixes * @brief The ansi_color_sink is a decorator around another sink and prefixes
* the output with an ANSI escape sequence color code depending on the severity * the output with an ANSI escape sequence color code depending on the severity
* of the message. * of the message.
*/ */
class ansicolor_sink : public sink class ansicolor_sink : public sink
{ {
public: public:
ansicolor_sink(sink_ptr wrapped_sink); ansicolor_sink(sink_ptr wrapped_sink);
virtual ~ansicolor_sink(); virtual ~ansicolor_sink();
ansicolor_sink(const ansicolor_sink& other) = delete; ansicolor_sink(const ansicolor_sink& other) = delete;
ansicolor_sink& operator=(const ansicolor_sink& other) = delete; ansicolor_sink& operator=(const ansicolor_sink& other) = delete;
virtual void log(const details::log_msg& msg) override; virtual void log(const details::log_msg& msg) override;
virtual void flush() override; virtual void flush() override;
void set_color(level::level_enum level, const std::string& color); void set_color(level::level_enum level, const std::string& color);
/// Formatting codes /// Formatting codes
const std::string reset = "\033[00m"; const std::string reset = "\033[00m";
const std::string bold = "\033[1m"; const std::string bold = "\033[1m";
const std::string dark = "\033[2m"; const std::string dark = "\033[2m";
const std::string underline = "\033[4m"; const std::string underline = "\033[4m";
const std::string blink = "\033[5m"; const std::string blink = "\033[5m";
const std::string reverse = "\033[7m"; const std::string reverse = "\033[7m";
const std::string concealed = "\033[8m"; const std::string concealed = "\033[8m";
// Foreground colors // Foreground colors
const std::string grey = "\033[30m"; const std::string grey = "\033[30m";
const std::string red = "\033[31m"; const std::string red = "\033[31m";
const std::string green = "\033[32m"; const std::string green = "\033[32m";
const std::string yellow = "\033[33m"; const std::string yellow = "\033[33m";
const std::string blue = "\033[34m"; const std::string blue = "\033[34m";
const std::string magenta = "\033[35m"; const std::string magenta = "\033[35m";
const std::string cyan = "\033[36m"; const std::string cyan = "\033[36m";
const std::string white = "\033[37m"; const std::string white = "\033[37m";
/// Background colors /// Background colors
const std::string on_grey = "\033[40m"; const std::string on_grey = "\033[40m";
const std::string on_red = "\033[41m"; const std::string on_red = "\033[41m";
const std::string on_green = "\033[42m"; const std::string on_green = "\033[42m";
const std::string on_yellow = "\033[43m"; const std::string on_yellow = "\033[43m";
const std::string on_blue = "\033[44m"; const std::string on_blue = "\033[44m";
const std::string on_magenta = "\033[45m"; const std::string on_magenta = "\033[45m";
const std::string on_cyan = "\033[46m"; const std::string on_cyan = "\033[46m";
const std::string on_white = "\033[47m"; const std::string on_white = "\033[47m";
protected: protected:
sink_ptr sink_; sink_ptr sink_;
std::map<level::level_enum, std::string> colors_; std::map<level::level_enum, std::string> colors_;
}; };
inline ansicolor_sink::ansicolor_sink(sink_ptr wrapped_sink) : sink_(wrapped_sink) inline ansicolor_sink::ansicolor_sink(sink_ptr wrapped_sink) : sink_(wrapped_sink)
{ {
colors_[level::trace] = cyan; colors_[level::trace] = cyan;
colors_[level::debug] = cyan; colors_[level::debug] = cyan;
colors_[level::info] = white; colors_[level::info] = white;
colors_[level::notice] = bold + white; colors_[level::notice] = bold + white;
colors_[level::warn] = bold + yellow; colors_[level::warn] = bold + yellow;
colors_[level::err] = red; colors_[level::err] = red;
colors_[level::critical] = bold + red; colors_[level::critical] = bold + red;
colors_[level::alert] = bold + white + on_red; colors_[level::alert] = bold + white + on_red;
colors_[level::emerg] = bold + yellow + on_red; colors_[level::emerg] = bold + yellow + on_red;
colors_[level::off] = reset; colors_[level::off] = reset;
} }
inline void ansicolor_sink::log(const details::log_msg& msg) inline void ansicolor_sink::log(const details::log_msg& msg)
{ {
// Wrap the originally formatted message in color codes // Wrap the originally formatted message in color codes
const std::string& prefix = colors_[msg.level]; const std::string& prefix = colors_[msg.level];
const std::string& s = msg.formatted.str(); const std::string& s = msg.formatted.str();
const std::string& suffix = reset; const std::string& suffix = reset;
details::log_msg m; details::log_msg m;
m.formatted << prefix << s << suffix; m.formatted << prefix << s << suffix;
sink_->log(m); sink_->log(m);
} }
inline void ansicolor_sink::flush() inline void ansicolor_sink::flush()
{ {
sink_->flush(); sink_->flush();
} }
inline void ansicolor_sink::set_color(level::level_enum level, const std::string& color) inline void ansicolor_sink::set_color(level::level_enum level, const std::string& color)
{ {
colors_[level] = color; colors_[level] = color;
} }
inline ansicolor_sink::~ansicolor_sink() inline ansicolor_sink::~ansicolor_sink()
{ {
flush(); flush();
} }
} // namespace sinks } // namespace sinks
} // namespace spdlog } // namespace spdlog

View File

@ -1,45 +1,45 @@
// //
// Copyright(c) 2015 Gabi Melman. // Copyright(c) 2015 Gabi Melman.
// Distributed under the MIT License (http://opensource.org/licenses/MIT) // Distributed under the MIT License (http://opensource.org/licenses/MIT)
// //
#pragma once #pragma once
// //
// base sink templated over a mutex (either dummy or realy) // base sink templated over a mutex (either dummy or realy)
// concrete implementation should only overrid the _sink_it method. // concrete implementation should only overrid the _sink_it method.
// all locking is taken care of here so no locking needed by the implementors.. // all locking is taken care of here so no locking needed by the implementors..
// //
#include <spdlog/sinks/sink.h> #include <spdlog/sinks/sink.h>
#include <spdlog/formatter.h> #include <spdlog/formatter.h>
#include <spdlog/common.h> #include <spdlog/common.h>
#include <spdlog/details/log_msg.h> #include <spdlog/details/log_msg.h>
#include <mutex> #include <mutex>
namespace spdlog namespace spdlog
{ {
namespace sinks namespace sinks
{ {
template<class Mutex> template<class Mutex>
class base_sink:public sink class base_sink:public sink
{ {
public: public:
base_sink():_mutex() {} base_sink():_mutex() {}
virtual ~base_sink() = default; virtual ~base_sink() = default;
base_sink(const base_sink&) = delete; base_sink(const base_sink&) = delete;
base_sink& operator=(const base_sink&) = delete; base_sink& operator=(const base_sink&) = delete;
void log(const details::log_msg& msg) override void log(const details::log_msg& msg) override
{ {
std::lock_guard<Mutex> lock(_mutex); std::lock_guard<Mutex> lock(_mutex);
_sink_it(msg); _sink_it(msg);
} }
protected: protected:
virtual void _sink_it(const details::log_msg& msg) = 0; virtual void _sink_it(const details::log_msg& msg) = 0;
Mutex _mutex; Mutex _mutex;
}; };
} }
} }

View File

@ -1,72 +1,72 @@
// //
// Copyright (c) 2015 David Schury, Gabi Melman // Copyright (c) 2015 David Schury, Gabi Melman
// Distributed under the MIT License (http://opensource.org/licenses/MIT) // Distributed under the MIT License (http://opensource.org/licenses/MIT)
// //
#pragma once #pragma once
#include <spdlog/details/log_msg.h> #include <spdlog/details/log_msg.h>
#include <spdlog/details/null_mutex.h> #include <spdlog/details/null_mutex.h>
#include <spdlog/sinks/base_sink.h> #include <spdlog/sinks/base_sink.h>
#include <spdlog/sinks/sink.h> #include <spdlog/sinks/sink.h>
#include <algorithm> #include <algorithm>
#include <memory> #include <memory>
#include <mutex> #include <mutex>
#include <vector> #include <vector>
namespace spdlog namespace spdlog
{ {
namespace sinks namespace sinks
{ {
template<class Mutex> template<class Mutex>
class dist_sink: public base_sink<Mutex> class dist_sink: public base_sink<Mutex>
{ {
public: public:
explicit dist_sink() :_sinks() {} explicit dist_sink() :_sinks() {}
dist_sink(const dist_sink&) = delete; dist_sink(const dist_sink&) = delete;
dist_sink& operator=(const dist_sink&) = delete; dist_sink& operator=(const dist_sink&) = delete;
virtual ~dist_sink() = default; virtual ~dist_sink() = default;
protected: protected:
void _sink_it(const details::log_msg& msg) override void _sink_it(const details::log_msg& msg) override
{ {
for (auto iter = _sinks.begin(); iter != _sinks.end(); iter++) for (auto iter = _sinks.begin(); iter != _sinks.end(); iter++)
(*iter)->log(msg); (*iter)->log(msg);
} }
std::vector<std::shared_ptr<sink>> _sinks; std::vector<std::shared_ptr<sink>> _sinks;
public: public:
void flush() override void flush() override
{ {
std::lock_guard<Mutex> lock(base_sink<Mutex>::_mutex); std::lock_guard<Mutex> lock(base_sink<Mutex>::_mutex);
for (auto iter = _sinks.begin(); iter != _sinks.end(); iter++) for (auto iter = _sinks.begin(); iter != _sinks.end(); iter++)
(*iter)->flush(); (*iter)->flush();
} }
void add_sink(std::shared_ptr<sink> sink) void add_sink(std::shared_ptr<sink> sink)
{ {
std::lock_guard<Mutex> lock(base_sink<Mutex>::_mutex); std::lock_guard<Mutex> lock(base_sink<Mutex>::_mutex);
if (sink && if (sink &&
_sinks.end() == std::find(_sinks.begin(), _sinks.end(), sink)) _sinks.end() == std::find(_sinks.begin(), _sinks.end(), sink))
{ {
_sinks.push_back(sink); _sinks.push_back(sink);
} }
} }
void remove_sink(std::shared_ptr<sink> sink) void remove_sink(std::shared_ptr<sink> sink)
{ {
std::lock_guard<Mutex> lock(base_sink<Mutex>::_mutex); std::lock_guard<Mutex> lock(base_sink<Mutex>::_mutex);
auto pos = std::find(_sinks.begin(), _sinks.end(), sink); auto pos = std::find(_sinks.begin(), _sinks.end(), sink);
if (pos != _sinks.end()) if (pos != _sinks.end())
{ {
_sinks.erase(pos); _sinks.erase(pos);
} }
} }
}; };
typedef dist_sink<std::mutex> dist_sink_mt; typedef dist_sink<std::mutex> dist_sink_mt;
typedef dist_sink<details::null_mutex> dist_sink_st; typedef dist_sink<details::null_mutex> dist_sink_st;
} }
} }

View File

@ -1,220 +1,220 @@
// //
// Copyright(c) 2015 Gabi Melman. // Copyright(c) 2015 Gabi Melman.
// Distributed under the MIT License (http://opensource.org/licenses/MIT) // Distributed under the MIT License (http://opensource.org/licenses/MIT)
// //
#pragma once #pragma once
#include <spdlog/sinks/base_sink.h> #include <spdlog/sinks/base_sink.h>
#include <spdlog/details/null_mutex.h> #include <spdlog/details/null_mutex.h>
#include <spdlog/details/file_helper.h> #include <spdlog/details/file_helper.h>
#include <spdlog/details/format.h> #include <spdlog/details/format.h>
#include <algorithm> #include <algorithm>
#include <chrono> #include <chrono>
#include <cstdio> #include <cstdio>
#include <ctime> #include <ctime>
#include <mutex> #include <mutex>
#include <string> #include <string>
namespace spdlog namespace spdlog
{ {
namespace sinks namespace sinks
{ {
/* /*
* Trivial file sink with single file as target * Trivial file sink with single file as target
*/ */
template<class Mutex> template<class Mutex>
class simple_file_sink : public base_sink < Mutex > class simple_file_sink : public base_sink < Mutex >
{ {
public: public:
explicit simple_file_sink(const filename_t &filename, explicit simple_file_sink(const filename_t &filename,
bool force_flush = false) : bool force_flush = false) :
_file_helper(force_flush) _file_helper(force_flush)
{ {
_file_helper.open(filename); _file_helper.open(filename);
} }
void flush() override void flush() override
{ {
_file_helper.flush(); _file_helper.flush();
} }
protected: protected:
void _sink_it(const details::log_msg& msg) override void _sink_it(const details::log_msg& msg) override
{ {
_file_helper.write(msg); _file_helper.write(msg);
} }
private: private:
details::file_helper _file_helper; details::file_helper _file_helper;
}; };
typedef simple_file_sink<std::mutex> simple_file_sink_mt; typedef simple_file_sink<std::mutex> simple_file_sink_mt;
typedef simple_file_sink<details::null_mutex> simple_file_sink_st; typedef simple_file_sink<details::null_mutex> simple_file_sink_st;
/* /*
* Rotating file sink based on size * Rotating file sink based on size
*/ */
template<class Mutex> template<class Mutex>
class rotating_file_sink : public base_sink < Mutex > class rotating_file_sink : public base_sink < Mutex >
{ {
public: public:
rotating_file_sink(const filename_t &base_filename, const filename_t &extension, rotating_file_sink(const filename_t &base_filename, const filename_t &extension,
std::size_t max_size, std::size_t max_files, std::size_t max_size, std::size_t max_files,
bool force_flush = false) : bool force_flush = false) :
_base_filename(base_filename), _base_filename(base_filename),
_extension(extension), _extension(extension),
_max_size(max_size), _max_size(max_size),
_max_files(max_files), _max_files(max_files),
_current_size(0), _current_size(0),
_file_helper(force_flush) _file_helper(force_flush)
{ {
_file_helper.open(calc_filename(_base_filename, 0, _extension)); _file_helper.open(calc_filename(_base_filename, 0, _extension));
_current_size = _file_helper.size(); //expensive. called only once _current_size = _file_helper.size(); //expensive. called only once
} }
void flush() override void flush() override
{ {
_file_helper.flush(); _file_helper.flush();
} }
protected: protected:
void _sink_it(const details::log_msg& msg) override void _sink_it(const details::log_msg& msg) override
{ {
_current_size += msg.formatted.size(); _current_size += msg.formatted.size();
if (_current_size > _max_size) if (_current_size > _max_size)
{ {
_rotate(); _rotate();
_current_size = msg.formatted.size(); _current_size = msg.formatted.size();
} }
_file_helper.write(msg); _file_helper.write(msg);
} }
private: private:
static filename_t calc_filename(const filename_t& filename, std::size_t index, const filename_t& extension) static filename_t calc_filename(const filename_t& filename, std::size_t index, const filename_t& extension)
{ {
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;
if (index) if (index)
w.write(SPDLOG_FILENAME_T("{}.{}.{}"), filename, index, extension); w.write(SPDLOG_FILENAME_T("{}.{}.{}"), filename, index, extension);
else else
w.write(SPDLOG_FILENAME_T("{}.{}"), filename, extension); w.write(SPDLOG_FILENAME_T("{}.{}"), filename, extension);
return w.str(); return w.str();
} }
// Rotate files: // Rotate files:
// log.txt -> log.1.txt // log.txt -> log.1.txt
// log.1.txt -> log2.txt // log.1.txt -> log2.txt
// log.2.txt -> log3.txt // log.2.txt -> log3.txt
// log.3.txt -> delete // log.3.txt -> delete
void _rotate() void _rotate()
{ {
_file_helper.close(); _file_helper.close();
for (auto i = _max_files; i > 0; --i) for (auto i = _max_files; i > 0; --i)
{ {
filename_t src = calc_filename(_base_filename, i - 1, _extension); filename_t src = calc_filename(_base_filename, i - 1, _extension);
filename_t target = calc_filename(_base_filename, i, _extension); filename_t target = calc_filename(_base_filename, i, _extension);
if (details::file_helper::file_exists(target)) if (details::file_helper::file_exists(target))
{ {
if (details::os::remove(target) != 0) if (details::os::remove(target) != 0)
{ {
throw spdlog_ex("rotating_file_sink: failed removing " + filename_to_str(target)); throw spdlog_ex("rotating_file_sink: failed removing " + filename_to_str(target));
} }
} }
if (details::file_helper::file_exists(src) && details::os::rename(src, target)) if (details::file_helper::file_exists(src) && details::os::rename(src, target))
{ {
throw spdlog_ex("rotating_file_sink: failed renaming " + filename_to_str(src) + " to " + filename_to_str(target)); throw spdlog_ex("rotating_file_sink: failed renaming " + filename_to_str(src) + " to " + filename_to_str(target));
} }
} }
_file_helper.reopen(true); _file_helper.reopen(true);
} }
filename_t _base_filename; filename_t _base_filename;
filename_t _extension; filename_t _extension;
std::size_t _max_size; std::size_t _max_size;
std::size_t _max_files; std::size_t _max_files;
std::size_t _current_size; std::size_t _current_size;
details::file_helper _file_helper; details::file_helper _file_helper;
}; };
typedef rotating_file_sink<std::mutex> rotating_file_sink_mt; typedef rotating_file_sink<std::mutex> rotating_file_sink_mt;
typedef rotating_file_sink<details::null_mutex>rotating_file_sink_st; typedef rotating_file_sink<details::null_mutex>rotating_file_sink_st;
/* /*
* Rotating file sink based on date. rotates at midnight * Rotating file sink based on date. rotates at midnight
*/ */
template<class Mutex> template<class Mutex>
class daily_file_sink :public base_sink < Mutex > class daily_file_sink :public base_sink < Mutex >
{ {
public: public:
//create daily file sink which rotates on given time //create daily file sink which rotates on given time
daily_file_sink( daily_file_sink(
const filename_t& base_filename, const filename_t& base_filename,
const filename_t& extension, const filename_t& extension,
int rotation_hour, int rotation_hour,
int rotation_minute, int rotation_minute,
bool force_flush = false) : _base_filename(base_filename), bool force_flush = false) : _base_filename(base_filename),
_extension(extension), _extension(extension),
_rotation_h(rotation_hour), _rotation_h(rotation_hour),
_rotation_m(rotation_minute), _rotation_m(rotation_minute),
_file_helper(force_flush) _file_helper(force_flush)
{ {
if (rotation_hour < 0 || rotation_hour > 23 || rotation_minute < 0 || rotation_minute > 59) if (rotation_hour < 0 || rotation_hour > 23 || rotation_minute < 0 || rotation_minute > 59)
throw spdlog_ex("daily_file_sink: Invalid rotation time in ctor"); throw spdlog_ex("daily_file_sink: Invalid rotation time in ctor");
_rotation_tp = _next_rotation_tp(); _rotation_tp = _next_rotation_tp();
_file_helper.open(calc_filename(_base_filename, _extension)); _file_helper.open(calc_filename(_base_filename, _extension));
} }
void flush() override void flush() override
{ {
_file_helper.flush(); _file_helper.flush();
} }
protected: protected:
void _sink_it(const details::log_msg& msg) override void _sink_it(const details::log_msg& msg) override
{ {
if (std::chrono::system_clock::now() >= _rotation_tp) if (std::chrono::system_clock::now() >= _rotation_tp)
{ {
_file_helper.open(calc_filename(_base_filename, _extension)); _file_helper.open(calc_filename(_base_filename, _extension));
_rotation_tp = _next_rotation_tp(); _rotation_tp = _next_rotation_tp();
} }
_file_helper.write(msg); _file_helper.write(msg);
} }
private: private:
std::chrono::system_clock::time_point _next_rotation_tp() std::chrono::system_clock::time_point _next_rotation_tp()
{ {
using namespace std::chrono; using namespace std::chrono;
auto now = system_clock::now(); auto now = system_clock::now();
time_t tnow = std::chrono::system_clock::to_time_t(now); time_t tnow = std::chrono::system_clock::to_time_t(now);
tm date = spdlog::details::os::localtime(tnow); tm date = spdlog::details::os::localtime(tnow);
date.tm_hour = _rotation_h; date.tm_hour = _rotation_h;
date.tm_min = _rotation_m; date.tm_min = _rotation_m;
date.tm_sec = 0; date.tm_sec = 0;
auto rotation_time = std::chrono::system_clock::from_time_t(std::mktime(&date)); auto rotation_time = std::chrono::system_clock::from_time_t(std::mktime(&date));
if (rotation_time > now) if (rotation_time > now)
return rotation_time; return rotation_time;
else else
return system_clock::time_point(rotation_time + hours(24)); return system_clock::time_point(rotation_time + hours(24));
} }
//Create filename for the form basename.YYYY-MM-DD.extension //Create filename for the form basename.YYYY-MM-DD.extension
static filename_t calc_filename(const filename_t& basename, const filename_t& extension) static filename_t calc_filename(const filename_t& basename, const filename_t& extension)
{ {
std::tm tm = spdlog::details::os::localtime(); std::tm tm = spdlog::details::os::localtime();
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, extension); 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, extension);
return w.str(); return w.str();
} }
filename_t _base_filename; filename_t _base_filename;
filename_t _extension; filename_t _extension;
int _rotation_h; int _rotation_h;
int _rotation_m; int _rotation_m;
std::chrono::system_clock::time_point _rotation_tp; std::chrono::system_clock::time_point _rotation_tp;
details::file_helper _file_helper; details::file_helper _file_helper;
}; };
typedef daily_file_sink<std::mutex> daily_file_sink_mt; typedef daily_file_sink<std::mutex> daily_file_sink_mt;
typedef daily_file_sink<details::null_mutex> daily_file_sink_st; typedef daily_file_sink<details::null_mutex> daily_file_sink_st;
} }
} }

View File

@ -1,50 +1,50 @@
// //
// Copyright(c) 2016 Alexander Dalshov. // Copyright(c) 2016 Alexander Dalshov.
// Distributed under the MIT License (http://opensource.org/licenses/MIT) // Distributed under the MIT License (http://opensource.org/licenses/MIT)
// //
#pragma once #pragma once
#if defined(_MSC_VER) #if defined(_MSC_VER)
#include <spdlog/sinks/base_sink.h> #include <spdlog/sinks/base_sink.h>
#include <spdlog/details/null_mutex.h> #include <spdlog/details/null_mutex.h>
#include <WinBase.h> #include <WinBase.h>
#include <mutex> #include <mutex>
#include <string> #include <string>
namespace spdlog namespace spdlog
{ {
namespace sinks namespace sinks
{ {
/* /*
* MSVC sink (logging using OutputDebugStringA) * MSVC sink (logging using OutputDebugStringA)
*/ */
template<class Mutex> template<class Mutex>
class msvc_sink : public base_sink < Mutex > class msvc_sink : public base_sink < Mutex >
{ {
public: public:
explicit msvc_sink() explicit msvc_sink()
{ {
} }
void flush() override void flush() override
{ {
} }
protected: protected:
void _sink_it(const details::log_msg& msg) override void _sink_it(const details::log_msg& msg) override
{ {
OutputDebugStringA(msg.formatted.c_str()); OutputDebugStringA(msg.formatted.c_str());
} }
}; };
typedef msvc_sink<std::mutex> msvc_sink_mt; typedef msvc_sink<std::mutex> msvc_sink_mt;
typedef msvc_sink<details::null_mutex> msvc_sink_st; typedef msvc_sink<details::null_mutex> msvc_sink_st;
} }
} }
#endif #endif

View File

@ -1,34 +1,34 @@
// //
// Copyright(c) 2015 Gabi Melman. // Copyright(c) 2015 Gabi Melman.
// Distributed under the MIT License (http://opensource.org/licenses/MIT) // Distributed under the MIT License (http://opensource.org/licenses/MIT)
// //
#pragma once #pragma once
#include <spdlog/sinks/base_sink.h> #include <spdlog/sinks/base_sink.h>
#include <spdlog/details/null_mutex.h> #include <spdlog/details/null_mutex.h>
#include <mutex> #include <mutex>
namespace spdlog namespace spdlog
{ {
namespace sinks namespace sinks
{ {
template <class Mutex> template <class Mutex>
class null_sink : public base_sink < Mutex > class null_sink : public base_sink < Mutex >
{ {
protected: protected:
void _sink_it(const details::log_msg&) override void _sink_it(const details::log_msg&) override
{} {}
void flush() override void flush() override
{} {}
}; };
typedef null_sink<details::null_mutex> null_sink_st; typedef null_sink<details::null_mutex> null_sink_st;
typedef null_sink<std::mutex> null_sink_mt; typedef null_sink<std::mutex> null_sink_mt;
} }
} }

View File

@ -1,47 +1,47 @@
// //
// Copyright(c) 2015 Gabi Melman. // Copyright(c) 2015 Gabi Melman.
// Distributed under the MIT License (http://opensource.org/licenses/MIT) // Distributed under the MIT License (http://opensource.org/licenses/MIT)
// //
#pragma once #pragma once
#include <spdlog/details/null_mutex.h> #include <spdlog/details/null_mutex.h>
#include <spdlog/sinks/base_sink.h> #include <spdlog/sinks/base_sink.h>
#include <ostream> #include <ostream>
#include <mutex> #include <mutex>
namespace spdlog namespace spdlog
{ {
namespace sinks namespace sinks
{ {
template<class Mutex> template<class Mutex>
class ostream_sink: public base_sink<Mutex> class ostream_sink: public base_sink<Mutex>
{ {
public: public:
explicit ostream_sink(std::ostream& os, bool force_flush=false) :_ostream(os), _force_flush(force_flush) {} explicit ostream_sink(std::ostream& os, bool force_flush=false) :_ostream(os), _force_flush(force_flush) {}
ostream_sink(const ostream_sink&) = delete; ostream_sink(const ostream_sink&) = delete;
ostream_sink& operator=(const ostream_sink&) = delete; ostream_sink& operator=(const ostream_sink&) = delete;
virtual ~ostream_sink() = default; virtual ~ostream_sink() = default;
protected: protected:
void _sink_it(const details::log_msg& msg) override void _sink_it(const details::log_msg& msg) override
{ {
_ostream.write(msg.formatted.data(), msg.formatted.size()); _ostream.write(msg.formatted.data(), msg.formatted.size());
if (_force_flush) if (_force_flush)
_ostream.flush(); _ostream.flush();
} }
void flush() override void flush() override
{ {
_ostream.flush(); _ostream.flush();
} }
std::ostream& _ostream; std::ostream& _ostream;
bool _force_flush; bool _force_flush;
}; };
typedef ostream_sink<std::mutex> ostream_sink_mt; typedef ostream_sink<std::mutex> ostream_sink_mt;
typedef ostream_sink<details::null_mutex> ostream_sink_st; typedef ostream_sink<details::null_mutex> ostream_sink_st;
} }
} }

View File

@ -1,24 +1,24 @@
// //
// Copyright(c) 2015 Gabi Melman. // Copyright(c) 2015 Gabi Melman.
// Distributed under the MIT License (http://opensource.org/licenses/MIT) // Distributed under the MIT License (http://opensource.org/licenses/MIT)
// //
#pragma once #pragma once
#include <spdlog/details/log_msg.h> #include <spdlog/details/log_msg.h>
namespace spdlog namespace spdlog
{ {
namespace sinks namespace sinks
{ {
class sink class sink
{ {
public: public:
virtual ~sink() {} virtual ~sink() {}
virtual void log(const details::log_msg& msg) = 0; virtual void log(const details::log_msg& msg) = 0;
virtual void flush() = 0; virtual void flush() = 0;
}; };
} }
} }

View File

@ -1,74 +1,74 @@
// //
// Copyright(c) 2015 Gabi Melman. // Copyright(c) 2015 Gabi Melman.
// Distributed under the MIT License (http://opensource.org/licenses/MIT) // Distributed under the MIT License (http://opensource.org/licenses/MIT)
// //
#pragma once #pragma once
#include <spdlog/details/null_mutex.h> #include <spdlog/details/null_mutex.h>
#include <cstdio> #include <cstdio>
#include <memory> #include <memory>
#include <mutex> #include <mutex>
namespace spdlog namespace spdlog
{ {
namespace sinks namespace sinks
{ {
template <class Mutex> template <class Mutex>
class stdout_sink : public base_sink<Mutex> class stdout_sink : public base_sink<Mutex>
{ {
using MyType = stdout_sink<Mutex>; using MyType = stdout_sink<Mutex>;
public: public:
stdout_sink() {} stdout_sink() {}
static std::shared_ptr<MyType> instance() static std::shared_ptr<MyType> instance()
{ {
static std::shared_ptr<MyType> instance = std::make_shared<MyType>(); static std::shared_ptr<MyType> instance = std::make_shared<MyType>();
return instance; return instance;
} }
void _sink_it(const details::log_msg& msg) override void _sink_it(const details::log_msg& msg) override
{ {
fwrite(msg.formatted.data(), sizeof(char), msg.formatted.size(), stdout); fwrite(msg.formatted.data(), sizeof(char), msg.formatted.size(), stdout);
flush(); flush();
} }
void flush() override void flush() override
{ {
fflush(stdout); fflush(stdout);
} }
}; };
typedef stdout_sink<details::null_mutex> stdout_sink_st; typedef stdout_sink<details::null_mutex> stdout_sink_st;
typedef stdout_sink<std::mutex> stdout_sink_mt; typedef stdout_sink<std::mutex> stdout_sink_mt;
template <class Mutex> template <class Mutex>
class stderr_sink : public base_sink<Mutex> class stderr_sink : public base_sink<Mutex>
{ {
using MyType = stderr_sink<Mutex>; using MyType = stderr_sink<Mutex>;
public: public:
stderr_sink() {} stderr_sink() {}
static std::shared_ptr<MyType> instance() static std::shared_ptr<MyType> instance()
{ {
static std::shared_ptr<MyType> instance = std::make_shared<MyType>(); static std::shared_ptr<MyType> instance = std::make_shared<MyType>();
return instance; return instance;
} }
void _sink_it(const details::log_msg& msg) override void _sink_it(const details::log_msg& msg) override
{ {
fwrite(msg.formatted.data(), sizeof(char), msg.formatted.size(), stderr); fwrite(msg.formatted.data(), sizeof(char), msg.formatted.size(), stderr);
flush(); flush();
} }
void flush() override void flush() override
{ {
fflush(stderr); fflush(stderr);
} }
}; };
typedef stderr_sink<std::mutex> stderr_sink_mt; typedef stderr_sink<std::mutex> stderr_sink_mt;
typedef stderr_sink<details::null_mutex> stderr_sink_st; typedef stderr_sink<details::null_mutex> stderr_sink_st;
} }
} }

View File

@ -1,83 +1,83 @@
// //
// Copyright(c) 2015 Gabi Melman. // Copyright(c) 2015 Gabi Melman.
// Distributed under the MIT License (http://opensource.org/licenses/MIT) // Distributed under the MIT License (http://opensource.org/licenses/MIT)
// //
#pragma once #pragma once
#if defined(__linux__) || defined(__APPLE__) #if defined(__linux__) || defined(__APPLE__)
#include <spdlog/sinks/sink.h> #include <spdlog/sinks/sink.h>
#include <spdlog/common.h> #include <spdlog/common.h>
#include <spdlog/details/log_msg.h> #include <spdlog/details/log_msg.h>
#include <array> #include <array>
#include <string> #include <string>
#include <syslog.h> #include <syslog.h>
namespace spdlog namespace spdlog
{ {
namespace sinks namespace sinks
{ {
/** /**
* Sink that write to syslog using the `syscall()` library call. * Sink that write to syslog using the `syscall()` library call.
* *
* Locking is not needed, as `syslog()` itself is thread-safe. * Locking is not needed, as `syslog()` itself is thread-safe.
*/ */
class syslog_sink : public sink class syslog_sink : public sink
{ {
public: public:
// //
syslog_sink(const std::string& ident = "", int syslog_option=0, int syslog_facility=LOG_USER): syslog_sink(const std::string& ident = "", int syslog_option=0, int syslog_facility=LOG_USER):
_ident(ident) _ident(ident)
{ {
_priorities[static_cast<int>(level::trace)] = LOG_DEBUG; _priorities[static_cast<int>(level::trace)] = LOG_DEBUG;
_priorities[static_cast<int>(level::debug)] = LOG_DEBUG; _priorities[static_cast<int>(level::debug)] = LOG_DEBUG;
_priorities[static_cast<int>(level::info)] = LOG_INFO; _priorities[static_cast<int>(level::info)] = LOG_INFO;
_priorities[static_cast<int>(level::notice)] = LOG_NOTICE; _priorities[static_cast<int>(level::notice)] = LOG_NOTICE;
_priorities[static_cast<int>(level::warn)] = LOG_WARNING; _priorities[static_cast<int>(level::warn)] = LOG_WARNING;
_priorities[static_cast<int>(level::err)] = LOG_ERR; _priorities[static_cast<int>(level::err)] = LOG_ERR;
_priorities[static_cast<int>(level::critical)] = LOG_CRIT; _priorities[static_cast<int>(level::critical)] = LOG_CRIT;
_priorities[static_cast<int>(level::alert)] = LOG_ALERT; _priorities[static_cast<int>(level::alert)] = LOG_ALERT;
_priorities[static_cast<int>(level::emerg)] = LOG_EMERG; _priorities[static_cast<int>(level::emerg)] = LOG_EMERG;
_priorities[static_cast<int>(level::off)] = LOG_INFO; _priorities[static_cast<int>(level::off)] = LOG_INFO;
//set ident to be program name if empty //set ident to be program name if empty
::openlog(_ident.empty()? nullptr:_ident.c_str(), syslog_option, syslog_facility); ::openlog(_ident.empty()? nullptr:_ident.c_str(), syslog_option, syslog_facility);
} }
~syslog_sink() ~syslog_sink()
{ {
::closelog(); ::closelog();
} }
syslog_sink(const syslog_sink&) = delete; syslog_sink(const syslog_sink&) = delete;
syslog_sink& operator=(const syslog_sink&) = delete; syslog_sink& operator=(const syslog_sink&) = delete;
void log(const details::log_msg &msg) override void log(const details::log_msg &msg) override
{ {
::syslog(syslog_prio_from_level(msg), "%s", msg.raw.str().c_str()); ::syslog(syslog_prio_from_level(msg), "%s", msg.raw.str().c_str());
} }
void flush() override void flush() override
{ {
} }
private: private:
std::array<int, 10> _priorities; std::array<int, 10> _priorities;
//must store the ident because the man says openlog might use the pointer as is and not a string copy //must store the ident because the man says openlog might use the pointer as is and not a string copy
const std::string _ident; const std::string _ident;
// //
// Simply maps spdlog's log level to syslog priority level. // Simply maps spdlog's log level to syslog priority level.
// //
int syslog_prio_from_level(const details::log_msg &msg) const int syslog_prio_from_level(const details::log_msg &msg) const
{ {
return _priorities[static_cast<int>(msg.level)]; return _priorities[static_cast<int>(msg.level)];
} }
}; };
} }
} }
#endif #endif

View File

@ -1,139 +1,139 @@
// //
// Copyright(c) 2015 Gabi Melman. // Copyright(c) 2015 Gabi Melman.
// Distributed under the MIT License (http://opensource.org/licenses/MIT) // Distributed under the MIT License (http://opensource.org/licenses/MIT)
// //
// spdlog main header file. // spdlog main header file.
// see example.cpp for usage example // see example.cpp for usage example
#pragma once #pragma once
#include <spdlog/tweakme.h> #include <spdlog/tweakme.h>
#include <spdlog/common.h> #include <spdlog/common.h>
#include <spdlog/logger.h> #include <spdlog/logger.h>
#include <memory> #include <memory>
#include <functional> #include <functional>
#include <chrono> #include <chrono>
#include <string> #include <string>
namespace spdlog namespace spdlog
{ {
// Return an existing logger or nullptr if a logger with such name doesn't exist. // Return an existing logger or nullptr if a logger with such name doesn't exist.
// Examples: // Examples:
// //
// spdlog::get("mylog")->info("Hello"); // spdlog::get("mylog")->info("Hello");
// auto logger = spdlog::get("mylog"); // auto logger = spdlog::get("mylog");
// logger.info("This is another message" , x, y, z); // logger.info("This is another message" , x, y, z);
// logger.info() << "This is another message" << x << y << z; // logger.info() << "This is another message" << x << y << z;
std::shared_ptr<logger> get(const std::string& name); std::shared_ptr<logger> get(const std::string& name);
// //
// Set global formatting // Set global formatting
// example: spdlog::set_pattern("%Y-%m-%d %H:%M:%S.%e %l : %v"); // example: spdlog::set_pattern("%Y-%m-%d %H:%M:%S.%e %l : %v");
// //
void set_pattern(const std::string& format_string); void set_pattern(const std::string& format_string);
void set_formatter(formatter_ptr f); void set_formatter(formatter_ptr f);
// //
// Set global logging level for // Set global logging level for
// //
void set_level(level::level_enum log_level); void set_level(level::level_enum log_level);
// //
// Turn on async mode (off by default) and set the queue size for each async_logger. // Turn on async mode (off by default) and set the queue size for each async_logger.
// effective only for loggers created after this call. // effective only for loggers created after this call.
// queue_size: size of queue (must be power of 2): // queue_size: size of queue (must be power of 2):
// Each logger will pre-allocate a dedicated queue with queue_size entries upon construction. // Each logger will pre-allocate a dedicated queue with queue_size entries upon construction.
// //
// async_overflow_policy (optional, block_retry by default): // async_overflow_policy (optional, block_retry by default):
// async_overflow_policy::block_retry - if queue is full, block until queue has room for the new log entry. // async_overflow_policy::block_retry - if queue is full, block until queue has room for the new log entry.
// async_overflow_policy::discard_log_msg - never block and discard any new messages when queue overflows. // async_overflow_policy::discard_log_msg - never block and discard any new messages when queue overflows.
// //
// worker_warmup_cb (optional): // worker_warmup_cb (optional):
// callback function that will be called in worker thread upon start (can be used to init stuff like thread affinity) // callback function that will be called in worker thread upon start (can be used to init stuff like thread affinity)
// //
void set_async_mode(size_t queue_size, const async_overflow_policy overflow_policy = async_overflow_policy::block_retry, const std::function<void()>& worker_warmup_cb = nullptr, const std::chrono::milliseconds& flush_interval_ms = std::chrono::milliseconds::zero()); void set_async_mode(size_t queue_size, const async_overflow_policy overflow_policy = async_overflow_policy::block_retry, const std::function<void()>& worker_warmup_cb = nullptr, const std::chrono::milliseconds& flush_interval_ms = std::chrono::milliseconds::zero());
// Turn off async mode // Turn off async mode
void set_sync_mode(); void set_sync_mode();
// //
// Create and register multi/single threaded rotating file logger // Create and register multi/single threaded rotating file logger
// //
std::shared_ptr<logger> rotating_logger_mt(const std::string& logger_name, const filename_t& filename, size_t max_file_size, size_t max_files, bool force_flush = false); std::shared_ptr<logger> rotating_logger_mt(const std::string& logger_name, const filename_t& filename, size_t max_file_size, size_t max_files, bool force_flush = false);
std::shared_ptr<logger> rotating_logger_st(const std::string& logger_name, const filename_t& filename, size_t max_file_size, size_t max_files, bool force_flush = false); std::shared_ptr<logger> rotating_logger_st(const std::string& logger_name, const filename_t& filename, size_t max_file_size, size_t max_files, bool force_flush = false);
// //
// Create file logger which creates new file on the given time (default in midnight): // Create file logger which creates new file on the given time (default in midnight):
// //
std::shared_ptr<logger> daily_logger_mt(const std::string& logger_name, const filename_t& filename, int hour=0, int minute=0, bool force_flush = false); std::shared_ptr<logger> daily_logger_mt(const std::string& logger_name, const filename_t& filename, int hour=0, int minute=0, bool force_flush = false);
std::shared_ptr<logger> daily_logger_st(const std::string& logger_name, const filename_t& filename, int hour=0, int minute=0, bool force_flush = false); std::shared_ptr<logger> daily_logger_st(const std::string& logger_name, const filename_t& filename, int hour=0, int minute=0, bool force_flush = false);
// //
// Create and register stdout/stderr loggers // Create and register stdout/stderr loggers
// //
std::shared_ptr<logger> stdout_logger_mt(const std::string& logger_name, bool color = false); std::shared_ptr<logger> stdout_logger_mt(const std::string& logger_name, bool color = false);
std::shared_ptr<logger> stdout_logger_st(const std::string& logger_name, bool color = false); std::shared_ptr<logger> stdout_logger_st(const std::string& logger_name, bool color = false);
std::shared_ptr<logger> stderr_logger_mt(const std::string& logger_name, bool color = false); std::shared_ptr<logger> stderr_logger_mt(const std::string& logger_name, bool color = false);
std::shared_ptr<logger> stderr_logger_st(const std::string& logger_name, bool color = false); std::shared_ptr<logger> stderr_logger_st(const std::string& logger_name, bool color = false);
// //
// Create and register a syslog logger // Create and register a syslog logger
// //
#if defined(__linux__) || defined(__APPLE__) #if defined(__linux__) || defined(__APPLE__)
std::shared_ptr<logger> syslog_logger(const std::string& logger_name, const std::string& ident = "", int syslog_option = 0); std::shared_ptr<logger> syslog_logger(const std::string& logger_name, const std::string& ident = "", int syslog_option = 0);
#endif #endif
// Create and register a logger with multiple sinks // Create and register a logger with multiple sinks
std::shared_ptr<logger> create(const std::string& logger_name, sinks_init_list sinks); std::shared_ptr<logger> create(const std::string& logger_name, sinks_init_list sinks);
template<class It> template<class It>
std::shared_ptr<logger> create(const std::string& logger_name, const It& sinks_begin, const It& sinks_end); std::shared_ptr<logger> create(const std::string& logger_name, const It& sinks_begin, const It& sinks_end);
// Create and register a logger with templated sink type // Create and register a logger with templated sink type
// Example: spdlog::create<daily_file_sink_st>("mylog", "dailylog_filename", "txt"); // Example: spdlog::create<daily_file_sink_st>("mylog", "dailylog_filename", "txt");
template <typename Sink, typename... Args> template <typename Sink, typename... Args>
std::shared_ptr<spdlog::logger> create(const std::string& logger_name, Args...); std::shared_ptr<spdlog::logger> create(const std::string& logger_name, Args...);
// Register the given logger with the given name // Register the given logger with the given name
void register_logger(std::shared_ptr<logger> logger); void register_logger(std::shared_ptr<logger> logger);
// Drop the reference to the given logger // Drop the reference to the given logger
void drop(const std::string &name); void drop(const std::string &name);
// Drop all references // Drop all references
void drop_all(); void drop_all();
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// //
// Macros to be display source file & line // Macros to be display source file & line
// Trace & Debug can be switched on/off at compile time for zero cost debug statements. // Trace & Debug can be switched on/off at compile time for zero cost debug statements.
// Uncomment SPDLOG_DEBUG_ON/SPDLOG_TRACE_ON in teakme.h to enable. // Uncomment SPDLOG_DEBUG_ON/SPDLOG_TRACE_ON in teakme.h to enable.
// //
// Example: // Example:
// spdlog::set_level(spdlog::level::debug); // spdlog::set_level(spdlog::level::debug);
// SPDLOG_DEBUG(my_logger, "Some debug message {} {}", 1, 3.2); // SPDLOG_DEBUG(my_logger, "Some debug message {} {}", 1, 3.2);
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
#ifdef SPDLOG_TRACE_ON #ifdef SPDLOG_TRACE_ON
#define SPDLOG_TRACE(logger, ...) logger->trace(__VA_ARGS__) << " (" << __FILE__ << " #" << __LINE__ <<")"; #define SPDLOG_TRACE(logger, ...) logger->trace(__VA_ARGS__) << " (" << __FILE__ << " #" << __LINE__ <<")";
#else #else
#define SPDLOG_TRACE(logger, ...) #define SPDLOG_TRACE(logger, ...)
#endif #endif
#ifdef SPDLOG_DEBUG_ON #ifdef SPDLOG_DEBUG_ON
#define SPDLOG_DEBUG(logger, ...) logger->debug(__VA_ARGS__) << " (" << __FILE__ << " #" << __LINE__ <<")"; #define SPDLOG_DEBUG(logger, ...) logger->debug(__VA_ARGS__) << " (" << __FILE__ << " #" << __LINE__ <<")";
#else #else
#define SPDLOG_DEBUG(logger, ...) #define SPDLOG_DEBUG(logger, ...)
#endif #endif
} }
#include <spdlog/details/spdlog_impl.h> #include <spdlog/details/spdlog_impl.h>

View File

@ -1,77 +1,77 @@
/* /*
* This content is released under the MIT License as specified in https://raw.githubusercontent.com/gabime/spdlog/master/LICENSE * This content is released under the MIT License as specified in https://raw.githubusercontent.com/gabime/spdlog/master/LICENSE
*/ */
#include "includes.h" #include "includes.h"
using namespace spdlog::details; using namespace spdlog::details;
static const std::string target_filename = "logs/file_helper_test.txt"; static const std::string target_filename = "logs/file_helper_test.txt";
static void write_with_helper(file_helper &helper, size_t howmany) static void write_with_helper(file_helper &helper, size_t howmany)
{ {
log_msg msg; log_msg msg;
msg.formatted << std::string(howmany, '1'); msg.formatted << std::string(howmany, '1');
helper.write(msg); helper.write(msg);
} }
TEST_CASE("file_helper_filename", "[file_helper::filename()]]") TEST_CASE("file_helper_filename", "[file_helper::filename()]]")
{ {
prepare_logdir(); prepare_logdir();
file_helper helper(false); file_helper helper(false);
helper.open(target_filename); helper.open(target_filename);
REQUIRE(helper.filename() == target_filename); REQUIRE(helper.filename() == target_filename);
} }
TEST_CASE("file_helper_size", "[file_helper::size()]]") TEST_CASE("file_helper_size", "[file_helper::size()]]")
{ {
prepare_logdir(); prepare_logdir();
auto expected_size = 123; auto expected_size = 123;
{ {
file_helper helper(true); file_helper helper(true);
helper.open(target_filename); helper.open(target_filename);
write_with_helper(helper, expected_size); write_with_helper(helper, expected_size);
REQUIRE(helper.size() == expected_size); REQUIRE(helper.size() == expected_size);
} }
REQUIRE(get_filesize(target_filename) == expected_size); REQUIRE(get_filesize(target_filename) == expected_size);
} }
TEST_CASE("file_helper_exists", "[file_helper::file_exists()]]") TEST_CASE("file_helper_exists", "[file_helper::file_exists()]]")
{ {
prepare_logdir(); prepare_logdir();
REQUIRE(!file_helper::file_exists(target_filename)); REQUIRE(!file_helper::file_exists(target_filename));
file_helper helper(false); file_helper helper(false);
helper.open(target_filename); helper.open(target_filename);
REQUIRE(file_helper::file_exists(target_filename)); REQUIRE(file_helper::file_exists(target_filename));
} }
TEST_CASE("file_helper_reopen", "[file_helper::reopen()]]") TEST_CASE("file_helper_reopen", "[file_helper::reopen()]]")
{ {
prepare_logdir(); prepare_logdir();
file_helper helper(true); file_helper helper(true);
helper.open(target_filename); helper.open(target_filename);
write_with_helper(helper, 12); write_with_helper(helper, 12);
REQUIRE(helper.size() == 12); REQUIRE(helper.size() == 12);
helper.reopen(true); helper.reopen(true);
REQUIRE(helper.size() == 0); REQUIRE(helper.size() == 0);
} }
TEST_CASE("file_helper_reopen2", "[file_helper::reopen(false)]]") TEST_CASE("file_helper_reopen2", "[file_helper::reopen(false)]]")
{ {
prepare_logdir(); prepare_logdir();
auto expected_size = 14; auto expected_size = 14;
file_helper helper(true); file_helper helper(true);
helper.open(target_filename); helper.open(target_filename);
write_with_helper(helper, expected_size); write_with_helper(helper, expected_size);
REQUIRE(helper.size() == expected_size); REQUIRE(helper.size() == expected_size);
helper.reopen(false); helper.reopen(false);
REQUIRE(helper.size() == expected_size); REQUIRE(helper.size() == expected_size);
} }

View File

@ -1,91 +1,91 @@
/* /*
* This content is released under the MIT License as specified in https://raw.githubusercontent.com/gabime/spdlog/master/LICENSE * This content is released under the MIT License as specified in https://raw.githubusercontent.com/gabime/spdlog/master/LICENSE
*/ */
#include "includes.h" #include "includes.h"
TEST_CASE("simple_file_logger", "[simple_logger]]") TEST_CASE("simple_file_logger", "[simple_logger]]")
{ {
prepare_logdir(); prepare_logdir();
std::string filename = "logs/simple_log.txt"; std::string filename = "logs/simple_log.txt";
auto logger = spdlog::create<spdlog::sinks::simple_file_sink_mt>("logger", filename); auto logger = spdlog::create<spdlog::sinks::simple_file_sink_mt>("logger", filename);
logger->set_pattern("%v"); logger->set_pattern("%v");
logger->info("Test message {}", 1); logger->info("Test message {}", 1);
logger->info("Test message {}", 2); logger->info("Test message {}", 2);
logger->flush(); logger->flush();
REQUIRE(file_contents(filename) == std::string("Test message 1\nTest message 2\n")); REQUIRE(file_contents(filename) == std::string("Test message 1\nTest message 2\n"));
REQUIRE(count_lines(filename) == 2); REQUIRE(count_lines(filename) == 2);
} }
TEST_CASE("rotating_file_logger1", "[rotating_logger]]") TEST_CASE("rotating_file_logger1", "[rotating_logger]]")
{ {
prepare_logdir(); prepare_logdir();
std::string basename = "logs/rotating_log"; std::string basename = "logs/rotating_log";
auto logger = spdlog::rotating_logger_mt("logger", basename, 1024, 0, true); auto logger = spdlog::rotating_logger_mt("logger", basename, 1024, 0, true);
for (int i = 0; i < 10; ++i) for (int i = 0; i < 10; ++i)
logger->info("Test message {}", i); logger->info("Test message {}", i);
auto filename = basename + ".txt"; auto filename = basename + ".txt";
REQUIRE(count_lines(filename) == 10); REQUIRE(count_lines(filename) == 10);
for (int i = 0; i < 1000; i++) for (int i = 0; i < 1000; i++)
logger->info("Test message {}", i); logger->info("Test message {}", i);
} }
TEST_CASE("rotating_file_logger2", "[rotating_logger]]") TEST_CASE("rotating_file_logger2", "[rotating_logger]]")
{ {
prepare_logdir(); prepare_logdir();
std::string basename = "logs/rotating_log"; std::string basename = "logs/rotating_log";
auto logger = spdlog::rotating_logger_mt("logger", basename, 1024, 1, false); auto logger = spdlog::rotating_logger_mt("logger", basename, 1024, 1, false);
for (int i = 0; i < 10; ++i) for (int i = 0; i < 10; ++i)
logger->info("Test message {}", i); logger->info("Test message {}", i);
logger->flush(); logger->flush();
auto filename = basename + ".txt"; auto filename = basename + ".txt";
REQUIRE(count_lines(filename) == 10); REQUIRE(count_lines(filename) == 10);
for (int i = 0; i < 1000; i++) for (int i = 0; i < 1000; i++)
logger->info("Test message {}", i); logger->info("Test message {}", i);
logger->flush(); logger->flush();
REQUIRE(get_filesize(filename) <= 1024); REQUIRE(get_filesize(filename) <= 1024);
auto filename1 = basename + ".1.txt"; auto filename1 = basename + ".1.txt";
REQUIRE(get_filesize(filename1) <= 1024); REQUIRE(get_filesize(filename1) <= 1024);
} }
TEST_CASE("daily_logger", "[daily_logger]]") TEST_CASE("daily_logger", "[daily_logger]]")
{ {
prepare_logdir(); prepare_logdir();
//calculate filename (time based) //calculate filename (time based)
std::string basename = "logs/daily_log"; std::string basename = "logs/daily_log";
std::tm tm = spdlog::details::os::localtime(); std::tm tm = spdlog::details::os::localtime();
fmt::MemoryWriter w; fmt::MemoryWriter w;
w.write("{}_{:04d}-{:02d}-{:02d}_{:02d}-{:02d}.txt", basename, tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min); w.write("{}_{:04d}-{:02d}-{:02d}_{:02d}-{:02d}.txt", basename, tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min);
auto logger = spdlog::daily_logger_mt("logger", basename, 0, 0, true); auto logger = spdlog::daily_logger_mt("logger", basename, 0, 0, true);
for (int i = 0; i < 10; ++i) for (int i = 0; i < 10; ++i)
logger->info("Test message {}", i); logger->info("Test message {}", i);
auto filename = w.str(); auto filename = w.str();
REQUIRE(count_lines(filename) == 10); REQUIRE(count_lines(filename) == 10);
} }

View File

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

View File

@ -1,45 +1,45 @@
#include "includes.h" #include "includes.h"
void prepare_logdir() void prepare_logdir()
{ {
spdlog::drop_all(); spdlog::drop_all();
#ifdef _WIN32 #ifdef _WIN32
auto rv = system("del /F /Q logs\\*"); auto rv = system("del /F /Q logs\\*");
#else #else
auto rv = system("rm -f logs/*"); auto rv = system("rm -f logs/*");
#endif #endif
(void)rv; (void)rv;
} }
std::string file_contents(const std::string& filename) std::string file_contents(const std::string& filename)
{ {
std::ifstream ifs(filename); std::ifstream ifs(filename);
if (!ifs) if (!ifs)
throw std::runtime_error("Failed open file "); throw std::runtime_error("Failed open file ");
return std::string((std::istreambuf_iterator<char>(ifs)), return std::string((std::istreambuf_iterator<char>(ifs)),
(std::istreambuf_iterator<char>())); (std::istreambuf_iterator<char>()));
} }
std::size_t count_lines(const std::string& filename) std::size_t count_lines(const std::string& filename)
{ {
std::ifstream ifs(filename); std::ifstream ifs(filename);
if (!ifs) if (!ifs)
throw std::runtime_error("Failed open file "); throw std::runtime_error("Failed open file ");
std::string line; std::string line;
size_t counter = 0; size_t counter = 0;
while(std::getline(ifs, line)) while(std::getline(ifs, line))
counter++; counter++;
return counter; return counter;
} }
std::size_t get_filesize(const std::string& filename) std::size_t get_filesize(const std::string& filename)
{ {
std::ifstream ifs(filename, std::ifstream::ate | std::ifstream::binary); std::ifstream ifs(filename, std::ifstream::ate | std::ifstream::binary);
if (!ifs) if (!ifs)
throw std::runtime_error("Failed open file "); throw std::runtime_error("Failed open file ");
return ifs.tellg(); return ifs.tellg();
} }

View File

@ -1,15 +1,15 @@
#pragma once #pragma once
#include <string> #include <string>
#include<cstddef> #include<cstddef>
std::size_t count_lines(const std::string& filename); std::size_t count_lines(const std::string& filename);
void prepare_logdir(); void prepare_logdir();
std::string file_contents(const std::string& filename); std::string file_contents(const std::string& filename);
std::size_t count_lines(const std::string& filename); std::size_t count_lines(const std::string& filename);
std::size_t get_filesize(const std::string& filename); std::size_t get_filesize(const std::string& filename);