mirror of
https://github.com/gabime/spdlog.git
synced 2024-11-15 08:25:43 +08:00
astyle
This commit is contained in:
parent
0f88996974
commit
0d26359856
@ -1,62 +1,62 @@
|
||||
//
|
||||
// Copyright(c) 2015 Gabi Melman.
|
||||
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||
//
|
||||
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
#include <atomic>
|
||||
#include <iostream>
|
||||
#include <chrono>
|
||||
#include <cstdlib>
|
||||
#include "spdlog/spdlog.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
|
||||
using namespace std::chrono;
|
||||
using clock=steady_clock;
|
||||
namespace spd = spdlog;
|
||||
|
||||
int thread_count = 10;
|
||||
if(argc > 1)
|
||||
thread_count = ::atoi(argv[1]);
|
||||
int howmany = 1000000;
|
||||
|
||||
spd::set_async_mode(1048576);
|
||||
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");
|
||||
|
||||
|
||||
std::atomic<int > msg_counter {0};
|
||||
vector<thread> threads;
|
||||
auto start = clock::now();
|
||||
for (int t = 0; t < thread_count; ++t)
|
||||
{
|
||||
threads.push_back(std::thread([&]()
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
int counter = ++msg_counter;
|
||||
if (counter > howmany) break;
|
||||
logger->info() << "spdlog message #" << counter << ": This is some text for your pleasure";
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
for(auto &t:threads)
|
||||
{
|
||||
t.join();
|
||||
};
|
||||
|
||||
duration<float> delta = clock::now() - start;
|
||||
float deltaf = delta.count();
|
||||
auto rate = howmany/deltaf;
|
||||
|
||||
cout << "Total: " << howmany << std::endl;
|
||||
cout << "Threads: " << thread_count << std::endl;
|
||||
std::cout << "Delta = " << deltaf << " seconds" << std::endl;
|
||||
std::cout << "Rate = " << rate << "/sec" << std::endl;
|
||||
}
|
||||
//
|
||||
// Copyright(c) 2015 Gabi Melman.
|
||||
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||
//
|
||||
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
#include <atomic>
|
||||
#include <iostream>
|
||||
#include <chrono>
|
||||
#include <cstdlib>
|
||||
#include "spdlog/spdlog.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
|
||||
using namespace std::chrono;
|
||||
using clock=steady_clock;
|
||||
namespace spd = spdlog;
|
||||
|
||||
int thread_count = 10;
|
||||
if(argc > 1)
|
||||
thread_count = ::atoi(argv[1]);
|
||||
int howmany = 1000000;
|
||||
|
||||
spd::set_async_mode(1048576);
|
||||
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");
|
||||
|
||||
|
||||
std::atomic<int > msg_counter {0};
|
||||
vector<thread> threads;
|
||||
auto start = clock::now();
|
||||
for (int t = 0; t < thread_count; ++t)
|
||||
{
|
||||
threads.push_back(std::thread([&]()
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
int counter = ++msg_counter;
|
||||
if (counter > howmany) break;
|
||||
logger->info() << "spdlog message #" << counter << ": This is some text for your pleasure";
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
for(auto &t:threads)
|
||||
{
|
||||
t.join();
|
||||
};
|
||||
|
||||
duration<float> delta = clock::now() - start;
|
||||
float deltaf = delta.count();
|
||||
auto rate = howmany/deltaf;
|
||||
|
||||
cout << "Total: " << howmany << std::endl;
|
||||
cout << "Threads: " << thread_count << std::endl;
|
||||
std::cout << "Delta = " << deltaf << " seconds" << std::endl;
|
||||
std::cout << "Rate = " << rate << "/sec" << std::endl;
|
||||
}
|
||||
|
@ -1,56 +1,56 @@
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
#include <atomic>
|
||||
#include <cstdlib>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <zf_log.c>
|
||||
|
||||
const char g_path[] = "logs/zf_log.txt";
|
||||
int g_fd;
|
||||
|
||||
static void output_callback(zf_log_message *msg)
|
||||
{
|
||||
*msg->p = '\n';
|
||||
write(g_fd, msg->buf, msg->p - msg->buf + 1);
|
||||
}
|
||||
|
||||
using namespace std;
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
g_fd = open(g_path, O_APPEND|O_CREAT|O_WRONLY);
|
||||
if (0 > g_fd)
|
||||
{
|
||||
ZF_LOGE_AUX(ZF_LOG_STDERR, "Failed to open log file: %s", g_path);
|
||||
return -1;
|
||||
}
|
||||
zf_log_set_output_callback(ZF_LOG_PUT_STD, output_callback);
|
||||
|
||||
int thread_count = 10;
|
||||
if(argc > 1)
|
||||
thread_count = std::atoi(argv[1]);
|
||||
int howmany = 1000000;
|
||||
std::atomic<int > msg_counter {0};
|
||||
vector<thread> threads;
|
||||
|
||||
for (int t = 0; t < thread_count; ++t)
|
||||
{
|
||||
threads.push_back(std::thread([&]()
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
int counter = ++msg_counter;
|
||||
if (counter > howmany) break;
|
||||
ZF_LOGI("zf_log message #%i: This is some text for your pleasure", counter);
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
for (auto &t:threads)
|
||||
{
|
||||
t.join();
|
||||
};
|
||||
close(g_fd);
|
||||
return 0;
|
||||
}
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
#include <atomic>
|
||||
#include <cstdlib>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <zf_log.c>
|
||||
|
||||
const char g_path[] = "logs/zf_log.txt";
|
||||
int g_fd;
|
||||
|
||||
static void output_callback(zf_log_message *msg)
|
||||
{
|
||||
*msg->p = '\n';
|
||||
write(g_fd, msg->buf, msg->p - msg->buf + 1);
|
||||
}
|
||||
|
||||
using namespace std;
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
g_fd = open(g_path, O_APPEND|O_CREAT|O_WRONLY);
|
||||
if (0 > g_fd)
|
||||
{
|
||||
ZF_LOGE_AUX(ZF_LOG_STDERR, "Failed to open log file: %s", g_path);
|
||||
return -1;
|
||||
}
|
||||
zf_log_set_output_callback(ZF_LOG_PUT_STD, output_callback);
|
||||
|
||||
int thread_count = 10;
|
||||
if(argc > 1)
|
||||
thread_count = std::atoi(argv[1]);
|
||||
int howmany = 1000000;
|
||||
std::atomic<int > msg_counter {0};
|
||||
vector<thread> threads;
|
||||
|
||||
for (int t = 0; t < thread_count; ++t)
|
||||
{
|
||||
threads.push_back(std::thread([&]()
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
int counter = ++msg_counter;
|
||||
if (counter > howmany) break;
|
||||
ZF_LOGI("zf_log message #%i: This is some text for your pleasure", counter);
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
for (auto &t:threads)
|
||||
{
|
||||
t.join();
|
||||
};
|
||||
close(g_fd);
|
||||
return 0;
|
||||
}
|
||||
|
@ -1,28 +1,28 @@
|
||||
#include <stdio.h>
|
||||
#include <zf_log.c>
|
||||
|
||||
const char g_path[] = "logs/zf_log.txt";
|
||||
static FILE *g_f;
|
||||
|
||||
static void output_callback(zf_log_message *msg)
|
||||
{
|
||||
*msg->p = '\n';
|
||||
fwrite(msg->buf, msg->p - msg->buf + 1, 1, g_f);
|
||||
}
|
||||
|
||||
int main(int, char* [])
|
||||
{
|
||||
g_f = fopen(g_path, "wb");
|
||||
if (!g_f)
|
||||
{
|
||||
ZF_LOGE_AUX(ZF_LOG_STDERR, "Failed to open log file: %s", g_path);
|
||||
return -1;
|
||||
}
|
||||
zf_log_set_output_callback(ZF_LOG_PUT_STD, output_callback);
|
||||
|
||||
const int howmany = 1000000;
|
||||
for(int i = 0 ; i < howmany; ++i)
|
||||
ZF_LOGI("zf_log message #%i: This is some text for your pleasure", i);
|
||||
fclose(g_f);
|
||||
return 0;
|
||||
}
|
||||
#include <stdio.h>
|
||||
#include <zf_log.c>
|
||||
|
||||
const char g_path[] = "logs/zf_log.txt";
|
||||
static FILE *g_f;
|
||||
|
||||
static void output_callback(zf_log_message *msg)
|
||||
{
|
||||
*msg->p = '\n';
|
||||
fwrite(msg->buf, msg->p - msg->buf + 1, 1, g_f);
|
||||
}
|
||||
|
||||
int main(int, char* [])
|
||||
{
|
||||
g_f = fopen(g_path, "wb");
|
||||
if (!g_f)
|
||||
{
|
||||
ZF_LOGE_AUX(ZF_LOG_STDERR, "Failed to open log file: %s", g_path);
|
||||
return -1;
|
||||
}
|
||||
zf_log_set_output_callback(ZF_LOG_PUT_STD, output_callback);
|
||||
|
||||
const int howmany = 1000000;
|
||||
for(int i = 0 ; i < howmany; ++i)
|
||||
ZF_LOGI("zf_log message #%i: This is some text for your pleasure", i);
|
||||
fclose(g_f);
|
||||
return 0;
|
||||
}
|
||||
|
@ -1,118 +1,118 @@
|
||||
//
|
||||
// Copyright(c) 2015 Gabi Melman.
|
||||
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||
//
|
||||
//
|
||||
// spdlog usage example
|
||||
//
|
||||
#include "spdlog/spdlog.h"
|
||||
|
||||
#include <cstdlib> // EXIT_FAILURE
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
|
||||
void async_example();
|
||||
void syslog_example();
|
||||
|
||||
namespace spd = spdlog;
|
||||
int main(int, char*[])
|
||||
{
|
||||
try
|
||||
{
|
||||
// Multithreaded color console
|
||||
auto console = spd::stdout_logger_mt("console", true);
|
||||
console->info("Welcome to spdlog!");
|
||||
console->info("An info message example {}..", 1);
|
||||
console->info() << "Streams are supported too " << 1;
|
||||
|
||||
// Formatting examples
|
||||
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 floats {:03.2f}", 1.23456);
|
||||
console->info("Positional args are {1} {0}..", "too", "supported");
|
||||
|
||||
console->info("{:<30}", "left aligned");
|
||||
console->info("{:>30}", "right aligned");
|
||||
console->info("{:^30}", "centered");
|
||||
|
||||
spd::get("console")->info("loggers can be retrieved from a global registry using the spdlog::get(logger_name) function");
|
||||
|
||||
// Runtime log levels
|
||||
spd::set_level(spd::level::info); //Set global log level to info
|
||||
console->debug("This message shold not be displayed!");
|
||||
console->set_level(spd::level::debug); // Set specific logger's log level
|
||||
console->debug("This message shold be displayed..");
|
||||
|
||||
// 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);
|
||||
for (int i = 0; i < 10; ++i)
|
||||
file_logger->info("{} * {} equals {:>10}", i, i, i*i);
|
||||
|
||||
// Create a daily logger - a new file is created every day on 2:30am
|
||||
auto daily_logger = spd::daily_logger_mt("daily_logger", "logs/daily", 2, 30);
|
||||
|
||||
// Customize msg format for all messages
|
||||
spd::set_pattern("*** [%H:%M:%S %z] [thread %t] %v ***");
|
||||
file_logger->info("This is another message with custom format");
|
||||
|
||||
|
||||
// Compile time debug or trace macros.
|
||||
// Enabled #ifdef SPDLOG_DEBUG_ON or #ifdef SPDLOG_TRACE_ON
|
||||
SPDLOG_TRACE(console, "Enabled only #ifdef SPDLOG_TRACE_ON..{} ,{}", 1, 3.23);
|
||||
SPDLOG_DEBUG(console, "Enabled only #ifdef SPDLOG_DEBUG_ON.. {} ,{}", 1, 3.23);
|
||||
|
||||
// Asynchronous logging is very fast..
|
||||
// Just call spdlog::set_async_mode(q_size) and all created loggers from now on will be asynchronous..
|
||||
async_example();
|
||||
|
||||
// syslog example. linux/osx only..
|
||||
syslog_example();
|
||||
|
||||
|
||||
// Release and close all loggers
|
||||
spdlog::drop_all();
|
||||
}
|
||||
|
||||
catch (const spd::spdlog_ex& ex)
|
||||
{
|
||||
std::cout << "Log failed: " << ex.what() << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
void async_example()
|
||||
{
|
||||
size_t q_size = 4096; //queue size must be power of 2
|
||||
spdlog::set_async_mode(q_size);
|
||||
auto async_file = spd::daily_logger_st("async_file_logger", "logs/async_log.txt");
|
||||
for (int i = 0; i < 100; ++i)
|
||||
async_file->info("Async message #{}", i);
|
||||
}
|
||||
|
||||
//syslog example (linux/osx only)
|
||||
void syslog_example()
|
||||
{
|
||||
#if defined (__linux__) || defined(__APPLE__)
|
||||
std::string ident = "spdlog-example";
|
||||
auto syslog_logger = spd::syslog_logger("syslog", ident, LOG_PID);
|
||||
syslog_logger->warn("This is warning that will end up in syslog. This is Linux only!");
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
// Example of user defined class with operator<<
|
||||
class some_class {};
|
||||
std::ostream& operator<<(std::ostream& os, const some_class&)
|
||||
{
|
||||
return os << "some_class";
|
||||
}
|
||||
|
||||
void custom_class_example()
|
||||
{
|
||||
some_class c;
|
||||
spdlog::get("console")->info("custom class with operator<<: {}..", c);
|
||||
spdlog::get("console")->info() << "custom class with operator<<: " << c << "..";
|
||||
}
|
||||
|
||||
//
|
||||
// Copyright(c) 2015 Gabi Melman.
|
||||
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||
//
|
||||
//
|
||||
// spdlog usage example
|
||||
//
|
||||
#include "spdlog/spdlog.h"
|
||||
|
||||
#include <cstdlib> // EXIT_FAILURE
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
|
||||
void async_example();
|
||||
void syslog_example();
|
||||
|
||||
namespace spd = spdlog;
|
||||
int main(int, char*[])
|
||||
{
|
||||
try
|
||||
{
|
||||
// Multithreaded color console
|
||||
auto console = spd::stdout_logger_mt("console", true);
|
||||
console->info("Welcome to spdlog!");
|
||||
console->info("An info message example {}..", 1);
|
||||
console->info() << "Streams are supported too " << 1;
|
||||
|
||||
// Formatting examples
|
||||
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 floats {:03.2f}", 1.23456);
|
||||
console->info("Positional args are {1} {0}..", "too", "supported");
|
||||
|
||||
console->info("{:<30}", "left aligned");
|
||||
console->info("{:>30}", "right aligned");
|
||||
console->info("{:^30}", "centered");
|
||||
|
||||
spd::get("console")->info("loggers can be retrieved from a global registry using the spdlog::get(logger_name) function");
|
||||
|
||||
// Runtime log levels
|
||||
spd::set_level(spd::level::info); //Set global log level to info
|
||||
console->debug("This message shold not be displayed!");
|
||||
console->set_level(spd::level::debug); // Set specific logger's log level
|
||||
console->debug("This message shold be displayed..");
|
||||
|
||||
// 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);
|
||||
for (int i = 0; i < 10; ++i)
|
||||
file_logger->info("{} * {} equals {:>10}", i, i, i*i);
|
||||
|
||||
// Create a daily logger - a new file is created every day on 2:30am
|
||||
auto daily_logger = spd::daily_logger_mt("daily_logger", "logs/daily", 2, 30);
|
||||
|
||||
// Customize msg format for all messages
|
||||
spd::set_pattern("*** [%H:%M:%S %z] [thread %t] %v ***");
|
||||
file_logger->info("This is another message with custom format");
|
||||
|
||||
|
||||
// Compile time debug or trace macros.
|
||||
// Enabled #ifdef SPDLOG_DEBUG_ON or #ifdef SPDLOG_TRACE_ON
|
||||
SPDLOG_TRACE(console, "Enabled only #ifdef SPDLOG_TRACE_ON..{} ,{}", 1, 3.23);
|
||||
SPDLOG_DEBUG(console, "Enabled only #ifdef SPDLOG_DEBUG_ON.. {} ,{}", 1, 3.23);
|
||||
|
||||
// Asynchronous logging is very fast..
|
||||
// Just call spdlog::set_async_mode(q_size) and all created loggers from now on will be asynchronous..
|
||||
async_example();
|
||||
|
||||
// syslog example. linux/osx only..
|
||||
syslog_example();
|
||||
|
||||
|
||||
// Release and close all loggers
|
||||
spdlog::drop_all();
|
||||
}
|
||||
|
||||
catch (const spd::spdlog_ex& ex)
|
||||
{
|
||||
std::cout << "Log failed: " << ex.what() << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
void async_example()
|
||||
{
|
||||
size_t q_size = 4096; //queue size must be power of 2
|
||||
spdlog::set_async_mode(q_size);
|
||||
auto async_file = spd::daily_logger_st("async_file_logger", "logs/async_log.txt");
|
||||
for (int i = 0; i < 100; ++i)
|
||||
async_file->info("Async message #{}", i);
|
||||
}
|
||||
|
||||
//syslog example (linux/osx only)
|
||||
void syslog_example()
|
||||
{
|
||||
#if defined (__linux__) || defined(__APPLE__)
|
||||
std::string ident = "spdlog-example";
|
||||
auto syslog_logger = spd::syslog_logger("syslog", ident, LOG_PID);
|
||||
syslog_logger->warn("This is warning that will end up in syslog. This is Linux only!");
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
// Example of user defined class with operator<<
|
||||
class some_class {};
|
||||
std::ostream& operator<<(std::ostream& os, const some_class&)
|
||||
{
|
||||
return os << "some_class";
|
||||
}
|
||||
|
||||
void custom_class_example()
|
||||
{
|
||||
some_class c;
|
||||
spdlog::get("console")->info("custom class with operator<<: {}..", c);
|
||||
spdlog::get("console")->info() << "custom class with operator<<: " << c << "..";
|
||||
}
|
||||
|
||||
|
@ -1,74 +1,74 @@
|
||||
//
|
||||
// Copyright(c) 2015 Gabi Melman.
|
||||
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
// 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.
|
||||
// Creates a single back thread to pop messages from the queue and log them.
|
||||
//
|
||||
// Upon each log write the logger:
|
||||
// 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)
|
||||
// 3. will throw spdlog_ex upon log exceptions
|
||||
// Upong destruction, logs all remaining messages in the queue before destructing..
|
||||
|
||||
#include <spdlog/common.h>
|
||||
#include <spdlog/logger.h>
|
||||
|
||||
#include <chrono>
|
||||
#include <functional>
|
||||
#include <string>
|
||||
#include <memory>
|
||||
|
||||
namespace spdlog
|
||||
{
|
||||
|
||||
namespace details
|
||||
{
|
||||
class async_log_helper;
|
||||
}
|
||||
|
||||
class async_logger :public logger
|
||||
{
|
||||
public:
|
||||
template<class It>
|
||||
async_logger(const std::string& name,
|
||||
const It& begin,
|
||||
const It& end,
|
||||
size_t queue_size,
|
||||
const async_overflow_policy overflow_policy = async_overflow_policy::block_retry,
|
||||
const std::function<void()>& worker_warmup_cb = nullptr,
|
||||
const std::chrono::milliseconds& flush_interval_ms = std::chrono::milliseconds::zero());
|
||||
|
||||
async_logger(const std::string& logger_name,
|
||||
sinks_init_list sinks,
|
||||
size_t queue_size,
|
||||
const async_overflow_policy overflow_policy = async_overflow_policy::block_retry,
|
||||
const std::function<void()>& worker_warmup_cb = nullptr,
|
||||
const std::chrono::milliseconds& flush_interval_ms = std::chrono::milliseconds::zero());
|
||||
|
||||
async_logger(const std::string& logger_name,
|
||||
sink_ptr single_sink,
|
||||
size_t queue_size,
|
||||
const async_overflow_policy overflow_policy = async_overflow_policy::block_retry,
|
||||
const std::function<void()>& worker_warmup_cb = nullptr,
|
||||
const std::chrono::milliseconds& flush_interval_ms = std::chrono::milliseconds::zero());
|
||||
|
||||
|
||||
void flush() override;
|
||||
protected:
|
||||
void _log_msg(details::log_msg& msg) override;
|
||||
void _set_formatter(spdlog::formatter_ptr msg_formatter) override;
|
||||
void _set_pattern(const std::string& pattern) override;
|
||||
|
||||
private:
|
||||
std::unique_ptr<details::async_log_helper> _async_log_helper;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
#include <spdlog/details/async_logger_impl.h>
|
||||
|
||||
//
|
||||
// Copyright(c) 2015 Gabi Melman.
|
||||
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
// 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.
|
||||
// Creates a single back thread to pop messages from the queue and log them.
|
||||
//
|
||||
// Upon each log write the logger:
|
||||
// 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)
|
||||
// 3. will throw spdlog_ex upon log exceptions
|
||||
// Upong destruction, logs all remaining messages in the queue before destructing..
|
||||
|
||||
#include <spdlog/common.h>
|
||||
#include <spdlog/logger.h>
|
||||
|
||||
#include <chrono>
|
||||
#include <functional>
|
||||
#include <string>
|
||||
#include <memory>
|
||||
|
||||
namespace spdlog
|
||||
{
|
||||
|
||||
namespace details
|
||||
{
|
||||
class async_log_helper;
|
||||
}
|
||||
|
||||
class async_logger :public logger
|
||||
{
|
||||
public:
|
||||
template<class It>
|
||||
async_logger(const std::string& name,
|
||||
const It& begin,
|
||||
const It& end,
|
||||
size_t queue_size,
|
||||
const async_overflow_policy overflow_policy = async_overflow_policy::block_retry,
|
||||
const std::function<void()>& worker_warmup_cb = nullptr,
|
||||
const std::chrono::milliseconds& flush_interval_ms = std::chrono::milliseconds::zero());
|
||||
|
||||
async_logger(const std::string& logger_name,
|
||||
sinks_init_list sinks,
|
||||
size_t queue_size,
|
||||
const async_overflow_policy overflow_policy = async_overflow_policy::block_retry,
|
||||
const std::function<void()>& worker_warmup_cb = nullptr,
|
||||
const std::chrono::milliseconds& flush_interval_ms = std::chrono::milliseconds::zero());
|
||||
|
||||
async_logger(const std::string& logger_name,
|
||||
sink_ptr single_sink,
|
||||
size_t queue_size,
|
||||
const async_overflow_policy overflow_policy = async_overflow_policy::block_retry,
|
||||
const std::function<void()>& worker_warmup_cb = nullptr,
|
||||
const std::chrono::milliseconds& flush_interval_ms = std::chrono::milliseconds::zero());
|
||||
|
||||
|
||||
void flush() override;
|
||||
protected:
|
||||
void _log_msg(details::log_msg& msg) override;
|
||||
void _set_formatter(spdlog::formatter_ptr msg_formatter) override;
|
||||
void _set_pattern(const std::string& pattern) override;
|
||||
|
||||
private:
|
||||
std::unique_ptr<details::async_log_helper> _async_log_helper;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
#include <spdlog/details/async_logger_impl.h>
|
||||
|
||||
|
@ -1,130 +1,130 @@
|
||||
//
|
||||
// Copyright(c) 2015 Gabi Melman.
|
||||
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
#include <string>
|
||||
#include <initializer_list>
|
||||
#include <chrono>
|
||||
#include <memory>
|
||||
#include <atomic>
|
||||
#include <exception>
|
||||
#if defined(_WIN32) && defined(SPDLOG_WCHAR_FILENAMES)
|
||||
#include <codecvt>
|
||||
#include <locale>
|
||||
#endif
|
||||
|
||||
#include <spdlog/details/null_mutex.h>
|
||||
|
||||
//visual studio does not support noexcept yet
|
||||
#ifndef _MSC_VER
|
||||
#define SPDLOG_NOEXCEPT noexcept
|
||||
#else
|
||||
#define SPDLOG_NOEXCEPT throw()
|
||||
#endif
|
||||
|
||||
namespace spdlog
|
||||
{
|
||||
|
||||
class formatter;
|
||||
|
||||
namespace sinks
|
||||
{
|
||||
class sink;
|
||||
}
|
||||
|
||||
// Common types across the lib
|
||||
using log_clock = std::chrono::system_clock;
|
||||
using sink_ptr = std::shared_ptr < sinks::sink >;
|
||||
using sinks_init_list = std::initializer_list < sink_ptr >;
|
||||
using formatter_ptr = std::shared_ptr<spdlog::formatter>;
|
||||
#if defined(SPDLOG_NO_ATOMIC_LEVELS)
|
||||
using level_t = details::null_atomic_int;
|
||||
#else
|
||||
using level_t = std::atomic_int;
|
||||
#endif
|
||||
|
||||
//Log level enum
|
||||
namespace level
|
||||
{
|
||||
typedef enum
|
||||
{
|
||||
trace = 0,
|
||||
debug = 1,
|
||||
info = 2,
|
||||
notice = 3,
|
||||
warn = 4,
|
||||
err = 5,
|
||||
critical = 6,
|
||||
alert = 7,
|
||||
emerg = 8,
|
||||
off = 9
|
||||
} level_enum;
|
||||
|
||||
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"};
|
||||
|
||||
inline const char* to_str(spdlog::level::level_enum l)
|
||||
{
|
||||
return level_names[l];
|
||||
}
|
||||
|
||||
inline const char* to_short_str(spdlog::level::level_enum l)
|
||||
{
|
||||
return short_level_names[l];
|
||||
}
|
||||
} //level
|
||||
|
||||
|
||||
//
|
||||
// Async overflow policy - block by default.
|
||||
//
|
||||
enum class async_overflow_policy
|
||||
{
|
||||
block_retry, // Block / yield / sleep until message can be enqueued
|
||||
discard_log_msg // Discard the message it enqueue fails
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// Log exception
|
||||
//
|
||||
class spdlog_ex : public std::exception
|
||||
{
|
||||
public:
|
||||
spdlog_ex(const std::string& msg) :_msg(msg) {}
|
||||
const char* what() const SPDLOG_NOEXCEPT override
|
||||
{
|
||||
return _msg.c_str();
|
||||
}
|
||||
private:
|
||||
std::string _msg;
|
||||
|
||||
};
|
||||
|
||||
//
|
||||
// wchar support for windows file names (SPDLOG_WCHAR_FILENAMES must be defined)
|
||||
//
|
||||
#if defined(_WIN32) && defined(SPDLOG_WCHAR_FILENAMES)
|
||||
#define SPDLOG_FILENAME_T(s) L ## s
|
||||
using filename_t = std::wstring;
|
||||
inline std::string filename_to_str(const filename_t& filename)
|
||||
{
|
||||
std::wstring_convert<std::codecvt_utf8<wchar_t>, wchar_t> c;
|
||||
return c.to_bytes(filename);
|
||||
}
|
||||
#else
|
||||
#define SPDLOG_FILENAME_T(s) s
|
||||
using filename_t = std::string;
|
||||
|
||||
inline std::string filename_to_str(const filename_t& filename)
|
||||
{
|
||||
return filename;
|
||||
}
|
||||
#endif
|
||||
|
||||
} //spdlog
|
||||
//
|
||||
// Copyright(c) 2015 Gabi Melman.
|
||||
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
#include <string>
|
||||
#include <initializer_list>
|
||||
#include <chrono>
|
||||
#include <memory>
|
||||
#include <atomic>
|
||||
#include <exception>
|
||||
#if defined(_WIN32) && defined(SPDLOG_WCHAR_FILENAMES)
|
||||
#include <codecvt>
|
||||
#include <locale>
|
||||
#endif
|
||||
|
||||
#include <spdlog/details/null_mutex.h>
|
||||
|
||||
//visual studio does not support noexcept yet
|
||||
#ifndef _MSC_VER
|
||||
#define SPDLOG_NOEXCEPT noexcept
|
||||
#else
|
||||
#define SPDLOG_NOEXCEPT throw()
|
||||
#endif
|
||||
|
||||
namespace spdlog
|
||||
{
|
||||
|
||||
class formatter;
|
||||
|
||||
namespace sinks
|
||||
{
|
||||
class sink;
|
||||
}
|
||||
|
||||
// Common types across the lib
|
||||
using log_clock = std::chrono::system_clock;
|
||||
using sink_ptr = std::shared_ptr < sinks::sink >;
|
||||
using sinks_init_list = std::initializer_list < sink_ptr >;
|
||||
using formatter_ptr = std::shared_ptr<spdlog::formatter>;
|
||||
#if defined(SPDLOG_NO_ATOMIC_LEVELS)
|
||||
using level_t = details::null_atomic_int;
|
||||
#else
|
||||
using level_t = std::atomic_int;
|
||||
#endif
|
||||
|
||||
//Log level enum
|
||||
namespace level
|
||||
{
|
||||
typedef enum
|
||||
{
|
||||
trace = 0,
|
||||
debug = 1,
|
||||
info = 2,
|
||||
notice = 3,
|
||||
warn = 4,
|
||||
err = 5,
|
||||
critical = 6,
|
||||
alert = 7,
|
||||
emerg = 8,
|
||||
off = 9
|
||||
} level_enum;
|
||||
|
||||
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"};
|
||||
|
||||
inline const char* to_str(spdlog::level::level_enum l)
|
||||
{
|
||||
return level_names[l];
|
||||
}
|
||||
|
||||
inline const char* to_short_str(spdlog::level::level_enum l)
|
||||
{
|
||||
return short_level_names[l];
|
||||
}
|
||||
} //level
|
||||
|
||||
|
||||
//
|
||||
// Async overflow policy - block by default.
|
||||
//
|
||||
enum class async_overflow_policy
|
||||
{
|
||||
block_retry, // Block / yield / sleep until message can be enqueued
|
||||
discard_log_msg // Discard the message it enqueue fails
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// Log exception
|
||||
//
|
||||
class spdlog_ex : public std::exception
|
||||
{
|
||||
public:
|
||||
spdlog_ex(const std::string& msg) :_msg(msg) {}
|
||||
const char* what() const SPDLOG_NOEXCEPT override
|
||||
{
|
||||
return _msg.c_str();
|
||||
}
|
||||
private:
|
||||
std::string _msg;
|
||||
|
||||
};
|
||||
|
||||
//
|
||||
// wchar support for windows file names (SPDLOG_WCHAR_FILENAMES must be defined)
|
||||
//
|
||||
#if defined(_WIN32) && defined(SPDLOG_WCHAR_FILENAMES)
|
||||
#define SPDLOG_FILENAME_T(s) L ## s
|
||||
using filename_t = std::wstring;
|
||||
inline std::string filename_to_str(const filename_t& filename)
|
||||
{
|
||||
std::wstring_convert<std::codecvt_utf8<wchar_t>, wchar_t> c;
|
||||
return c.to_bytes(filename);
|
||||
}
|
||||
#else
|
||||
#define SPDLOG_FILENAME_T(s) s
|
||||
using filename_t = std::string;
|
||||
|
||||
inline std::string filename_to_str(const filename_t& filename)
|
||||
{
|
||||
return filename;
|
||||
}
|
||||
#endif
|
||||
|
||||
} //spdlog
|
||||
|
@ -1,368 +1,368 @@
|
||||
//
|
||||
// Copyright(c) 2015 Gabi Melman.
|
||||
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||
//
|
||||
|
||||
// async log helper :
|
||||
// Process logs asynchronously using a back thread.
|
||||
//
|
||||
// If the internal queue of log messages reaches its max size,
|
||||
// then the client call will block until there is more room.
|
||||
//
|
||||
// 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
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <spdlog/common.h>
|
||||
#include <spdlog/sinks/sink.h>
|
||||
#include <spdlog/details/mpmc_bounded_q.h>
|
||||
#include <spdlog/details/log_msg.h>
|
||||
#include <spdlog/details/os.h>
|
||||
#include <spdlog/formatter.h>
|
||||
|
||||
#include <chrono>
|
||||
#include <exception>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace spdlog
|
||||
{
|
||||
namespace details
|
||||
{
|
||||
|
||||
class async_log_helper
|
||||
{
|
||||
// Async msg to move to/from the queue
|
||||
// Movable only. should never be copied
|
||||
enum class async_msg_type
|
||||
{
|
||||
log,
|
||||
flush,
|
||||
terminate
|
||||
};
|
||||
struct async_msg
|
||||
{
|
||||
std::string logger_name;
|
||||
level::level_enum level;
|
||||
log_clock::time_point time;
|
||||
size_t thread_id;
|
||||
std::string txt;
|
||||
async_msg_type msg_type;
|
||||
|
||||
async_msg() = default;
|
||||
~async_msg() = default;
|
||||
|
||||
|
||||
async_msg(async_msg&& other) SPDLOG_NOEXCEPT:
|
||||
logger_name(std::move(other.logger_name)),
|
||||
level(std::move(other.level)),
|
||||
time(std::move(other.time)),
|
||||
txt(std::move(other.txt)),
|
||||
msg_type(std::move(other.msg_type))
|
||||
{}
|
||||
|
||||
async_msg(async_msg_type m_type) :msg_type(m_type)
|
||||
{};
|
||||
|
||||
async_msg& operator=(async_msg&& other) SPDLOG_NOEXCEPT
|
||||
{
|
||||
logger_name = std::move(other.logger_name);
|
||||
level = other.level;
|
||||
time = std::move(other.time);
|
||||
thread_id = other.thread_id;
|
||||
txt = std::move(other.txt);
|
||||
msg_type = other.msg_type;
|
||||
return *this;
|
||||
}
|
||||
|
||||
// never copy or assign. should only be moved..
|
||||
async_msg(const async_msg&) = delete;
|
||||
async_msg& operator=(async_msg& other) = delete;
|
||||
|
||||
// construct from log_msg
|
||||
async_msg(const details::log_msg& m) :
|
||||
logger_name(m.logger_name),
|
||||
level(m.level),
|
||||
time(m.time),
|
||||
thread_id(m.thread_id),
|
||||
txt(m.raw.data(), m.raw.size()),
|
||||
msg_type(async_msg_type::log)
|
||||
{}
|
||||
|
||||
|
||||
|
||||
// copy into log_msg
|
||||
void fill_log_msg(log_msg &msg)
|
||||
{
|
||||
msg.clear();
|
||||
msg.logger_name = logger_name;
|
||||
msg.level = level;
|
||||
msg.time = time;
|
||||
msg.thread_id = thread_id;
|
||||
msg.raw << txt;
|
||||
}
|
||||
};
|
||||
|
||||
public:
|
||||
|
||||
using item_type = async_msg;
|
||||
using q_type = details::mpmc_bounded_queue<item_type>;
|
||||
|
||||
using clock = std::chrono::steady_clock;
|
||||
|
||||
|
||||
async_log_helper(formatter_ptr formatter,
|
||||
const std::vector<sink_ptr>& sinks,
|
||||
size_t queue_size,
|
||||
const async_overflow_policy overflow_policy = async_overflow_policy::block_retry,
|
||||
const std::function<void()>& worker_warmup_cb = nullptr,
|
||||
const std::chrono::milliseconds& flush_interval_ms = std::chrono::milliseconds::zero());
|
||||
|
||||
void log(const details::log_msg& msg);
|
||||
|
||||
// stop logging and join the back thread
|
||||
~async_log_helper();
|
||||
|
||||
void set_formatter(formatter_ptr);
|
||||
|
||||
void flush();
|
||||
|
||||
|
||||
private:
|
||||
formatter_ptr _formatter;
|
||||
std::vector<std::shared_ptr<sinks::sink>> _sinks;
|
||||
|
||||
// queue of messages to log
|
||||
q_type _q;
|
||||
|
||||
bool _flush_requested;
|
||||
|
||||
bool _terminate_requested;
|
||||
|
||||
|
||||
// last exception thrown from the worker thread
|
||||
std::shared_ptr<spdlog_ex> _last_workerthread_ex;
|
||||
|
||||
// overflow policy
|
||||
const async_overflow_policy _overflow_policy;
|
||||
|
||||
// worker thread warmup callback - one can set thread priority, affinity, etc
|
||||
const std::function<void()> _worker_warmup_cb;
|
||||
|
||||
// auto periodic sink flush parameter
|
||||
const std::chrono::milliseconds _flush_interval_ms;
|
||||
|
||||
// worker thread
|
||||
std::thread _worker_thread;
|
||||
|
||||
void push_msg(async_msg&& new_msg);
|
||||
// throw last worker thread exception or if worker thread is not active
|
||||
|
||||
void throw_if_bad_worker();
|
||||
|
||||
// worker thread main loop
|
||||
void worker_loop();
|
||||
|
||||
// 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
|
||||
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);
|
||||
|
||||
// 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);
|
||||
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// async_sink class implementation
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
inline spdlog::details::async_log_helper::async_log_helper(
|
||||
formatter_ptr formatter,
|
||||
const std::vector<sink_ptr>& sinks,
|
||||
size_t queue_size,
|
||||
const async_overflow_policy overflow_policy,
|
||||
const std::function<void()>& worker_warmup_cb,
|
||||
const std::chrono::milliseconds& flush_interval_ms):
|
||||
_formatter(formatter),
|
||||
_sinks(sinks),
|
||||
_q(queue_size),
|
||||
_flush_requested(false),
|
||||
_terminate_requested(false),
|
||||
_overflow_policy(overflow_policy),
|
||||
_worker_warmup_cb(worker_warmup_cb),
|
||||
_flush_interval_ms(flush_interval_ms),
|
||||
_worker_thread(&async_log_helper::worker_loop, this)
|
||||
{}
|
||||
|
||||
// Send to the worker thread termination message(level=off)
|
||||
// and wait for it to finish gracefully
|
||||
inline spdlog::details::async_log_helper::~async_log_helper()
|
||||
{
|
||||
try
|
||||
{
|
||||
push_msg(async_msg(async_msg_type::terminate));
|
||||
_worker_thread.join();
|
||||
}
|
||||
catch (...) // don't crash in destructor
|
||||
{}
|
||||
}
|
||||
|
||||
|
||||
//Try to push and block until succeeded
|
||||
inline void spdlog::details::async_log_helper::log(const details::log_msg& msg)
|
||||
{
|
||||
push_msg(async_msg(msg));
|
||||
|
||||
|
||||
}
|
||||
|
||||
//Try to push and block until succeeded
|
||||
inline void spdlog::details::async_log_helper::push_msg(details::async_log_helper::async_msg&& new_msg)
|
||||
{
|
||||
throw_if_bad_worker();
|
||||
if (!_q.enqueue(std::move(new_msg)) && _overflow_policy != async_overflow_policy::discard_log_msg)
|
||||
{
|
||||
auto last_op_time = details::os::now();
|
||||
auto now = last_op_time;
|
||||
do
|
||||
{
|
||||
now = details::os::now();
|
||||
sleep_or_yield(now, last_op_time);
|
||||
}
|
||||
while (!_q.enqueue(std::move(new_msg)));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
inline void spdlog::details::async_log_helper::flush()
|
||||
{
|
||||
push_msg(async_msg(async_msg_type::flush));
|
||||
}
|
||||
|
||||
inline void spdlog::details::async_log_helper::worker_loop()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (_worker_warmup_cb) _worker_warmup_cb();
|
||||
auto last_pop = details::os::now();
|
||||
auto last_flush = last_pop;
|
||||
while(process_next_msg(last_pop, last_flush));
|
||||
}
|
||||
catch (const std::exception& ex)
|
||||
{
|
||||
_last_workerthread_ex = std::make_shared<spdlog_ex>(std::string("async_logger worker thread exception: ") + ex.what());
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
_last_workerthread_ex = std::make_shared<spdlog_ex>("async_logger worker thread exception");
|
||||
}
|
||||
}
|
||||
|
||||
// process next message in the queue
|
||||
// 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)
|
||||
{
|
||||
|
||||
async_msg incoming_async_msg;
|
||||
log_msg incoming_log_msg;
|
||||
|
||||
if (_q.dequeue(incoming_async_msg))
|
||||
{
|
||||
last_pop = details::os::now();
|
||||
switch (incoming_async_msg.msg_type)
|
||||
{
|
||||
case async_msg_type::flush:
|
||||
_flush_requested = true;
|
||||
break;
|
||||
|
||||
case async_msg_type::terminate:
|
||||
_flush_requested = true;
|
||||
_terminate_requested = true;
|
||||
break;
|
||||
|
||||
default:
|
||||
incoming_async_msg.fill_log_msg(incoming_log_msg);
|
||||
_formatter->format(incoming_log_msg);
|
||||
for (auto &s : _sinks)
|
||||
s->log(incoming_log_msg);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Handle empty queue..
|
||||
// This is the only place where the queue can terminate or flush to avoid losing messages already in the queue
|
||||
else
|
||||
{
|
||||
auto now = details::os::now();
|
||||
handle_flush_interval(now, last_flush);
|
||||
sleep_or_yield(now, last_pop);
|
||||
return !_terminate_requested;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
if (should_flush)
|
||||
{
|
||||
for (auto &s : _sinks)
|
||||
s->flush();
|
||||
now = last_flush = details::os::now();
|
||||
_flush_requested = false;
|
||||
}
|
||||
}
|
||||
inline void spdlog::details::async_log_helper::set_formatter(formatter_ptr msg_formatter)
|
||||
{
|
||||
_formatter = msg_formatter;
|
||||
}
|
||||
|
||||
|
||||
// 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)
|
||||
{
|
||||
using std::chrono::milliseconds;
|
||||
using namespace std::this_thread;
|
||||
|
||||
auto time_since_op = now - last_op_time;
|
||||
|
||||
// spin upto 1 ms
|
||||
if (time_since_op <= milliseconds(1))
|
||||
return;
|
||||
|
||||
// yield upto 10ms
|
||||
if (time_since_op <= milliseconds(10))
|
||||
return yield();
|
||||
|
||||
|
||||
// sleep for half of duration since last op
|
||||
if (time_since_op <= milliseconds(100))
|
||||
return sleep_for(time_since_op / 2);
|
||||
|
||||
return sleep_for(milliseconds(100));
|
||||
}
|
||||
|
||||
// throw if the worker thread threw an exception or not active
|
||||
inline void spdlog::details::async_log_helper::throw_if_bad_worker()
|
||||
{
|
||||
if (_last_workerthread_ex)
|
||||
{
|
||||
auto ex = std::move(_last_workerthread_ex);
|
||||
throw *ex;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//
|
||||
// Copyright(c) 2015 Gabi Melman.
|
||||
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||
//
|
||||
|
||||
// async log helper :
|
||||
// Process logs asynchronously using a back thread.
|
||||
//
|
||||
// If the internal queue of log messages reaches its max size,
|
||||
// then the client call will block until there is more room.
|
||||
//
|
||||
// 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
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <spdlog/common.h>
|
||||
#include <spdlog/sinks/sink.h>
|
||||
#include <spdlog/details/mpmc_bounded_q.h>
|
||||
#include <spdlog/details/log_msg.h>
|
||||
#include <spdlog/details/os.h>
|
||||
#include <spdlog/formatter.h>
|
||||
|
||||
#include <chrono>
|
||||
#include <exception>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace spdlog
|
||||
{
|
||||
namespace details
|
||||
{
|
||||
|
||||
class async_log_helper
|
||||
{
|
||||
// Async msg to move to/from the queue
|
||||
// Movable only. should never be copied
|
||||
enum class async_msg_type
|
||||
{
|
||||
log,
|
||||
flush,
|
||||
terminate
|
||||
};
|
||||
struct async_msg
|
||||
{
|
||||
std::string logger_name;
|
||||
level::level_enum level;
|
||||
log_clock::time_point time;
|
||||
size_t thread_id;
|
||||
std::string txt;
|
||||
async_msg_type msg_type;
|
||||
|
||||
async_msg() = default;
|
||||
~async_msg() = default;
|
||||
|
||||
|
||||
async_msg(async_msg&& other) SPDLOG_NOEXCEPT:
|
||||
logger_name(std::move(other.logger_name)),
|
||||
level(std::move(other.level)),
|
||||
time(std::move(other.time)),
|
||||
txt(std::move(other.txt)),
|
||||
msg_type(std::move(other.msg_type))
|
||||
{}
|
||||
|
||||
async_msg(async_msg_type m_type) :msg_type(m_type)
|
||||
{};
|
||||
|
||||
async_msg& operator=(async_msg&& other) SPDLOG_NOEXCEPT
|
||||
{
|
||||
logger_name = std::move(other.logger_name);
|
||||
level = other.level;
|
||||
time = std::move(other.time);
|
||||
thread_id = other.thread_id;
|
||||
txt = std::move(other.txt);
|
||||
msg_type = other.msg_type;
|
||||
return *this;
|
||||
}
|
||||
|
||||
// never copy or assign. should only be moved..
|
||||
async_msg(const async_msg&) = delete;
|
||||
async_msg& operator=(async_msg& other) = delete;
|
||||
|
||||
// construct from log_msg
|
||||
async_msg(const details::log_msg& m) :
|
||||
logger_name(m.logger_name),
|
||||
level(m.level),
|
||||
time(m.time),
|
||||
thread_id(m.thread_id),
|
||||
txt(m.raw.data(), m.raw.size()),
|
||||
msg_type(async_msg_type::log)
|
||||
{}
|
||||
|
||||
|
||||
|
||||
// copy into log_msg
|
||||
void fill_log_msg(log_msg &msg)
|
||||
{
|
||||
msg.clear();
|
||||
msg.logger_name = logger_name;
|
||||
msg.level = level;
|
||||
msg.time = time;
|
||||
msg.thread_id = thread_id;
|
||||
msg.raw << txt;
|
||||
}
|
||||
};
|
||||
|
||||
public:
|
||||
|
||||
using item_type = async_msg;
|
||||
using q_type = details::mpmc_bounded_queue<item_type>;
|
||||
|
||||
using clock = std::chrono::steady_clock;
|
||||
|
||||
|
||||
async_log_helper(formatter_ptr formatter,
|
||||
const std::vector<sink_ptr>& sinks,
|
||||
size_t queue_size,
|
||||
const async_overflow_policy overflow_policy = async_overflow_policy::block_retry,
|
||||
const std::function<void()>& worker_warmup_cb = nullptr,
|
||||
const std::chrono::milliseconds& flush_interval_ms = std::chrono::milliseconds::zero());
|
||||
|
||||
void log(const details::log_msg& msg);
|
||||
|
||||
// stop logging and join the back thread
|
||||
~async_log_helper();
|
||||
|
||||
void set_formatter(formatter_ptr);
|
||||
|
||||
void flush();
|
||||
|
||||
|
||||
private:
|
||||
formatter_ptr _formatter;
|
||||
std::vector<std::shared_ptr<sinks::sink>> _sinks;
|
||||
|
||||
// queue of messages to log
|
||||
q_type _q;
|
||||
|
||||
bool _flush_requested;
|
||||
|
||||
bool _terminate_requested;
|
||||
|
||||
|
||||
// last exception thrown from the worker thread
|
||||
std::shared_ptr<spdlog_ex> _last_workerthread_ex;
|
||||
|
||||
// overflow policy
|
||||
const async_overflow_policy _overflow_policy;
|
||||
|
||||
// worker thread warmup callback - one can set thread priority, affinity, etc
|
||||
const std::function<void()> _worker_warmup_cb;
|
||||
|
||||
// auto periodic sink flush parameter
|
||||
const std::chrono::milliseconds _flush_interval_ms;
|
||||
|
||||
// worker thread
|
||||
std::thread _worker_thread;
|
||||
|
||||
void push_msg(async_msg&& new_msg);
|
||||
// throw last worker thread exception or if worker thread is not active
|
||||
|
||||
void throw_if_bad_worker();
|
||||
|
||||
// worker thread main loop
|
||||
void worker_loop();
|
||||
|
||||
// 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
|
||||
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);
|
||||
|
||||
// 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);
|
||||
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// async_sink class implementation
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
inline spdlog::details::async_log_helper::async_log_helper(
|
||||
formatter_ptr formatter,
|
||||
const std::vector<sink_ptr>& sinks,
|
||||
size_t queue_size,
|
||||
const async_overflow_policy overflow_policy,
|
||||
const std::function<void()>& worker_warmup_cb,
|
||||
const std::chrono::milliseconds& flush_interval_ms):
|
||||
_formatter(formatter),
|
||||
_sinks(sinks),
|
||||
_q(queue_size),
|
||||
_flush_requested(false),
|
||||
_terminate_requested(false),
|
||||
_overflow_policy(overflow_policy),
|
||||
_worker_warmup_cb(worker_warmup_cb),
|
||||
_flush_interval_ms(flush_interval_ms),
|
||||
_worker_thread(&async_log_helper::worker_loop, this)
|
||||
{}
|
||||
|
||||
// Send to the worker thread termination message(level=off)
|
||||
// and wait for it to finish gracefully
|
||||
inline spdlog::details::async_log_helper::~async_log_helper()
|
||||
{
|
||||
try
|
||||
{
|
||||
push_msg(async_msg(async_msg_type::terminate));
|
||||
_worker_thread.join();
|
||||
}
|
||||
catch (...) // don't crash in destructor
|
||||
{}
|
||||
}
|
||||
|
||||
|
||||
//Try to push and block until succeeded
|
||||
inline void spdlog::details::async_log_helper::log(const details::log_msg& msg)
|
||||
{
|
||||
push_msg(async_msg(msg));
|
||||
|
||||
|
||||
}
|
||||
|
||||
//Try to push and block until succeeded
|
||||
inline void spdlog::details::async_log_helper::push_msg(details::async_log_helper::async_msg&& new_msg)
|
||||
{
|
||||
throw_if_bad_worker();
|
||||
if (!_q.enqueue(std::move(new_msg)) && _overflow_policy != async_overflow_policy::discard_log_msg)
|
||||
{
|
||||
auto last_op_time = details::os::now();
|
||||
auto now = last_op_time;
|
||||
do
|
||||
{
|
||||
now = details::os::now();
|
||||
sleep_or_yield(now, last_op_time);
|
||||
}
|
||||
while (!_q.enqueue(std::move(new_msg)));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
inline void spdlog::details::async_log_helper::flush()
|
||||
{
|
||||
push_msg(async_msg(async_msg_type::flush));
|
||||
}
|
||||
|
||||
inline void spdlog::details::async_log_helper::worker_loop()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (_worker_warmup_cb) _worker_warmup_cb();
|
||||
auto last_pop = details::os::now();
|
||||
auto last_flush = last_pop;
|
||||
while(process_next_msg(last_pop, last_flush));
|
||||
}
|
||||
catch (const std::exception& ex)
|
||||
{
|
||||
_last_workerthread_ex = std::make_shared<spdlog_ex>(std::string("async_logger worker thread exception: ") + ex.what());
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
_last_workerthread_ex = std::make_shared<spdlog_ex>("async_logger worker thread exception");
|
||||
}
|
||||
}
|
||||
|
||||
// process next message in the queue
|
||||
// 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)
|
||||
{
|
||||
|
||||
async_msg incoming_async_msg;
|
||||
log_msg incoming_log_msg;
|
||||
|
||||
if (_q.dequeue(incoming_async_msg))
|
||||
{
|
||||
last_pop = details::os::now();
|
||||
switch (incoming_async_msg.msg_type)
|
||||
{
|
||||
case async_msg_type::flush:
|
||||
_flush_requested = true;
|
||||
break;
|
||||
|
||||
case async_msg_type::terminate:
|
||||
_flush_requested = true;
|
||||
_terminate_requested = true;
|
||||
break;
|
||||
|
||||
default:
|
||||
incoming_async_msg.fill_log_msg(incoming_log_msg);
|
||||
_formatter->format(incoming_log_msg);
|
||||
for (auto &s : _sinks)
|
||||
s->log(incoming_log_msg);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Handle empty queue..
|
||||
// This is the only place where the queue can terminate or flush to avoid losing messages already in the queue
|
||||
else
|
||||
{
|
||||
auto now = details::os::now();
|
||||
handle_flush_interval(now, last_flush);
|
||||
sleep_or_yield(now, last_pop);
|
||||
return !_terminate_requested;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
if (should_flush)
|
||||
{
|
||||
for (auto &s : _sinks)
|
||||
s->flush();
|
||||
now = last_flush = details::os::now();
|
||||
_flush_requested = false;
|
||||
}
|
||||
}
|
||||
inline void spdlog::details::async_log_helper::set_formatter(formatter_ptr msg_formatter)
|
||||
{
|
||||
_formatter = msg_formatter;
|
||||
}
|
||||
|
||||
|
||||
// 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)
|
||||
{
|
||||
using std::chrono::milliseconds;
|
||||
using namespace std::this_thread;
|
||||
|
||||
auto time_since_op = now - last_op_time;
|
||||
|
||||
// spin upto 1 ms
|
||||
if (time_since_op <= milliseconds(1))
|
||||
return;
|
||||
|
||||
// yield upto 10ms
|
||||
if (time_since_op <= milliseconds(10))
|
||||
return yield();
|
||||
|
||||
|
||||
// sleep for half of duration since last op
|
||||
if (time_since_op <= milliseconds(100))
|
||||
return sleep_for(time_since_op / 2);
|
||||
|
||||
return sleep_for(milliseconds(100));
|
||||
}
|
||||
|
||||
// throw if the worker thread threw an exception or not active
|
||||
inline void spdlog::details::async_log_helper::throw_if_bad_worker()
|
||||
{
|
||||
if (_last_workerthread_ex)
|
||||
{
|
||||
auto ex = std::move(_last_workerthread_ex);
|
||||
throw *ex;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -1,74 +1,74 @@
|
||||
//
|
||||
// Copyright(c) 2015 Gabi Melman.
|
||||
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
// Async Logger implementation
|
||||
// Use an async_sink (queue per logger) to perform the logging in a worker thread
|
||||
|
||||
#include <spdlog/details/async_log_helper.h>
|
||||
#include <spdlog/async_logger.h>
|
||||
|
||||
#include <string>
|
||||
#include <functional>
|
||||
#include <chrono>
|
||||
#include <memory>
|
||||
|
||||
template<class It>
|
||||
inline spdlog::async_logger::async_logger(const std::string& logger_name,
|
||||
const It& begin,
|
||||
const It& end,
|
||||
size_t queue_size,
|
||||
const async_overflow_policy overflow_policy,
|
||||
const std::function<void()>& worker_warmup_cb,
|
||||
const std::chrono::milliseconds& flush_interval_ms) :
|
||||
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))
|
||||
{
|
||||
}
|
||||
|
||||
inline spdlog::async_logger::async_logger(const std::string& logger_name,
|
||||
sinks_init_list sinks,
|
||||
size_t queue_size,
|
||||
const async_overflow_policy overflow_policy,
|
||||
const std::function<void()>& worker_warmup_cb,
|
||||
const std::chrono::milliseconds& flush_interval_ms) :
|
||||
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,
|
||||
sink_ptr single_sink,
|
||||
size_t queue_size,
|
||||
const async_overflow_policy overflow_policy,
|
||||
const std::function<void()>& worker_warmup_cb,
|
||||
const std::chrono::milliseconds& flush_interval_ms) :
|
||||
async_logger(logger_name,
|
||||
{
|
||||
single_sink
|
||||
}, queue_size, overflow_policy, worker_warmup_cb, flush_interval_ms) {}
|
||||
|
||||
|
||||
inline void spdlog::async_logger::flush()
|
||||
{
|
||||
|
||||
_async_log_helper->flush();
|
||||
}
|
||||
|
||||
inline void spdlog::async_logger::_set_formatter(spdlog::formatter_ptr msg_formatter)
|
||||
{
|
||||
_formatter = msg_formatter;
|
||||
_async_log_helper->set_formatter(_formatter);
|
||||
}
|
||||
|
||||
inline void spdlog::async_logger::_set_pattern(const std::string& pattern)
|
||||
{
|
||||
_formatter = std::make_shared<pattern_formatter>(pattern);
|
||||
_async_log_helper->set_formatter(_formatter);
|
||||
}
|
||||
|
||||
|
||||
inline void spdlog::async_logger::_log_msg(details::log_msg& msg)
|
||||
{
|
||||
_async_log_helper->log(msg);
|
||||
}
|
||||
//
|
||||
// Copyright(c) 2015 Gabi Melman.
|
||||
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
// Async Logger implementation
|
||||
// Use an async_sink (queue per logger) to perform the logging in a worker thread
|
||||
|
||||
#include <spdlog/details/async_log_helper.h>
|
||||
#include <spdlog/async_logger.h>
|
||||
|
||||
#include <string>
|
||||
#include <functional>
|
||||
#include <chrono>
|
||||
#include <memory>
|
||||
|
||||
template<class It>
|
||||
inline spdlog::async_logger::async_logger(const std::string& logger_name,
|
||||
const It& begin,
|
||||
const It& end,
|
||||
size_t queue_size,
|
||||
const async_overflow_policy overflow_policy,
|
||||
const std::function<void()>& worker_warmup_cb,
|
||||
const std::chrono::milliseconds& flush_interval_ms) :
|
||||
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))
|
||||
{
|
||||
}
|
||||
|
||||
inline spdlog::async_logger::async_logger(const std::string& logger_name,
|
||||
sinks_init_list sinks,
|
||||
size_t queue_size,
|
||||
const async_overflow_policy overflow_policy,
|
||||
const std::function<void()>& worker_warmup_cb,
|
||||
const std::chrono::milliseconds& flush_interval_ms) :
|
||||
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,
|
||||
sink_ptr single_sink,
|
||||
size_t queue_size,
|
||||
const async_overflow_policy overflow_policy,
|
||||
const std::function<void()>& worker_warmup_cb,
|
||||
const std::chrono::milliseconds& flush_interval_ms) :
|
||||
async_logger(logger_name,
|
||||
{
|
||||
single_sink
|
||||
}, queue_size, overflow_policy, worker_warmup_cb, flush_interval_ms) {}
|
||||
|
||||
|
||||
inline void spdlog::async_logger::flush()
|
||||
{
|
||||
|
||||
_async_log_helper->flush();
|
||||
}
|
||||
|
||||
inline void spdlog::async_logger::_set_formatter(spdlog::formatter_ptr msg_formatter)
|
||||
{
|
||||
_formatter = msg_formatter;
|
||||
_async_log_helper->set_formatter(_formatter);
|
||||
}
|
||||
|
||||
inline void spdlog::async_logger::_set_pattern(const std::string& pattern)
|
||||
{
|
||||
_formatter = std::make_shared<pattern_formatter>(pattern);
|
||||
_async_log_helper->set_formatter(_formatter);
|
||||
}
|
||||
|
||||
|
||||
inline void spdlog::async_logger::_log_msg(details::log_msg& msg)
|
||||
{
|
||||
_async_log_helper->log(msg);
|
||||
}
|
||||
|
@ -1,142 +1,142 @@
|
||||
//
|
||||
// Copyright(c) 2015 Gabi Melman.
|
||||
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
// Helper class for file sink
|
||||
// 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
|
||||
// Throw spdlog_ex exception on errors
|
||||
|
||||
#include <spdlog/details/os.h>
|
||||
#include <spdlog/details/log_msg.h>
|
||||
|
||||
#include <chrono>
|
||||
#include <cstdio>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
|
||||
namespace spdlog
|
||||
{
|
||||
namespace details
|
||||
{
|
||||
|
||||
class file_helper
|
||||
{
|
||||
public:
|
||||
const int open_tries = 5;
|
||||
const int open_interval = 10;
|
||||
|
||||
explicit file_helper(bool force_flush) :
|
||||
_fd(nullptr),
|
||||
_force_flush(force_flush)
|
||||
{}
|
||||
|
||||
file_helper(const file_helper&) = delete;
|
||||
file_helper& operator=(const file_helper&) = delete;
|
||||
|
||||
~file_helper()
|
||||
{
|
||||
close();
|
||||
}
|
||||
|
||||
|
||||
void open(const filename_t& fname, bool truncate = false)
|
||||
{
|
||||
|
||||
close();
|
||||
auto *mode = truncate ? SPDLOG_FILENAME_T("wb") : SPDLOG_FILENAME_T("ab");
|
||||
_filename = fname;
|
||||
for (int tries = 0; tries < open_tries; ++tries)
|
||||
{
|
||||
if (!os::fopen_s(&_fd, fname, mode))
|
||||
return;
|
||||
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(open_interval));
|
||||
}
|
||||
|
||||
throw spdlog_ex("Failed opening file " + filename_to_str(_filename) + " for writing");
|
||||
}
|
||||
|
||||
void reopen(bool truncate)
|
||||
{
|
||||
if (_filename.empty())
|
||||
throw spdlog_ex("Failed re opening file - was not opened before");
|
||||
open(_filename, truncate);
|
||||
|
||||
}
|
||||
|
||||
void flush()
|
||||
{
|
||||
std::fflush(_fd);
|
||||
}
|
||||
|
||||
void close()
|
||||
{
|
||||
if (_fd)
|
||||
{
|
||||
std::fclose(_fd);
|
||||
_fd = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void write(const log_msg& msg)
|
||||
{
|
||||
|
||||
size_t msg_size = msg.formatted.size();
|
||||
auto data = msg.formatted.data();
|
||||
if (std::fwrite(data, 1, msg_size, _fd) != msg_size)
|
||||
throw spdlog_ex("Failed writing to file " + filename_to_str(_filename));
|
||||
|
||||
if (_force_flush)
|
||||
std::fflush(_fd);
|
||||
|
||||
}
|
||||
|
||||
long size()
|
||||
{
|
||||
if (!_fd)
|
||||
throw spdlog_ex("Cannot use size() on closed file " + filename_to_str(_filename));
|
||||
|
||||
auto pos = ftell(_fd);
|
||||
if (fseek(_fd, 0, SEEK_END) != 0)
|
||||
throw spdlog_ex("fseek failed on file " + filename_to_str(_filename));
|
||||
|
||||
auto file_size = ftell(_fd);
|
||||
|
||||
if(fseek(_fd, pos, SEEK_SET) !=0)
|
||||
throw spdlog_ex("fseek failed on file " + filename_to_str(_filename));
|
||||
|
||||
if (file_size == -1)
|
||||
throw spdlog_ex("ftell failed on file " + filename_to_str(_filename));
|
||||
|
||||
|
||||
return file_size;
|
||||
|
||||
|
||||
}
|
||||
|
||||
const filename_t& filename() const
|
||||
{
|
||||
return _filename;
|
||||
}
|
||||
|
||||
static bool file_exists(const filename_t& name)
|
||||
{
|
||||
|
||||
return os::file_exists(name);
|
||||
}
|
||||
|
||||
|
||||
|
||||
private:
|
||||
FILE* _fd;
|
||||
filename_t _filename;
|
||||
bool _force_flush;
|
||||
|
||||
|
||||
};
|
||||
}
|
||||
}
|
||||
//
|
||||
// Copyright(c) 2015 Gabi Melman.
|
||||
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
// Helper class for file sink
|
||||
// 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
|
||||
// Throw spdlog_ex exception on errors
|
||||
|
||||
#include <spdlog/details/os.h>
|
||||
#include <spdlog/details/log_msg.h>
|
||||
|
||||
#include <chrono>
|
||||
#include <cstdio>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
|
||||
namespace spdlog
|
||||
{
|
||||
namespace details
|
||||
{
|
||||
|
||||
class file_helper
|
||||
{
|
||||
public:
|
||||
const int open_tries = 5;
|
||||
const int open_interval = 10;
|
||||
|
||||
explicit file_helper(bool force_flush) :
|
||||
_fd(nullptr),
|
||||
_force_flush(force_flush)
|
||||
{}
|
||||
|
||||
file_helper(const file_helper&) = delete;
|
||||
file_helper& operator=(const file_helper&) = delete;
|
||||
|
||||
~file_helper()
|
||||
{
|
||||
close();
|
||||
}
|
||||
|
||||
|
||||
void open(const filename_t& fname, bool truncate = false)
|
||||
{
|
||||
|
||||
close();
|
||||
auto *mode = truncate ? SPDLOG_FILENAME_T("wb") : SPDLOG_FILENAME_T("ab");
|
||||
_filename = fname;
|
||||
for (int tries = 0; tries < open_tries; ++tries)
|
||||
{
|
||||
if (!os::fopen_s(&_fd, fname, mode))
|
||||
return;
|
||||
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(open_interval));
|
||||
}
|
||||
|
||||
throw spdlog_ex("Failed opening file " + filename_to_str(_filename) + " for writing");
|
||||
}
|
||||
|
||||
void reopen(bool truncate)
|
||||
{
|
||||
if (_filename.empty())
|
||||
throw spdlog_ex("Failed re opening file - was not opened before");
|
||||
open(_filename, truncate);
|
||||
|
||||
}
|
||||
|
||||
void flush()
|
||||
{
|
||||
std::fflush(_fd);
|
||||
}
|
||||
|
||||
void close()
|
||||
{
|
||||
if (_fd)
|
||||
{
|
||||
std::fclose(_fd);
|
||||
_fd = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void write(const log_msg& msg)
|
||||
{
|
||||
|
||||
size_t msg_size = msg.formatted.size();
|
||||
auto data = msg.formatted.data();
|
||||
if (std::fwrite(data, 1, msg_size, _fd) != msg_size)
|
||||
throw spdlog_ex("Failed writing to file " + filename_to_str(_filename));
|
||||
|
||||
if (_force_flush)
|
||||
std::fflush(_fd);
|
||||
|
||||
}
|
||||
|
||||
long size()
|
||||
{
|
||||
if (!_fd)
|
||||
throw spdlog_ex("Cannot use size() on closed file " + filename_to_str(_filename));
|
||||
|
||||
auto pos = ftell(_fd);
|
||||
if (fseek(_fd, 0, SEEK_END) != 0)
|
||||
throw spdlog_ex("fseek failed on file " + filename_to_str(_filename));
|
||||
|
||||
auto file_size = ftell(_fd);
|
||||
|
||||
if(fseek(_fd, pos, SEEK_SET) !=0)
|
||||
throw spdlog_ex("fseek failed on file " + filename_to_str(_filename));
|
||||
|
||||
if (file_size == -1)
|
||||
throw spdlog_ex("ftell failed on file " + filename_to_str(_filename));
|
||||
|
||||
|
||||
return file_size;
|
||||
|
||||
|
||||
}
|
||||
|
||||
const filename_t& filename() const
|
||||
{
|
||||
return _filename;
|
||||
}
|
||||
|
||||
static bool file_exists(const filename_t& name)
|
||||
{
|
||||
|
||||
return os::file_exists(name);
|
||||
}
|
||||
|
||||
|
||||
|
||||
private:
|
||||
FILE* _fd;
|
||||
filename_t _filename;
|
||||
bool _force_flush;
|
||||
|
||||
|
||||
};
|
||||
}
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,78 +1,78 @@
|
||||
//
|
||||
// Copyright(c) 2015 Gabi Melman.
|
||||
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||
//
|
||||
#pragma once
|
||||
|
||||
#include <spdlog/common.h>
|
||||
#include <spdlog/details/log_msg.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
// Line logger class - aggregates operator<< calls to fast ostream
|
||||
// and logs upon destruction
|
||||
|
||||
namespace spdlog
|
||||
{
|
||||
|
||||
// Forward declaration
|
||||
class logger;
|
||||
|
||||
namespace details
|
||||
{
|
||||
class line_logger
|
||||
{
|
||||
public:
|
||||
line_logger(logger* callback_logger, level::level_enum msg_level, bool enabled);
|
||||
|
||||
// No copy intended. Only move
|
||||
line_logger(const line_logger& other) = delete;
|
||||
line_logger& operator=(const line_logger&) = delete;
|
||||
line_logger& operator=(line_logger&&) = delete;
|
||||
|
||||
|
||||
line_logger(line_logger&& other);
|
||||
|
||||
//Log the log message using the callback logger
|
||||
~line_logger();
|
||||
|
||||
//
|
||||
// Support for format string with variadic args
|
||||
//
|
||||
|
||||
|
||||
void write(const char* what);
|
||||
|
||||
template <typename... Args>
|
||||
void write(const char* fmt, const Args&... args);
|
||||
|
||||
//
|
||||
// Support for operator<<
|
||||
//
|
||||
line_logger& operator<<(const char* what);
|
||||
line_logger& operator<<(const std::string& what);
|
||||
line_logger& operator<<(int what);
|
||||
line_logger& operator<<(unsigned int what);
|
||||
line_logger& operator<<(long what);
|
||||
line_logger& operator<<(unsigned long what);
|
||||
line_logger& operator<<(long long what);
|
||||
line_logger& operator<<(unsigned long long what);
|
||||
line_logger& operator<<(double what);
|
||||
line_logger& operator<<(long double what);
|
||||
line_logger& operator<<(float what);
|
||||
line_logger& operator<<(char what);
|
||||
//Support user types which implements operator<<
|
||||
template<typename T>
|
||||
line_logger& operator<<(const T& what);
|
||||
|
||||
void disable();
|
||||
bool is_enabled() const;
|
||||
|
||||
private:
|
||||
logger* _callback_logger;
|
||||
log_msg _log_msg;
|
||||
bool _enabled;
|
||||
};
|
||||
} //Namespace details
|
||||
} // Namespace spdlog
|
||||
|
||||
//
|
||||
// Copyright(c) 2015 Gabi Melman.
|
||||
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||
//
|
||||
#pragma once
|
||||
|
||||
#include <spdlog/common.h>
|
||||
#include <spdlog/details/log_msg.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
// Line logger class - aggregates operator<< calls to fast ostream
|
||||
// and logs upon destruction
|
||||
|
||||
namespace spdlog
|
||||
{
|
||||
|
||||
// Forward declaration
|
||||
class logger;
|
||||
|
||||
namespace details
|
||||
{
|
||||
class line_logger
|
||||
{
|
||||
public:
|
||||
line_logger(logger* callback_logger, level::level_enum msg_level, bool enabled);
|
||||
|
||||
// No copy intended. Only move
|
||||
line_logger(const line_logger& other) = delete;
|
||||
line_logger& operator=(const line_logger&) = delete;
|
||||
line_logger& operator=(line_logger&&) = delete;
|
||||
|
||||
|
||||
line_logger(line_logger&& other);
|
||||
|
||||
//Log the log message using the callback logger
|
||||
~line_logger();
|
||||
|
||||
//
|
||||
// Support for format string with variadic args
|
||||
//
|
||||
|
||||
|
||||
void write(const char* what);
|
||||
|
||||
template <typename... Args>
|
||||
void write(const char* fmt, const Args&... args);
|
||||
|
||||
//
|
||||
// Support for operator<<
|
||||
//
|
||||
line_logger& operator<<(const char* what);
|
||||
line_logger& operator<<(const std::string& what);
|
||||
line_logger& operator<<(int what);
|
||||
line_logger& operator<<(unsigned int what);
|
||||
line_logger& operator<<(long what);
|
||||
line_logger& operator<<(unsigned long what);
|
||||
line_logger& operator<<(long long what);
|
||||
line_logger& operator<<(unsigned long long what);
|
||||
line_logger& operator<<(double what);
|
||||
line_logger& operator<<(long double what);
|
||||
line_logger& operator<<(float what);
|
||||
line_logger& operator<<(char what);
|
||||
//Support user types which implements operator<<
|
||||
template<typename T>
|
||||
line_logger& operator<<(const T& what);
|
||||
|
||||
void disable();
|
||||
bool is_enabled() const;
|
||||
|
||||
private:
|
||||
logger* _callback_logger;
|
||||
log_msg _log_msg;
|
||||
bool _enabled;
|
||||
};
|
||||
} //Namespace details
|
||||
} // Namespace spdlog
|
||||
|
||||
|
@ -1,185 +1,185 @@
|
||||
//
|
||||
// Copyright(c) 2015 Gabi Melman.
|
||||
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||
//
|
||||
#pragma once
|
||||
#include <type_traits>
|
||||
|
||||
#include <spdlog/details/line_logger_fwd.h>
|
||||
#include <spdlog/common.h>
|
||||
#include <spdlog/logger.h>
|
||||
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
// Line logger class - aggregates operator<< calls to fast ostream
|
||||
// and logs upon destruction
|
||||
|
||||
inline spdlog::details::line_logger::line_logger(logger* callback_logger, level::level_enum msg_level, bool enabled):
|
||||
_callback_logger(callback_logger),
|
||||
_log_msg(msg_level),
|
||||
_enabled(enabled)
|
||||
{}
|
||||
|
||||
inline spdlog::details::line_logger::line_logger(line_logger&& other) :
|
||||
_callback_logger(other._callback_logger),
|
||||
_log_msg(std::move(other._log_msg)),
|
||||
_enabled(other._enabled)
|
||||
{
|
||||
other.disable();
|
||||
}
|
||||
|
||||
//Log the log message using the callback logger
|
||||
inline spdlog::details::line_logger::~line_logger()
|
||||
{
|
||||
if (_enabled)
|
||||
{
|
||||
#ifndef SPDLOG_NO_NAME
|
||||
_log_msg.logger_name = _callback_logger->name();
|
||||
#endif
|
||||
#ifndef SPDLOG_NO_DATETIME
|
||||
_log_msg.time = os::now();
|
||||
#endif
|
||||
|
||||
#ifndef SPDLOG_NO_THREAD_ID
|
||||
_log_msg.thread_id = os::thread_id();
|
||||
#endif
|
||||
_callback_logger->_log_msg(_log_msg);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Support for format string with variadic args
|
||||
//
|
||||
|
||||
|
||||
inline void spdlog::details::line_logger::write(const char* what)
|
||||
{
|
||||
if (_enabled)
|
||||
_log_msg.raw << what;
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
inline void spdlog::details::line_logger::write(const char* fmt, const Args&... args)
|
||||
{
|
||||
if (!_enabled)
|
||||
return;
|
||||
try
|
||||
{
|
||||
_log_msg.raw.write(fmt, args...);
|
||||
}
|
||||
catch (const fmt::FormatError& e)
|
||||
{
|
||||
throw spdlog_ex(fmt::format("formatting error while processing format string '{}': {}", fmt, e.what()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Support for operator<<
|
||||
//
|
||||
inline spdlog::details::line_logger& spdlog::details::line_logger::operator<<(const char* what)
|
||||
{
|
||||
if (_enabled)
|
||||
_log_msg.raw << what;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline spdlog::details::line_logger& spdlog::details::line_logger::operator<<(const std::string& what)
|
||||
{
|
||||
if (_enabled)
|
||||
_log_msg.raw << what;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline spdlog::details::line_logger& spdlog::details::line_logger::operator<<(int what)
|
||||
{
|
||||
if (_enabled)
|
||||
_log_msg.raw << what;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline spdlog::details::line_logger& spdlog::details::line_logger::operator<<(unsigned int what)
|
||||
{
|
||||
if (_enabled)
|
||||
_log_msg.raw << what;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
inline spdlog::details::line_logger& spdlog::details::line_logger::operator<<(long what)
|
||||
{
|
||||
if (_enabled)
|
||||
_log_msg.raw << what;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline spdlog::details::line_logger& spdlog::details::line_logger::operator<<(unsigned long what)
|
||||
{
|
||||
if (_enabled)
|
||||
_log_msg.raw << what;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline spdlog::details::line_logger& spdlog::details::line_logger::operator<<(long long what)
|
||||
{
|
||||
if (_enabled)
|
||||
_log_msg.raw << what;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline spdlog::details::line_logger& spdlog::details::line_logger::operator<<(unsigned long long what)
|
||||
{
|
||||
if (_enabled)
|
||||
_log_msg.raw << what;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline spdlog::details::line_logger& spdlog::details::line_logger::operator<<(double what)
|
||||
{
|
||||
if (_enabled)
|
||||
_log_msg.raw << what;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline spdlog::details::line_logger& spdlog::details::line_logger::operator<<(long double what)
|
||||
{
|
||||
if (_enabled)
|
||||
_log_msg.raw << what;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline spdlog::details::line_logger& spdlog::details::line_logger::operator<<(float what)
|
||||
{
|
||||
if (_enabled)
|
||||
_log_msg.raw << what;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline spdlog::details::line_logger& spdlog::details::line_logger::operator<<(char what)
|
||||
{
|
||||
if (_enabled)
|
||||
_log_msg.raw << what;
|
||||
return *this;
|
||||
}
|
||||
|
||||
//Support user types which implements operator<<
|
||||
template<typename T>
|
||||
inline spdlog::details::line_logger& spdlog::details::line_logger::operator<<(const T& what)
|
||||
{
|
||||
if (_enabled)
|
||||
_log_msg.raw.write("{}", what);
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
inline void spdlog::details::line_logger::disable()
|
||||
{
|
||||
_enabled = false;
|
||||
}
|
||||
|
||||
inline bool spdlog::details::line_logger::is_enabled() const
|
||||
{
|
||||
return _enabled;
|
||||
}
|
||||
|
||||
//
|
||||
// Copyright(c) 2015 Gabi Melman.
|
||||
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||
//
|
||||
#pragma once
|
||||
#include <type_traits>
|
||||
|
||||
#include <spdlog/details/line_logger_fwd.h>
|
||||
#include <spdlog/common.h>
|
||||
#include <spdlog/logger.h>
|
||||
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
// Line logger class - aggregates operator<< calls to fast ostream
|
||||
// and logs upon destruction
|
||||
|
||||
inline spdlog::details::line_logger::line_logger(logger* callback_logger, level::level_enum msg_level, bool enabled):
|
||||
_callback_logger(callback_logger),
|
||||
_log_msg(msg_level),
|
||||
_enabled(enabled)
|
||||
{}
|
||||
|
||||
inline spdlog::details::line_logger::line_logger(line_logger&& other) :
|
||||
_callback_logger(other._callback_logger),
|
||||
_log_msg(std::move(other._log_msg)),
|
||||
_enabled(other._enabled)
|
||||
{
|
||||
other.disable();
|
||||
}
|
||||
|
||||
//Log the log message using the callback logger
|
||||
inline spdlog::details::line_logger::~line_logger()
|
||||
{
|
||||
if (_enabled)
|
||||
{
|
||||
#ifndef SPDLOG_NO_NAME
|
||||
_log_msg.logger_name = _callback_logger->name();
|
||||
#endif
|
||||
#ifndef SPDLOG_NO_DATETIME
|
||||
_log_msg.time = os::now();
|
||||
#endif
|
||||
|
||||
#ifndef SPDLOG_NO_THREAD_ID
|
||||
_log_msg.thread_id = os::thread_id();
|
||||
#endif
|
||||
_callback_logger->_log_msg(_log_msg);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Support for format string with variadic args
|
||||
//
|
||||
|
||||
|
||||
inline void spdlog::details::line_logger::write(const char* what)
|
||||
{
|
||||
if (_enabled)
|
||||
_log_msg.raw << what;
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
inline void spdlog::details::line_logger::write(const char* fmt, const Args&... args)
|
||||
{
|
||||
if (!_enabled)
|
||||
return;
|
||||
try
|
||||
{
|
||||
_log_msg.raw.write(fmt, args...);
|
||||
}
|
||||
catch (const fmt::FormatError& e)
|
||||
{
|
||||
throw spdlog_ex(fmt::format("formatting error while processing format string '{}': {}", fmt, e.what()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Support for operator<<
|
||||
//
|
||||
inline spdlog::details::line_logger& spdlog::details::line_logger::operator<<(const char* what)
|
||||
{
|
||||
if (_enabled)
|
||||
_log_msg.raw << what;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline spdlog::details::line_logger& spdlog::details::line_logger::operator<<(const std::string& what)
|
||||
{
|
||||
if (_enabled)
|
||||
_log_msg.raw << what;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline spdlog::details::line_logger& spdlog::details::line_logger::operator<<(int what)
|
||||
{
|
||||
if (_enabled)
|
||||
_log_msg.raw << what;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline spdlog::details::line_logger& spdlog::details::line_logger::operator<<(unsigned int what)
|
||||
{
|
||||
if (_enabled)
|
||||
_log_msg.raw << what;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
inline spdlog::details::line_logger& spdlog::details::line_logger::operator<<(long what)
|
||||
{
|
||||
if (_enabled)
|
||||
_log_msg.raw << what;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline spdlog::details::line_logger& spdlog::details::line_logger::operator<<(unsigned long what)
|
||||
{
|
||||
if (_enabled)
|
||||
_log_msg.raw << what;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline spdlog::details::line_logger& spdlog::details::line_logger::operator<<(long long what)
|
||||
{
|
||||
if (_enabled)
|
||||
_log_msg.raw << what;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline spdlog::details::line_logger& spdlog::details::line_logger::operator<<(unsigned long long what)
|
||||
{
|
||||
if (_enabled)
|
||||
_log_msg.raw << what;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline spdlog::details::line_logger& spdlog::details::line_logger::operator<<(double what)
|
||||
{
|
||||
if (_enabled)
|
||||
_log_msg.raw << what;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline spdlog::details::line_logger& spdlog::details::line_logger::operator<<(long double what)
|
||||
{
|
||||
if (_enabled)
|
||||
_log_msg.raw << what;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline spdlog::details::line_logger& spdlog::details::line_logger::operator<<(float what)
|
||||
{
|
||||
if (_enabled)
|
||||
_log_msg.raw << what;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline spdlog::details::line_logger& spdlog::details::line_logger::operator<<(char what)
|
||||
{
|
||||
if (_enabled)
|
||||
_log_msg.raw << what;
|
||||
return *this;
|
||||
}
|
||||
|
||||
//Support user types which implements operator<<
|
||||
template<typename T>
|
||||
inline spdlog::details::line_logger& spdlog::details::line_logger::operator<<(const T& what)
|
||||
{
|
||||
if (_enabled)
|
||||
_log_msg.raw.write("{}", what);
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
inline void spdlog::details::line_logger::disable()
|
||||
{
|
||||
_enabled = false;
|
||||
}
|
||||
|
||||
inline bool spdlog::details::line_logger::is_enabled() const
|
||||
{
|
||||
return _enabled;
|
||||
}
|
||||
|
||||
|
@ -1,81 +1,81 @@
|
||||
//
|
||||
// Copyright(c) 2015 Gabi Melman.
|
||||
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <spdlog/common.h>
|
||||
#include <spdlog/details/format.h>
|
||||
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
namespace spdlog
|
||||
{
|
||||
namespace details
|
||||
{
|
||||
struct log_msg
|
||||
{
|
||||
log_msg() = default;
|
||||
log_msg(level::level_enum l):
|
||||
logger_name(),
|
||||
level(l),
|
||||
raw(),
|
||||
formatted() {}
|
||||
|
||||
|
||||
log_msg(const log_msg& other) :
|
||||
logger_name(other.logger_name),
|
||||
level(other.level),
|
||||
time(other.time),
|
||||
thread_id(other.thread_id)
|
||||
{
|
||||
if (other.raw.size())
|
||||
raw << fmt::BasicStringRef<char>(other.raw.data(), other.raw.size());
|
||||
if (other.formatted.size())
|
||||
formatted << fmt::BasicStringRef<char>(other.formatted.data(), other.formatted.size());
|
||||
}
|
||||
|
||||
log_msg(log_msg&& other) :
|
||||
logger_name(std::move(other.logger_name)),
|
||||
level(other.level),
|
||||
time(std::move(other.time)),
|
||||
thread_id(other.thread_id),
|
||||
raw(std::move(other.raw)),
|
||||
formatted(std::move(other.formatted))
|
||||
{
|
||||
other.clear();
|
||||
}
|
||||
|
||||
log_msg& operator=(log_msg&& other)
|
||||
{
|
||||
if (this == &other)
|
||||
return *this;
|
||||
|
||||
logger_name = std::move(other.logger_name);
|
||||
level = other.level;
|
||||
time = std::move(other.time);
|
||||
thread_id = other.thread_id;
|
||||
raw = std::move(other.raw);
|
||||
formatted = std::move(other.formatted);
|
||||
other.clear();
|
||||
return *this;
|
||||
}
|
||||
|
||||
void clear()
|
||||
{
|
||||
level = level::off;
|
||||
raw.clear();
|
||||
formatted.clear();
|
||||
}
|
||||
|
||||
std::string logger_name;
|
||||
level::level_enum level;
|
||||
log_clock::time_point time;
|
||||
size_t thread_id;
|
||||
fmt::MemoryWriter raw;
|
||||
fmt::MemoryWriter formatted;
|
||||
};
|
||||
}
|
||||
}
|
||||
//
|
||||
// Copyright(c) 2015 Gabi Melman.
|
||||
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <spdlog/common.h>
|
||||
#include <spdlog/details/format.h>
|
||||
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
namespace spdlog
|
||||
{
|
||||
namespace details
|
||||
{
|
||||
struct log_msg
|
||||
{
|
||||
log_msg() = default;
|
||||
log_msg(level::level_enum l):
|
||||
logger_name(),
|
||||
level(l),
|
||||
raw(),
|
||||
formatted() {}
|
||||
|
||||
|
||||
log_msg(const log_msg& other) :
|
||||
logger_name(other.logger_name),
|
||||
level(other.level),
|
||||
time(other.time),
|
||||
thread_id(other.thread_id)
|
||||
{
|
||||
if (other.raw.size())
|
||||
raw << fmt::BasicStringRef<char>(other.raw.data(), other.raw.size());
|
||||
if (other.formatted.size())
|
||||
formatted << fmt::BasicStringRef<char>(other.formatted.data(), other.formatted.size());
|
||||
}
|
||||
|
||||
log_msg(log_msg&& other) :
|
||||
logger_name(std::move(other.logger_name)),
|
||||
level(other.level),
|
||||
time(std::move(other.time)),
|
||||
thread_id(other.thread_id),
|
||||
raw(std::move(other.raw)),
|
||||
formatted(std::move(other.formatted))
|
||||
{
|
||||
other.clear();
|
||||
}
|
||||
|
||||
log_msg& operator=(log_msg&& other)
|
||||
{
|
||||
if (this == &other)
|
||||
return *this;
|
||||
|
||||
logger_name = std::move(other.logger_name);
|
||||
level = other.level;
|
||||
time = std::move(other.time);
|
||||
thread_id = other.thread_id;
|
||||
raw = std::move(other.raw);
|
||||
formatted = std::move(other.formatted);
|
||||
other.clear();
|
||||
return *this;
|
||||
}
|
||||
|
||||
void clear()
|
||||
{
|
||||
level = level::off;
|
||||
raw.clear();
|
||||
formatted.clear();
|
||||
}
|
||||
|
||||
std::string logger_name;
|
||||
level::level_enum level;
|
||||
log_clock::time_point time;
|
||||
size_t thread_id;
|
||||
fmt::MemoryWriter raw;
|
||||
fmt::MemoryWriter formatted;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -1,302 +1,302 @@
|
||||
//
|
||||
// Copyright(c) 2015 Gabi Melman.
|
||||
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <spdlog/logger.h>
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
// create logger with given name, sinks and the default pattern formatter
|
||||
// all other ctors will call this one
|
||||
template<class It>
|
||||
inline spdlog::logger::logger(const std::string& logger_name, const It& begin, const It& end) :
|
||||
_name(logger_name),
|
||||
_sinks(begin, end),
|
||||
_formatter(std::make_shared<pattern_formatter>("%+"))
|
||||
{
|
||||
|
||||
// no support under vs2013 for member initialization for std::atomic
|
||||
_level = level::info;
|
||||
}
|
||||
|
||||
// ctor with sinks as init list
|
||||
inline spdlog::logger::logger(const std::string& logger_name, sinks_init_list sinks_list) :
|
||||
logger(logger_name, sinks_list.begin(), sinks_list.end()) {}
|
||||
|
||||
|
||||
// ctor with single sink
|
||||
inline spdlog::logger::logger(const std::string& logger_name, spdlog::sink_ptr single_sink) :
|
||||
logger(logger_name,
|
||||
{
|
||||
single_sink
|
||||
}) {}
|
||||
|
||||
|
||||
inline spdlog::logger::~logger() = default;
|
||||
|
||||
|
||||
inline void spdlog::logger::set_formatter(spdlog::formatter_ptr msg_formatter)
|
||||
{
|
||||
_set_formatter(msg_formatter);
|
||||
}
|
||||
|
||||
inline void spdlog::logger::set_pattern(const std::string& pattern)
|
||||
{
|
||||
_set_pattern(pattern);
|
||||
}
|
||||
|
||||
//
|
||||
// log only if given level>=logger's log level
|
||||
//
|
||||
|
||||
|
||||
template <typename... 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);
|
||||
details::line_logger l(this, lvl, msg_enabled);
|
||||
l.write(fmt, args...);
|
||||
return l;
|
||||
}
|
||||
|
||||
inline spdlog::details::line_logger spdlog::logger::_log_if_enabled(level::level_enum lvl)
|
||||
{
|
||||
return details::line_logger(this, lvl, should_log(lvl));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline spdlog::details::line_logger spdlog::logger::_log_if_enabled(level::level_enum lvl, const T& msg)
|
||||
{
|
||||
bool msg_enabled = should_log(lvl);
|
||||
details::line_logger l(this, lvl, msg_enabled);
|
||||
l << msg;
|
||||
return l;
|
||||
}
|
||||
|
||||
//
|
||||
// logger.info(cppformat_string, arg1, arg2, arg3, ...) call style
|
||||
//
|
||||
template <typename... Args>
|
||||
inline spdlog::details::line_logger spdlog::logger::trace(const char* fmt, const Args&... args)
|
||||
{
|
||||
return _log_if_enabled(level::trace, fmt, args...);
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
inline spdlog::details::line_logger spdlog::logger::debug(const char* fmt, const Args&... args)
|
||||
{
|
||||
return _log_if_enabled(level::debug, fmt, args...);
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
inline spdlog::details::line_logger spdlog::logger::info(const char* fmt, const Args&... args)
|
||||
{
|
||||
return _log_if_enabled(level::info, fmt, args...);
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
inline spdlog::details::line_logger spdlog::logger::notice(const char* fmt, const Args&... args)
|
||||
{
|
||||
return _log_if_enabled(level::notice, fmt, args...);
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
inline spdlog::details::line_logger spdlog::logger::warn(const char* fmt, const Args&... args)
|
||||
{
|
||||
return _log_if_enabled(level::warn, fmt, args...);
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
inline spdlog::details::line_logger spdlog::logger::error(const char* fmt, const Args&... args)
|
||||
{
|
||||
return _log_if_enabled(level::err, fmt, args...);
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
inline spdlog::details::line_logger spdlog::logger::critical(const char* fmt, const Args&... args)
|
||||
{
|
||||
return _log_if_enabled(level::critical, fmt, args...);
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
inline spdlog::details::line_logger spdlog::logger::alert(const char* fmt, const Args&... args)
|
||||
{
|
||||
return _log_if_enabled(level::alert, fmt, args...);
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
inline spdlog::details::line_logger spdlog::logger::emerg(const char* fmt, const Args&... args)
|
||||
{
|
||||
return _log_if_enabled(level::emerg, fmt, args...);
|
||||
}
|
||||
|
||||
//
|
||||
// logger.info(msg) << ".." call style
|
||||
//
|
||||
template<typename T>
|
||||
inline spdlog::details::line_logger spdlog::logger::trace(const T& msg)
|
||||
{
|
||||
return _log_if_enabled(level::trace, msg);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline spdlog::details::line_logger spdlog::logger::debug(const T& msg)
|
||||
{
|
||||
return _log_if_enabled(level::debug, msg);
|
||||
}
|
||||
|
||||
|
||||
template<typename T>
|
||||
inline spdlog::details::line_logger spdlog::logger::info(const T& msg)
|
||||
{
|
||||
return _log_if_enabled(level::info, msg);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline spdlog::details::line_logger spdlog::logger::notice(const T& msg)
|
||||
{
|
||||
return _log_if_enabled(level::notice, msg);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline spdlog::details::line_logger spdlog::logger::warn(const T& msg)
|
||||
{
|
||||
return _log_if_enabled(level::warn, msg);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline spdlog::details::line_logger spdlog::logger::error(const T& msg)
|
||||
{
|
||||
return _log_if_enabled(level::err, msg);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline spdlog::details::line_logger spdlog::logger::critical(const T& msg)
|
||||
{
|
||||
return _log_if_enabled(level::critical, msg);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline spdlog::details::line_logger spdlog::logger::alert(const T& msg)
|
||||
{
|
||||
return _log_if_enabled(level::alert, msg);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline spdlog::details::line_logger spdlog::logger::emerg(const T& msg)
|
||||
{
|
||||
return _log_if_enabled(level::emerg, msg);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
//
|
||||
// logger.info() << ".." call style
|
||||
//
|
||||
inline spdlog::details::line_logger spdlog::logger::trace()
|
||||
{
|
||||
return _log_if_enabled(level::trace);
|
||||
}
|
||||
|
||||
inline spdlog::details::line_logger spdlog::logger::debug()
|
||||
{
|
||||
return _log_if_enabled(level::debug);
|
||||
}
|
||||
|
||||
inline spdlog::details::line_logger spdlog::logger::info()
|
||||
{
|
||||
return _log_if_enabled(level::info);
|
||||
}
|
||||
|
||||
inline spdlog::details::line_logger spdlog::logger::notice()
|
||||
{
|
||||
return _log_if_enabled(level::notice);
|
||||
}
|
||||
|
||||
inline spdlog::details::line_logger spdlog::logger::warn()
|
||||
{
|
||||
return _log_if_enabled(level::warn);
|
||||
}
|
||||
|
||||
inline spdlog::details::line_logger spdlog::logger::error()
|
||||
{
|
||||
return _log_if_enabled(level::err);
|
||||
}
|
||||
|
||||
inline spdlog::details::line_logger spdlog::logger::critical()
|
||||
{
|
||||
return _log_if_enabled(level::critical);
|
||||
}
|
||||
|
||||
inline spdlog::details::line_logger spdlog::logger::alert()
|
||||
{
|
||||
return _log_if_enabled(level::alert);
|
||||
}
|
||||
|
||||
inline spdlog::details::line_logger spdlog::logger::emerg()
|
||||
{
|
||||
return _log_if_enabled(level::emerg);
|
||||
}
|
||||
|
||||
|
||||
// always log, no matter what is the actual logger's log level
|
||||
template <typename... 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);
|
||||
l.write(fmt, args...);
|
||||
return l;
|
||||
}
|
||||
|
||||
//
|
||||
// name and level
|
||||
//
|
||||
inline const std::string& spdlog::logger::name() const
|
||||
{
|
||||
return _name;
|
||||
}
|
||||
|
||||
inline void spdlog::logger::set_level(spdlog::level::level_enum log_level)
|
||||
{
|
||||
_level.store(log_level);
|
||||
}
|
||||
|
||||
inline spdlog::level::level_enum spdlog::logger::level() const
|
||||
{
|
||||
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
|
||||
{
|
||||
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
|
||||
//
|
||||
inline void spdlog::logger::_log_msg(details::log_msg& msg)
|
||||
{
|
||||
_formatter->format(msg);
|
||||
for (auto &sink : _sinks)
|
||||
sink->log(msg);
|
||||
}
|
||||
|
||||
inline void spdlog::logger::_set_pattern(const std::string& pattern)
|
||||
{
|
||||
_formatter = std::make_shared<pattern_formatter>(pattern);
|
||||
}
|
||||
inline void spdlog::logger::_set_formatter(formatter_ptr msg_formatter)
|
||||
{
|
||||
_formatter = msg_formatter;
|
||||
}
|
||||
|
||||
inline void spdlog::logger::flush()
|
||||
{
|
||||
for (auto& sink : _sinks)
|
||||
sink->flush();
|
||||
}
|
||||
//
|
||||
// Copyright(c) 2015 Gabi Melman.
|
||||
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <spdlog/logger.h>
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
// create logger with given name, sinks and the default pattern formatter
|
||||
// all other ctors will call this one
|
||||
template<class It>
|
||||
inline spdlog::logger::logger(const std::string& logger_name, const It& begin, const It& end) :
|
||||
_name(logger_name),
|
||||
_sinks(begin, end),
|
||||
_formatter(std::make_shared<pattern_formatter>("%+"))
|
||||
{
|
||||
|
||||
// no support under vs2013 for member initialization for std::atomic
|
||||
_level = level::info;
|
||||
}
|
||||
|
||||
// ctor with sinks as init list
|
||||
inline spdlog::logger::logger(const std::string& logger_name, sinks_init_list sinks_list) :
|
||||
logger(logger_name, sinks_list.begin(), sinks_list.end()) {}
|
||||
|
||||
|
||||
// ctor with single sink
|
||||
inline spdlog::logger::logger(const std::string& logger_name, spdlog::sink_ptr single_sink) :
|
||||
logger(logger_name,
|
||||
{
|
||||
single_sink
|
||||
}) {}
|
||||
|
||||
|
||||
inline spdlog::logger::~logger() = default;
|
||||
|
||||
|
||||
inline void spdlog::logger::set_formatter(spdlog::formatter_ptr msg_formatter)
|
||||
{
|
||||
_set_formatter(msg_formatter);
|
||||
}
|
||||
|
||||
inline void spdlog::logger::set_pattern(const std::string& pattern)
|
||||
{
|
||||
_set_pattern(pattern);
|
||||
}
|
||||
|
||||
//
|
||||
// log only if given level>=logger's log level
|
||||
//
|
||||
|
||||
|
||||
template <typename... 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);
|
||||
details::line_logger l(this, lvl, msg_enabled);
|
||||
l.write(fmt, args...);
|
||||
return l;
|
||||
}
|
||||
|
||||
inline spdlog::details::line_logger spdlog::logger::_log_if_enabled(level::level_enum lvl)
|
||||
{
|
||||
return details::line_logger(this, lvl, should_log(lvl));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline spdlog::details::line_logger spdlog::logger::_log_if_enabled(level::level_enum lvl, const T& msg)
|
||||
{
|
||||
bool msg_enabled = should_log(lvl);
|
||||
details::line_logger l(this, lvl, msg_enabled);
|
||||
l << msg;
|
||||
return l;
|
||||
}
|
||||
|
||||
//
|
||||
// logger.info(cppformat_string, arg1, arg2, arg3, ...) call style
|
||||
//
|
||||
template <typename... Args>
|
||||
inline spdlog::details::line_logger spdlog::logger::trace(const char* fmt, const Args&... args)
|
||||
{
|
||||
return _log_if_enabled(level::trace, fmt, args...);
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
inline spdlog::details::line_logger spdlog::logger::debug(const char* fmt, const Args&... args)
|
||||
{
|
||||
return _log_if_enabled(level::debug, fmt, args...);
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
inline spdlog::details::line_logger spdlog::logger::info(const char* fmt, const Args&... args)
|
||||
{
|
||||
return _log_if_enabled(level::info, fmt, args...);
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
inline spdlog::details::line_logger spdlog::logger::notice(const char* fmt, const Args&... args)
|
||||
{
|
||||
return _log_if_enabled(level::notice, fmt, args...);
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
inline spdlog::details::line_logger spdlog::logger::warn(const char* fmt, const Args&... args)
|
||||
{
|
||||
return _log_if_enabled(level::warn, fmt, args...);
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
inline spdlog::details::line_logger spdlog::logger::error(const char* fmt, const Args&... args)
|
||||
{
|
||||
return _log_if_enabled(level::err, fmt, args...);
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
inline spdlog::details::line_logger spdlog::logger::critical(const char* fmt, const Args&... args)
|
||||
{
|
||||
return _log_if_enabled(level::critical, fmt, args...);
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
inline spdlog::details::line_logger spdlog::logger::alert(const char* fmt, const Args&... args)
|
||||
{
|
||||
return _log_if_enabled(level::alert, fmt, args...);
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
inline spdlog::details::line_logger spdlog::logger::emerg(const char* fmt, const Args&... args)
|
||||
{
|
||||
return _log_if_enabled(level::emerg, fmt, args...);
|
||||
}
|
||||
|
||||
//
|
||||
// logger.info(msg) << ".." call style
|
||||
//
|
||||
template<typename T>
|
||||
inline spdlog::details::line_logger spdlog::logger::trace(const T& msg)
|
||||
{
|
||||
return _log_if_enabled(level::trace, msg);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline spdlog::details::line_logger spdlog::logger::debug(const T& msg)
|
||||
{
|
||||
return _log_if_enabled(level::debug, msg);
|
||||
}
|
||||
|
||||
|
||||
template<typename T>
|
||||
inline spdlog::details::line_logger spdlog::logger::info(const T& msg)
|
||||
{
|
||||
return _log_if_enabled(level::info, msg);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline spdlog::details::line_logger spdlog::logger::notice(const T& msg)
|
||||
{
|
||||
return _log_if_enabled(level::notice, msg);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline spdlog::details::line_logger spdlog::logger::warn(const T& msg)
|
||||
{
|
||||
return _log_if_enabled(level::warn, msg);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline spdlog::details::line_logger spdlog::logger::error(const T& msg)
|
||||
{
|
||||
return _log_if_enabled(level::err, msg);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline spdlog::details::line_logger spdlog::logger::critical(const T& msg)
|
||||
{
|
||||
return _log_if_enabled(level::critical, msg);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline spdlog::details::line_logger spdlog::logger::alert(const T& msg)
|
||||
{
|
||||
return _log_if_enabled(level::alert, msg);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline spdlog::details::line_logger spdlog::logger::emerg(const T& msg)
|
||||
{
|
||||
return _log_if_enabled(level::emerg, msg);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
//
|
||||
// logger.info() << ".." call style
|
||||
//
|
||||
inline spdlog::details::line_logger spdlog::logger::trace()
|
||||
{
|
||||
return _log_if_enabled(level::trace);
|
||||
}
|
||||
|
||||
inline spdlog::details::line_logger spdlog::logger::debug()
|
||||
{
|
||||
return _log_if_enabled(level::debug);
|
||||
}
|
||||
|
||||
inline spdlog::details::line_logger spdlog::logger::info()
|
||||
{
|
||||
return _log_if_enabled(level::info);
|
||||
}
|
||||
|
||||
inline spdlog::details::line_logger spdlog::logger::notice()
|
||||
{
|
||||
return _log_if_enabled(level::notice);
|
||||
}
|
||||
|
||||
inline spdlog::details::line_logger spdlog::logger::warn()
|
||||
{
|
||||
return _log_if_enabled(level::warn);
|
||||
}
|
||||
|
||||
inline spdlog::details::line_logger spdlog::logger::error()
|
||||
{
|
||||
return _log_if_enabled(level::err);
|
||||
}
|
||||
|
||||
inline spdlog::details::line_logger spdlog::logger::critical()
|
||||
{
|
||||
return _log_if_enabled(level::critical);
|
||||
}
|
||||
|
||||
inline spdlog::details::line_logger spdlog::logger::alert()
|
||||
{
|
||||
return _log_if_enabled(level::alert);
|
||||
}
|
||||
|
||||
inline spdlog::details::line_logger spdlog::logger::emerg()
|
||||
{
|
||||
return _log_if_enabled(level::emerg);
|
||||
}
|
||||
|
||||
|
||||
// always log, no matter what is the actual logger's log level
|
||||
template <typename... 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);
|
||||
l.write(fmt, args...);
|
||||
return l;
|
||||
}
|
||||
|
||||
//
|
||||
// name and level
|
||||
//
|
||||
inline const std::string& spdlog::logger::name() const
|
||||
{
|
||||
return _name;
|
||||
}
|
||||
|
||||
inline void spdlog::logger::set_level(spdlog::level::level_enum log_level)
|
||||
{
|
||||
_level.store(log_level);
|
||||
}
|
||||
|
||||
inline spdlog::level::level_enum spdlog::logger::level() const
|
||||
{
|
||||
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
|
||||
{
|
||||
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
|
||||
//
|
||||
inline void spdlog::logger::_log_msg(details::log_msg& msg)
|
||||
{
|
||||
_formatter->format(msg);
|
||||
for (auto &sink : _sinks)
|
||||
sink->log(msg);
|
||||
}
|
||||
|
||||
inline void spdlog::logger::_set_pattern(const std::string& pattern)
|
||||
{
|
||||
_formatter = std::make_shared<pattern_formatter>(pattern);
|
||||
}
|
||||
inline void spdlog::logger::_set_formatter(formatter_ptr msg_formatter)
|
||||
{
|
||||
_formatter = msg_formatter;
|
||||
}
|
||||
|
||||
inline void spdlog::logger::flush()
|
||||
{
|
||||
for (auto& sink : _sinks)
|
||||
sink->flush();
|
||||
}
|
||||
|
@ -1,159 +1,159 @@
|
||||
/*
|
||||
A modified version of Bounded MPMC queue by Dmitry Vyukov.
|
||||
|
||||
Original code from:
|
||||
http://www.1024cores.net/home/lock-free-algorithms/queues/bounded-mpmc-queue
|
||||
|
||||
licensed by Dmitry Vyukov under the terms below:
|
||||
|
||||
Simplified BSD license
|
||||
|
||||
Copyright (c) 2010-2011 Dmitry Vyukov. All rights reserved.
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
conditions and the following disclaimer.
|
||||
|
||||
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
|
||||
provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY DMITRY VYUKOV "AS IS" AND ANY EXPRESS OR IMPLIED
|
||||
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
||||
SHALL DMITRY VYUKOV OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
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
|
||||
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
/*
|
||||
The code in its current form adds the license below:
|
||||
|
||||
Copyright(c) 2015 Gabi Melman.
|
||||
Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <spdlog/common.h>
|
||||
|
||||
#include <atomic>
|
||||
#include <utility>
|
||||
|
||||
namespace spdlog
|
||||
{
|
||||
namespace details
|
||||
{
|
||||
|
||||
template<typename T>
|
||||
class mpmc_bounded_queue
|
||||
{
|
||||
public:
|
||||
|
||||
using item_type = T;
|
||||
mpmc_bounded_queue(size_t buffer_size)
|
||||
: buffer_(new cell_t [buffer_size]),
|
||||
buffer_mask_(buffer_size - 1)
|
||||
{
|
||||
//queue size must be power of two
|
||||
if(!((buffer_size >= 2) && ((buffer_size & (buffer_size - 1)) == 0)))
|
||||
throw spdlog_ex("async logger queue size must be power of two");
|
||||
|
||||
for (size_t i = 0; i != buffer_size; i += 1)
|
||||
buffer_[i].sequence_.store(i, std::memory_order_relaxed);
|
||||
enqueue_pos_.store(0, std::memory_order_relaxed);
|
||||
dequeue_pos_.store(0, std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
~mpmc_bounded_queue()
|
||||
{
|
||||
delete [] buffer_;
|
||||
}
|
||||
|
||||
|
||||
bool enqueue(T&& data)
|
||||
{
|
||||
cell_t* cell;
|
||||
size_t pos = enqueue_pos_.load(std::memory_order_relaxed);
|
||||
for (;;)
|
||||
{
|
||||
cell = &buffer_[pos & buffer_mask_];
|
||||
size_t seq = cell->sequence_.load(std::memory_order_acquire);
|
||||
intptr_t dif = (intptr_t)seq - (intptr_t)pos;
|
||||
if (dif == 0)
|
||||
{
|
||||
if (enqueue_pos_.compare_exchange_weak(pos, pos + 1, std::memory_order_relaxed))
|
||||
break;
|
||||
}
|
||||
else if (dif < 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
pos = enqueue_pos_.load(std::memory_order_relaxed);
|
||||
}
|
||||
}
|
||||
cell->data_ = std::move(data);
|
||||
cell->sequence_.store(pos + 1, std::memory_order_release);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool dequeue(T& data)
|
||||
{
|
||||
cell_t* cell;
|
||||
size_t pos = dequeue_pos_.load(std::memory_order_relaxed);
|
||||
for (;;)
|
||||
{
|
||||
cell = &buffer_[pos & buffer_mask_];
|
||||
size_t seq =
|
||||
cell->sequence_.load(std::memory_order_acquire);
|
||||
intptr_t dif = (intptr_t)seq - (intptr_t)(pos + 1);
|
||||
if (dif == 0)
|
||||
{
|
||||
if (dequeue_pos_.compare_exchange_weak(pos, pos + 1, std::memory_order_relaxed))
|
||||
break;
|
||||
}
|
||||
else if (dif < 0)
|
||||
return false;
|
||||
else
|
||||
pos = dequeue_pos_.load(std::memory_order_relaxed);
|
||||
}
|
||||
data = std::move(cell->data_);
|
||||
cell->sequence_.store(pos + buffer_mask_ + 1, std::memory_order_release);
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
struct cell_t
|
||||
{
|
||||
std::atomic<size_t> sequence_;
|
||||
T data_;
|
||||
};
|
||||
|
||||
static size_t const cacheline_size = 64;
|
||||
typedef char cacheline_pad_t [cacheline_size];
|
||||
|
||||
cacheline_pad_t pad0_;
|
||||
cell_t* const buffer_;
|
||||
size_t const buffer_mask_;
|
||||
cacheline_pad_t pad1_;
|
||||
std::atomic<size_t> enqueue_pos_;
|
||||
cacheline_pad_t pad2_;
|
||||
std::atomic<size_t> dequeue_pos_;
|
||||
cacheline_pad_t pad3_;
|
||||
|
||||
mpmc_bounded_queue(mpmc_bounded_queue const&);
|
||||
void operator = (mpmc_bounded_queue const&);
|
||||
};
|
||||
|
||||
} // ns details
|
||||
} // ns spdlog
|
||||
/*
|
||||
A modified version of Bounded MPMC queue by Dmitry Vyukov.
|
||||
|
||||
Original code from:
|
||||
http://www.1024cores.net/home/lock-free-algorithms/queues/bounded-mpmc-queue
|
||||
|
||||
licensed by Dmitry Vyukov under the terms below:
|
||||
|
||||
Simplified BSD license
|
||||
|
||||
Copyright (c) 2010-2011 Dmitry Vyukov. All rights reserved.
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
conditions and the following disclaimer.
|
||||
|
||||
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
|
||||
provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY DMITRY VYUKOV "AS IS" AND ANY EXPRESS OR IMPLIED
|
||||
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
||||
SHALL DMITRY VYUKOV OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
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
|
||||
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
/*
|
||||
The code in its current form adds the license below:
|
||||
|
||||
Copyright(c) 2015 Gabi Melman.
|
||||
Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <spdlog/common.h>
|
||||
|
||||
#include <atomic>
|
||||
#include <utility>
|
||||
|
||||
namespace spdlog
|
||||
{
|
||||
namespace details
|
||||
{
|
||||
|
||||
template<typename T>
|
||||
class mpmc_bounded_queue
|
||||
{
|
||||
public:
|
||||
|
||||
using item_type = T;
|
||||
mpmc_bounded_queue(size_t buffer_size)
|
||||
: buffer_(new cell_t [buffer_size]),
|
||||
buffer_mask_(buffer_size - 1)
|
||||
{
|
||||
//queue size must be power of two
|
||||
if(!((buffer_size >= 2) && ((buffer_size & (buffer_size - 1)) == 0)))
|
||||
throw spdlog_ex("async logger queue size must be power of two");
|
||||
|
||||
for (size_t i = 0; i != buffer_size; i += 1)
|
||||
buffer_[i].sequence_.store(i, std::memory_order_relaxed);
|
||||
enqueue_pos_.store(0, std::memory_order_relaxed);
|
||||
dequeue_pos_.store(0, std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
~mpmc_bounded_queue()
|
||||
{
|
||||
delete [] buffer_;
|
||||
}
|
||||
|
||||
|
||||
bool enqueue(T&& data)
|
||||
{
|
||||
cell_t* cell;
|
||||
size_t pos = enqueue_pos_.load(std::memory_order_relaxed);
|
||||
for (;;)
|
||||
{
|
||||
cell = &buffer_[pos & buffer_mask_];
|
||||
size_t seq = cell->sequence_.load(std::memory_order_acquire);
|
||||
intptr_t dif = (intptr_t)seq - (intptr_t)pos;
|
||||
if (dif == 0)
|
||||
{
|
||||
if (enqueue_pos_.compare_exchange_weak(pos, pos + 1, std::memory_order_relaxed))
|
||||
break;
|
||||
}
|
||||
else if (dif < 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
pos = enqueue_pos_.load(std::memory_order_relaxed);
|
||||
}
|
||||
}
|
||||
cell->data_ = std::move(data);
|
||||
cell->sequence_.store(pos + 1, std::memory_order_release);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool dequeue(T& data)
|
||||
{
|
||||
cell_t* cell;
|
||||
size_t pos = dequeue_pos_.load(std::memory_order_relaxed);
|
||||
for (;;)
|
||||
{
|
||||
cell = &buffer_[pos & buffer_mask_];
|
||||
size_t seq =
|
||||
cell->sequence_.load(std::memory_order_acquire);
|
||||
intptr_t dif = (intptr_t)seq - (intptr_t)(pos + 1);
|
||||
if (dif == 0)
|
||||
{
|
||||
if (dequeue_pos_.compare_exchange_weak(pos, pos + 1, std::memory_order_relaxed))
|
||||
break;
|
||||
}
|
||||
else if (dif < 0)
|
||||
return false;
|
||||
else
|
||||
pos = dequeue_pos_.load(std::memory_order_relaxed);
|
||||
}
|
||||
data = std::move(cell->data_);
|
||||
cell->sequence_.store(pos + buffer_mask_ + 1, std::memory_order_release);
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
struct cell_t
|
||||
{
|
||||
std::atomic<size_t> sequence_;
|
||||
T data_;
|
||||
};
|
||||
|
||||
static size_t const cacheline_size = 64;
|
||||
typedef char cacheline_pad_t [cacheline_size];
|
||||
|
||||
cacheline_pad_t pad0_;
|
||||
cell_t* const buffer_;
|
||||
size_t const buffer_mask_;
|
||||
cacheline_pad_t pad1_;
|
||||
std::atomic<size_t> enqueue_pos_;
|
||||
cacheline_pad_t pad2_;
|
||||
std::atomic<size_t> dequeue_pos_;
|
||||
cacheline_pad_t pad3_;
|
||||
|
||||
mpmc_bounded_queue(mpmc_bounded_queue const&);
|
||||
void operator = (mpmc_bounded_queue const&);
|
||||
};
|
||||
|
||||
} // ns details
|
||||
} // ns spdlog
|
||||
|
@ -24,21 +24,21 @@ struct null_mutex
|
||||
|
||||
struct null_atomic_int
|
||||
{
|
||||
int value;
|
||||
null_atomic_int() = default;
|
||||
int value;
|
||||
null_atomic_int() = default;
|
||||
|
||||
null_atomic_int(int val):value(val)
|
||||
{}
|
||||
null_atomic_int(int val):value(val)
|
||||
{}
|
||||
|
||||
int load(std::memory_order) const
|
||||
{
|
||||
return value;
|
||||
}
|
||||
int load(std::memory_order) const
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
void store(int val)
|
||||
{
|
||||
value = val;
|
||||
}
|
||||
void store(int val)
|
||||
{
|
||||
value = val;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -1,246 +1,246 @@
|
||||
//
|
||||
// Copyright(c) 2015 Gabi Melman.
|
||||
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||
//
|
||||
#pragma once
|
||||
|
||||
#include <spdlog/common.h>
|
||||
|
||||
#include <cstdio>
|
||||
#include <ctime>
|
||||
#include <functional>
|
||||
#include <string>
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
#ifndef NOMINMAX
|
||||
#define NOMINMAX //prevent windows redefining min/max
|
||||
#endif
|
||||
|
||||
#ifndef WIN32_LEAN_AND_MEAN
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#endif
|
||||
#include <windows.h>
|
||||
|
||||
#ifdef __MINGW32__
|
||||
#include <share.h>
|
||||
#endif
|
||||
|
||||
#elif __linux__
|
||||
#include <sys/syscall.h> //Use gettid() syscall under linux to get thread id
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <chrono>
|
||||
#else
|
||||
#include <thread>
|
||||
#endif
|
||||
|
||||
namespace spdlog
|
||||
{
|
||||
namespace details
|
||||
{
|
||||
namespace os
|
||||
{
|
||||
|
||||
inline spdlog::log_clock::time_point now()
|
||||
{
|
||||
|
||||
#if defined __linux__ && defined SPDLOG_CLOCK_COARSE
|
||||
timespec ts;
|
||||
::clock_gettime(CLOCK_REALTIME_COARSE, &ts);
|
||||
return std::chrono::time_point<log_clock, typename log_clock::duration>(
|
||||
std::chrono::duration_cast<typename log_clock::duration>(
|
||||
std::chrono::seconds(ts.tv_sec) + std::chrono::nanoseconds(ts.tv_nsec)));
|
||||
|
||||
|
||||
#else
|
||||
return log_clock::now();
|
||||
#endif
|
||||
|
||||
}
|
||||
inline std::tm localtime(const std::time_t &time_tt)
|
||||
{
|
||||
|
||||
#ifdef _WIN32
|
||||
std::tm tm;
|
||||
localtime_s(&tm, &time_tt);
|
||||
#else
|
||||
std::tm tm;
|
||||
localtime_r(&time_tt, &tm);
|
||||
#endif
|
||||
return tm;
|
||||
}
|
||||
|
||||
inline std::tm localtime()
|
||||
{
|
||||
std::time_t now_t = time(nullptr);
|
||||
return localtime(now_t);
|
||||
}
|
||||
|
||||
|
||||
inline std::tm gmtime(const std::time_t &time_tt)
|
||||
{
|
||||
|
||||
#ifdef _WIN32
|
||||
std::tm tm;
|
||||
gmtime_s(&tm, &time_tt);
|
||||
#else
|
||||
std::tm tm;
|
||||
gmtime_r(&time_tt, &tm);
|
||||
#endif
|
||||
return tm;
|
||||
}
|
||||
|
||||
inline std::tm gmtime()
|
||||
{
|
||||
std::time_t now_t = time(nullptr);
|
||||
return gmtime(now_t);
|
||||
}
|
||||
inline bool operator==(const std::tm& tm1, const std::tm& tm2)
|
||||
{
|
||||
return (tm1.tm_sec == tm2.tm_sec &&
|
||||
tm1.tm_min == tm2.tm_min &&
|
||||
tm1.tm_hour == tm2.tm_hour &&
|
||||
tm1.tm_mday == tm2.tm_mday &&
|
||||
tm1.tm_mon == tm2.tm_mon &&
|
||||
tm1.tm_year == tm2.tm_year &&
|
||||
tm1.tm_isdst == tm2.tm_isdst);
|
||||
}
|
||||
|
||||
inline bool operator!=(const std::tm& tm1, const std::tm& tm2)
|
||||
{
|
||||
return !(tm1 == tm2);
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
inline const char* eol()
|
||||
{
|
||||
return "\r\n";
|
||||
}
|
||||
#else
|
||||
constexpr inline const char* eol()
|
||||
{
|
||||
return "\n";
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
inline unsigned short eol_size()
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
#else
|
||||
constexpr inline unsigned short eol_size()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
//fopen_s on non windows for writing
|
||||
inline int fopen_s(FILE** fp, const filename_t& filename, const filename_t& mode)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
#ifdef SPDLOG_WCHAR_FILENAMES
|
||||
*fp = _wfsopen((filename.c_str()), mode.c_str(), _SH_DENYWR);
|
||||
#else
|
||||
*fp = _fsopen((filename.c_str()), mode.c_str(), _SH_DENYWR);
|
||||
#endif
|
||||
return *fp == nullptr;
|
||||
#else
|
||||
*fp = fopen((filename.c_str()), mode.c_str());
|
||||
return *fp == nullptr;
|
||||
#endif
|
||||
}
|
||||
|
||||
inline int remove(const filename_t &filename)
|
||||
{
|
||||
#if defined(_WIN32) && defined(SPDLOG_WCHAR_FILENAMES)
|
||||
return _wremove(filename.c_str());
|
||||
#else
|
||||
return std::remove(filename.c_str());
|
||||
#endif
|
||||
}
|
||||
|
||||
inline int rename(const filename_t& filename1, const filename_t& filename2)
|
||||
{
|
||||
#if defined(_WIN32) && defined(SPDLOG_WCHAR_FILENAMES)
|
||||
return _wrename(filename1.c_str(), filename2.c_str());
|
||||
#else
|
||||
return std::rename(filename1.c_str(), filename2.c_str());
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
//Return if file exists
|
||||
inline bool file_exists(const filename_t& filename)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
#ifdef SPDLOG_WCHAR_FILENAMES
|
||||
auto attribs = GetFileAttributesW(filename.c_str());
|
||||
#else
|
||||
auto attribs = GetFileAttributesA(filename.c_str());
|
||||
#endif
|
||||
return (attribs != INVALID_FILE_ATTRIBUTES && !(attribs & FILE_ATTRIBUTE_DIRECTORY));
|
||||
#elif __linux__
|
||||
struct stat buffer;
|
||||
return (stat (filename.c_str(), &buffer) == 0);
|
||||
#else
|
||||
auto *file = fopen(filename.c_str(), "r");
|
||||
if (file != nullptr)
|
||||
{
|
||||
fclose(file);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
//Return utc offset in minutes or throw spdlog_ex on failure
|
||||
inline int utc_minutes_offset(const std::tm& tm = details::os::localtime())
|
||||
{
|
||||
|
||||
#ifdef _WIN32
|
||||
#if _WIN32_WINNT < _WIN32_WINNT_WS08
|
||||
TIME_ZONE_INFORMATION tzinfo;
|
||||
auto rv = GetTimeZoneInformation(&tzinfo);
|
||||
#else
|
||||
DYNAMIC_TIME_ZONE_INFORMATION tzinfo;
|
||||
auto rv = GetDynamicTimeZoneInformation(&tzinfo);
|
||||
#endif
|
||||
if (rv == TIME_ZONE_ID_INVALID)
|
||||
throw spdlog::spdlog_ex("Failed getting timezone info. Last error: " + GetLastError());
|
||||
|
||||
int offset = -tzinfo.Bias;
|
||||
if (tm.tm_isdst)
|
||||
offset -= tzinfo.DaylightBias;
|
||||
else
|
||||
offset -= tzinfo.StandardBias;
|
||||
return offset;
|
||||
#else
|
||||
return static_cast<int>(tm.tm_gmtoff / 60);
|
||||
#endif
|
||||
}
|
||||
|
||||
//Return current thread id as size_t
|
||||
//It exists because the std::this_thread::get_id() is much slower(espcially under VS 2013)
|
||||
inline size_t thread_id()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
return static_cast<size_t>(::GetCurrentThreadId());
|
||||
#elif __linux__
|
||||
# if defined(__ANDROID__) && defined(__ANDROID_API__) && (__ANDROID_API__ < 21)
|
||||
# define SYS_gettid __NR_gettid
|
||||
# endif
|
||||
return static_cast<size_t>(syscall(SYS_gettid));
|
||||
#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()));
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
} //os
|
||||
} //details
|
||||
} //spdlog
|
||||
|
||||
|
||||
//
|
||||
// Copyright(c) 2015 Gabi Melman.
|
||||
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||
//
|
||||
#pragma once
|
||||
|
||||
#include <spdlog/common.h>
|
||||
|
||||
#include <cstdio>
|
||||
#include <ctime>
|
||||
#include <functional>
|
||||
#include <string>
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
#ifndef NOMINMAX
|
||||
#define NOMINMAX //prevent windows redefining min/max
|
||||
#endif
|
||||
|
||||
#ifndef WIN32_LEAN_AND_MEAN
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#endif
|
||||
#include <windows.h>
|
||||
|
||||
#ifdef __MINGW32__
|
||||
#include <share.h>
|
||||
#endif
|
||||
|
||||
#elif __linux__
|
||||
#include <sys/syscall.h> //Use gettid() syscall under linux to get thread id
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <chrono>
|
||||
#else
|
||||
#include <thread>
|
||||
#endif
|
||||
|
||||
namespace spdlog
|
||||
{
|
||||
namespace details
|
||||
{
|
||||
namespace os
|
||||
{
|
||||
|
||||
inline spdlog::log_clock::time_point now()
|
||||
{
|
||||
|
||||
#if defined __linux__ && defined SPDLOG_CLOCK_COARSE
|
||||
timespec ts;
|
||||
::clock_gettime(CLOCK_REALTIME_COARSE, &ts);
|
||||
return std::chrono::time_point<log_clock, typename log_clock::duration>(
|
||||
std::chrono::duration_cast<typename log_clock::duration>(
|
||||
std::chrono::seconds(ts.tv_sec) + std::chrono::nanoseconds(ts.tv_nsec)));
|
||||
|
||||
|
||||
#else
|
||||
return log_clock::now();
|
||||
#endif
|
||||
|
||||
}
|
||||
inline std::tm localtime(const std::time_t &time_tt)
|
||||
{
|
||||
|
||||
#ifdef _WIN32
|
||||
std::tm tm;
|
||||
localtime_s(&tm, &time_tt);
|
||||
#else
|
||||
std::tm tm;
|
||||
localtime_r(&time_tt, &tm);
|
||||
#endif
|
||||
return tm;
|
||||
}
|
||||
|
||||
inline std::tm localtime()
|
||||
{
|
||||
std::time_t now_t = time(nullptr);
|
||||
return localtime(now_t);
|
||||
}
|
||||
|
||||
|
||||
inline std::tm gmtime(const std::time_t &time_tt)
|
||||
{
|
||||
|
||||
#ifdef _WIN32
|
||||
std::tm tm;
|
||||
gmtime_s(&tm, &time_tt);
|
||||
#else
|
||||
std::tm tm;
|
||||
gmtime_r(&time_tt, &tm);
|
||||
#endif
|
||||
return tm;
|
||||
}
|
||||
|
||||
inline std::tm gmtime()
|
||||
{
|
||||
std::time_t now_t = time(nullptr);
|
||||
return gmtime(now_t);
|
||||
}
|
||||
inline bool operator==(const std::tm& tm1, const std::tm& tm2)
|
||||
{
|
||||
return (tm1.tm_sec == tm2.tm_sec &&
|
||||
tm1.tm_min == tm2.tm_min &&
|
||||
tm1.tm_hour == tm2.tm_hour &&
|
||||
tm1.tm_mday == tm2.tm_mday &&
|
||||
tm1.tm_mon == tm2.tm_mon &&
|
||||
tm1.tm_year == tm2.tm_year &&
|
||||
tm1.tm_isdst == tm2.tm_isdst);
|
||||
}
|
||||
|
||||
inline bool operator!=(const std::tm& tm1, const std::tm& tm2)
|
||||
{
|
||||
return !(tm1 == tm2);
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
inline const char* eol()
|
||||
{
|
||||
return "\r\n";
|
||||
}
|
||||
#else
|
||||
constexpr inline const char* eol()
|
||||
{
|
||||
return "\n";
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
inline unsigned short eol_size()
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
#else
|
||||
constexpr inline unsigned short eol_size()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
//fopen_s on non windows for writing
|
||||
inline int fopen_s(FILE** fp, const filename_t& filename, const filename_t& mode)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
#ifdef SPDLOG_WCHAR_FILENAMES
|
||||
*fp = _wfsopen((filename.c_str()), mode.c_str(), _SH_DENYWR);
|
||||
#else
|
||||
*fp = _fsopen((filename.c_str()), mode.c_str(), _SH_DENYWR);
|
||||
#endif
|
||||
return *fp == nullptr;
|
||||
#else
|
||||
*fp = fopen((filename.c_str()), mode.c_str());
|
||||
return *fp == nullptr;
|
||||
#endif
|
||||
}
|
||||
|
||||
inline int remove(const filename_t &filename)
|
||||
{
|
||||
#if defined(_WIN32) && defined(SPDLOG_WCHAR_FILENAMES)
|
||||
return _wremove(filename.c_str());
|
||||
#else
|
||||
return std::remove(filename.c_str());
|
||||
#endif
|
||||
}
|
||||
|
||||
inline int rename(const filename_t& filename1, const filename_t& filename2)
|
||||
{
|
||||
#if defined(_WIN32) && defined(SPDLOG_WCHAR_FILENAMES)
|
||||
return _wrename(filename1.c_str(), filename2.c_str());
|
||||
#else
|
||||
return std::rename(filename1.c_str(), filename2.c_str());
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
//Return if file exists
|
||||
inline bool file_exists(const filename_t& filename)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
#ifdef SPDLOG_WCHAR_FILENAMES
|
||||
auto attribs = GetFileAttributesW(filename.c_str());
|
||||
#else
|
||||
auto attribs = GetFileAttributesA(filename.c_str());
|
||||
#endif
|
||||
return (attribs != INVALID_FILE_ATTRIBUTES && !(attribs & FILE_ATTRIBUTE_DIRECTORY));
|
||||
#elif __linux__
|
||||
struct stat buffer;
|
||||
return (stat (filename.c_str(), &buffer) == 0);
|
||||
#else
|
||||
auto *file = fopen(filename.c_str(), "r");
|
||||
if (file != nullptr)
|
||||
{
|
||||
fclose(file);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
//Return utc offset in minutes or throw spdlog_ex on failure
|
||||
inline int utc_minutes_offset(const std::tm& tm = details::os::localtime())
|
||||
{
|
||||
|
||||
#ifdef _WIN32
|
||||
#if _WIN32_WINNT < _WIN32_WINNT_WS08
|
||||
TIME_ZONE_INFORMATION tzinfo;
|
||||
auto rv = GetTimeZoneInformation(&tzinfo);
|
||||
#else
|
||||
DYNAMIC_TIME_ZONE_INFORMATION tzinfo;
|
||||
auto rv = GetDynamicTimeZoneInformation(&tzinfo);
|
||||
#endif
|
||||
if (rv == TIME_ZONE_ID_INVALID)
|
||||
throw spdlog::spdlog_ex("Failed getting timezone info. Last error: " + GetLastError());
|
||||
|
||||
int offset = -tzinfo.Bias;
|
||||
if (tm.tm_isdst)
|
||||
offset -= tzinfo.DaylightBias;
|
||||
else
|
||||
offset -= tzinfo.StandardBias;
|
||||
return offset;
|
||||
#else
|
||||
return static_cast<int>(tm.tm_gmtoff / 60);
|
||||
#endif
|
||||
}
|
||||
|
||||
//Return current thread id as size_t
|
||||
//It exists because the std::this_thread::get_id() is much slower(espcially under VS 2013)
|
||||
inline size_t thread_id()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
return static_cast<size_t>(::GetCurrentThreadId());
|
||||
#elif __linux__
|
||||
# if defined(__ANDROID__) && defined(__ANDROID_API__) && (__ANDROID_API__ < 21)
|
||||
# define SYS_gettid __NR_gettid
|
||||
# endif
|
||||
return static_cast<size_t>(syscall(SYS_gettid));
|
||||
#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()));
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
} //os
|
||||
} //details
|
||||
} //spdlog
|
||||
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,163 +1,163 @@
|
||||
//
|
||||
// Copyright(c) 2015 Gabi Melman.
|
||||
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
// Loggers registy of unique name->logger pointer
|
||||
// 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
|
||||
// This class is thread safe
|
||||
|
||||
#include <spdlog/details/null_mutex.h>
|
||||
#include <spdlog/logger.h>
|
||||
#include <spdlog/async_logger.h>
|
||||
#include <spdlog/common.h>
|
||||
|
||||
#include <chrono>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace spdlog
|
||||
{
|
||||
namespace details
|
||||
{
|
||||
template <class Mutex> class registry_t
|
||||
{
|
||||
public:
|
||||
|
||||
void register_logger(std::shared_ptr<logger> logger)
|
||||
{
|
||||
std::lock_guard<Mutex> lock(_mutex);
|
||||
auto logger_name = logger->name();
|
||||
throw_if_exists(logger_name);
|
||||
_loggers[logger_name] = logger;
|
||||
}
|
||||
|
||||
|
||||
std::shared_ptr<logger> get(const std::string& logger_name)
|
||||
{
|
||||
std::lock_guard<Mutex> lock(_mutex);
|
||||
auto found = _loggers.find(logger_name);
|
||||
return found == _loggers.end() ? nullptr : found->second;
|
||||
}
|
||||
|
||||
template<class It>
|
||||
std::shared_ptr<logger> create(const std::string& logger_name, const It& sinks_begin, const It& sinks_end)
|
||||
{
|
||||
std::lock_guard<Mutex> lock(_mutex);
|
||||
throw_if_exists(logger_name);
|
||||
std::shared_ptr<logger> new_logger;
|
||||
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);
|
||||
else
|
||||
new_logger = std::make_shared<logger>(logger_name, sinks_begin, sinks_end);
|
||||
|
||||
if (_formatter)
|
||||
new_logger->set_formatter(_formatter);
|
||||
|
||||
new_logger->set_level(_level);
|
||||
//Add to registry
|
||||
_loggers[logger_name] = new_logger;
|
||||
return new_logger;
|
||||
}
|
||||
|
||||
void drop(const std::string& logger_name)
|
||||
{
|
||||
std::lock_guard<Mutex> lock(_mutex);
|
||||
_loggers.erase(logger_name);
|
||||
}
|
||||
|
||||
void drop_all()
|
||||
{
|
||||
std::lock_guard<Mutex> lock(_mutex);
|
||||
_loggers.clear();
|
||||
}
|
||||
std::shared_ptr<logger> create(const std::string& logger_name, sinks_init_list sinks)
|
||||
{
|
||||
return create(logger_name, sinks.begin(), sinks.end());
|
||||
}
|
||||
|
||||
std::shared_ptr<logger> create(const std::string& logger_name, sink_ptr sink)
|
||||
{
|
||||
return create(logger_name, { sink });
|
||||
}
|
||||
|
||||
|
||||
void formatter(formatter_ptr f)
|
||||
{
|
||||
std::lock_guard<Mutex> lock(_mutex);
|
||||
_formatter = f;
|
||||
for (auto& l : _loggers)
|
||||
l.second->set_formatter(_formatter);
|
||||
}
|
||||
|
||||
void set_pattern(const std::string& pattern)
|
||||
{
|
||||
std::lock_guard<Mutex> lock(_mutex);
|
||||
_formatter = std::make_shared<pattern_formatter>(pattern);
|
||||
for (auto& l : _loggers)
|
||||
l.second->set_formatter(_formatter);
|
||||
}
|
||||
|
||||
void set_level(level::level_enum log_level)
|
||||
{
|
||||
std::lock_guard<Mutex> lock(_mutex);
|
||||
for (auto& l : _loggers)
|
||||
l.second->set_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)
|
||||
{
|
||||
std::lock_guard<Mutex> lock(_mutex);
|
||||
_async_mode = true;
|
||||
_async_q_size = q_size;
|
||||
_overflow_policy = overflow_policy;
|
||||
_worker_warmup_cb = worker_warmup_cb;
|
||||
_flush_interval_ms = flush_interval_ms;
|
||||
}
|
||||
|
||||
void set_sync_mode()
|
||||
{
|
||||
std::lock_guard<Mutex> lock(_mutex);
|
||||
_async_mode = false;
|
||||
}
|
||||
|
||||
static registry_t<Mutex>& instance()
|
||||
{
|
||||
static registry_t<Mutex> s_instance;
|
||||
return s_instance;
|
||||
}
|
||||
|
||||
private:
|
||||
registry_t<Mutex>() {}
|
||||
registry_t<Mutex>(const registry_t<Mutex>&) = delete;
|
||||
registry_t<Mutex>& operator=(const registry_t<Mutex>&) = delete;
|
||||
|
||||
void throw_if_exists(const std::string &logger_name)
|
||||
{
|
||||
if (_loggers.find(logger_name) != _loggers.end())
|
||||
throw spdlog_ex("logger with name '" + logger_name + "' already exists");
|
||||
}
|
||||
Mutex _mutex;
|
||||
std::unordered_map <std::string, std::shared_ptr<logger>> _loggers;
|
||||
formatter_ptr _formatter;
|
||||
level::level_enum _level = level::info;
|
||||
bool _async_mode = false;
|
||||
size_t _async_q_size = 0;
|
||||
async_overflow_policy _overflow_policy = async_overflow_policy::block_retry;
|
||||
std::function<void()> _worker_warmup_cb = nullptr;
|
||||
std::chrono::milliseconds _flush_interval_ms;
|
||||
};
|
||||
#ifdef SPDLOG_NO_REGISTRY_MUTEX
|
||||
typedef registry_t<spdlog::details::null_mutex> registry;
|
||||
#else
|
||||
typedef registry_t<std::mutex> registry;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
//
|
||||
// Copyright(c) 2015 Gabi Melman.
|
||||
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
// Loggers registy of unique name->logger pointer
|
||||
// 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
|
||||
// This class is thread safe
|
||||
|
||||
#include <spdlog/details/null_mutex.h>
|
||||
#include <spdlog/logger.h>
|
||||
#include <spdlog/async_logger.h>
|
||||
#include <spdlog/common.h>
|
||||
|
||||
#include <chrono>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace spdlog
|
||||
{
|
||||
namespace details
|
||||
{
|
||||
template <class Mutex> class registry_t
|
||||
{
|
||||
public:
|
||||
|
||||
void register_logger(std::shared_ptr<logger> logger)
|
||||
{
|
||||
std::lock_guard<Mutex> lock(_mutex);
|
||||
auto logger_name = logger->name();
|
||||
throw_if_exists(logger_name);
|
||||
_loggers[logger_name] = logger;
|
||||
}
|
||||
|
||||
|
||||
std::shared_ptr<logger> get(const std::string& logger_name)
|
||||
{
|
||||
std::lock_guard<Mutex> lock(_mutex);
|
||||
auto found = _loggers.find(logger_name);
|
||||
return found == _loggers.end() ? nullptr : found->second;
|
||||
}
|
||||
|
||||
template<class It>
|
||||
std::shared_ptr<logger> create(const std::string& logger_name, const It& sinks_begin, const It& sinks_end)
|
||||
{
|
||||
std::lock_guard<Mutex> lock(_mutex);
|
||||
throw_if_exists(logger_name);
|
||||
std::shared_ptr<logger> new_logger;
|
||||
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);
|
||||
else
|
||||
new_logger = std::make_shared<logger>(logger_name, sinks_begin, sinks_end);
|
||||
|
||||
if (_formatter)
|
||||
new_logger->set_formatter(_formatter);
|
||||
|
||||
new_logger->set_level(_level);
|
||||
//Add to registry
|
||||
_loggers[logger_name] = new_logger;
|
||||
return new_logger;
|
||||
}
|
||||
|
||||
void drop(const std::string& logger_name)
|
||||
{
|
||||
std::lock_guard<Mutex> lock(_mutex);
|
||||
_loggers.erase(logger_name);
|
||||
}
|
||||
|
||||
void drop_all()
|
||||
{
|
||||
std::lock_guard<Mutex> lock(_mutex);
|
||||
_loggers.clear();
|
||||
}
|
||||
std::shared_ptr<logger> create(const std::string& logger_name, sinks_init_list sinks)
|
||||
{
|
||||
return create(logger_name, sinks.begin(), sinks.end());
|
||||
}
|
||||
|
||||
std::shared_ptr<logger> create(const std::string& logger_name, sink_ptr sink)
|
||||
{
|
||||
return create(logger_name, { sink });
|
||||
}
|
||||
|
||||
|
||||
void formatter(formatter_ptr f)
|
||||
{
|
||||
std::lock_guard<Mutex> lock(_mutex);
|
||||
_formatter = f;
|
||||
for (auto& l : _loggers)
|
||||
l.second->set_formatter(_formatter);
|
||||
}
|
||||
|
||||
void set_pattern(const std::string& pattern)
|
||||
{
|
||||
std::lock_guard<Mutex> lock(_mutex);
|
||||
_formatter = std::make_shared<pattern_formatter>(pattern);
|
||||
for (auto& l : _loggers)
|
||||
l.second->set_formatter(_formatter);
|
||||
}
|
||||
|
||||
void set_level(level::level_enum log_level)
|
||||
{
|
||||
std::lock_guard<Mutex> lock(_mutex);
|
||||
for (auto& l : _loggers)
|
||||
l.second->set_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)
|
||||
{
|
||||
std::lock_guard<Mutex> lock(_mutex);
|
||||
_async_mode = true;
|
||||
_async_q_size = q_size;
|
||||
_overflow_policy = overflow_policy;
|
||||
_worker_warmup_cb = worker_warmup_cb;
|
||||
_flush_interval_ms = flush_interval_ms;
|
||||
}
|
||||
|
||||
void set_sync_mode()
|
||||
{
|
||||
std::lock_guard<Mutex> lock(_mutex);
|
||||
_async_mode = false;
|
||||
}
|
||||
|
||||
static registry_t<Mutex>& instance()
|
||||
{
|
||||
static registry_t<Mutex> s_instance;
|
||||
return s_instance;
|
||||
}
|
||||
|
||||
private:
|
||||
registry_t<Mutex>() {}
|
||||
registry_t<Mutex>(const registry_t<Mutex>&) = delete;
|
||||
registry_t<Mutex>& operator=(const registry_t<Mutex>&) = delete;
|
||||
|
||||
void throw_if_exists(const std::string &logger_name)
|
||||
{
|
||||
if (_loggers.find(logger_name) != _loggers.end())
|
||||
throw spdlog_ex("logger with name '" + logger_name + "' already exists");
|
||||
}
|
||||
Mutex _mutex;
|
||||
std::unordered_map <std::string, std::shared_ptr<logger>> _loggers;
|
||||
formatter_ptr _formatter;
|
||||
level::level_enum _level = level::info;
|
||||
bool _async_mode = false;
|
||||
size_t _async_q_size = 0;
|
||||
async_overflow_policy _overflow_policy = async_overflow_policy::block_retry;
|
||||
std::function<void()> _worker_warmup_cb = nullptr;
|
||||
std::chrono::milliseconds _flush_interval_ms;
|
||||
};
|
||||
#ifdef SPDLOG_NO_REGISTRY_MUTEX
|
||||
typedef registry_t<spdlog::details::null_mutex> registry;
|
||||
#else
|
||||
typedef registry_t<std::mutex> registry;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
@ -1,149 +1,149 @@
|
||||
//
|
||||
// Copyright(c) 2015 Gabi Melman.
|
||||
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
//
|
||||
// Global registry functions
|
||||
//
|
||||
#include <spdlog/spdlog.h>
|
||||
#include <spdlog/details/registry.h>
|
||||
#include <spdlog/sinks/file_sinks.h>
|
||||
#include <spdlog/sinks/stdout_sinks.h>
|
||||
#include <spdlog/sinks/syslog_sink.h>
|
||||
#include <spdlog/sinks/ansicolor_sink.h>
|
||||
|
||||
#include <chrono>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
inline void spdlog::register_logger(std::shared_ptr<logger> logger)
|
||||
{
|
||||
return details::registry::instance().register_logger(logger);
|
||||
}
|
||||
|
||||
inline std::shared_ptr<spdlog::logger> spdlog::get(const std::string& name)
|
||||
{
|
||||
return details::registry::instance().get(name);
|
||||
}
|
||||
|
||||
inline void spdlog::drop(const std::string &name)
|
||||
{
|
||||
details::registry::instance().drop(name);
|
||||
}
|
||||
|
||||
// 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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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):
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
// 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)
|
||||
{
|
||||
if (color) //use color wrapper sink
|
||||
sink = std::make_shared<spdlog::sinks::ansicolor_sink>(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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
return create_console_logger(logger_name, sinks::stderr_sink_st::instance(), color);
|
||||
}
|
||||
|
||||
#if defined(__linux__) || defined(__APPLE__)
|
||||
// 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)
|
||||
{
|
||||
return create<spdlog::sinks::syslog_sink>(logger_name, syslog_ident, syslog_option);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
//Create logger with multiple 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);
|
||||
}
|
||||
|
||||
|
||||
template <typename Sink, typename... Args>
|
||||
inline std::shared_ptr<spdlog::logger> spdlog::create(const std::string& logger_name, Args... args)
|
||||
{
|
||||
sink_ptr sink = std::make_shared<Sink>(args...);
|
||||
return details::registry::instance().create(logger_name, { sink });
|
||||
}
|
||||
|
||||
|
||||
template<class It>
|
||||
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);
|
||||
}
|
||||
|
||||
inline void spdlog::set_formatter(spdlog::formatter_ptr f)
|
||||
{
|
||||
details::registry::instance().formatter(f);
|
||||
}
|
||||
|
||||
inline void spdlog::set_pattern(const std::string& format_string)
|
||||
{
|
||||
return details::registry::instance().set_pattern(format_string);
|
||||
}
|
||||
|
||||
inline void spdlog::set_level(level::level_enum 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)
|
||||
{
|
||||
details::registry::instance().set_async_mode(queue_size, overflow_policy, worker_warmup_cb, flush_interval_ms);
|
||||
}
|
||||
|
||||
inline void spdlog::set_sync_mode()
|
||||
{
|
||||
details::registry::instance().set_sync_mode();
|
||||
}
|
||||
|
||||
inline void spdlog::drop_all()
|
||||
{
|
||||
details::registry::instance().drop_all();
|
||||
}
|
||||
|
||||
//
|
||||
// Copyright(c) 2015 Gabi Melman.
|
||||
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
//
|
||||
// Global registry functions
|
||||
//
|
||||
#include <spdlog/spdlog.h>
|
||||
#include <spdlog/details/registry.h>
|
||||
#include <spdlog/sinks/file_sinks.h>
|
||||
#include <spdlog/sinks/stdout_sinks.h>
|
||||
#include <spdlog/sinks/syslog_sink.h>
|
||||
#include <spdlog/sinks/ansicolor_sink.h>
|
||||
|
||||
#include <chrono>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
inline void spdlog::register_logger(std::shared_ptr<logger> logger)
|
||||
{
|
||||
return details::registry::instance().register_logger(logger);
|
||||
}
|
||||
|
||||
inline std::shared_ptr<spdlog::logger> spdlog::get(const std::string& name)
|
||||
{
|
||||
return details::registry::instance().get(name);
|
||||
}
|
||||
|
||||
inline void spdlog::drop(const std::string &name)
|
||||
{
|
||||
details::registry::instance().drop(name);
|
||||
}
|
||||
|
||||
// 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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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):
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
// 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)
|
||||
{
|
||||
if (color) //use color wrapper sink
|
||||
sink = std::make_shared<spdlog::sinks::ansicolor_sink>(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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
return create_console_logger(logger_name, sinks::stderr_sink_st::instance(), color);
|
||||
}
|
||||
|
||||
#if defined(__linux__) || defined(__APPLE__)
|
||||
// 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)
|
||||
{
|
||||
return create<spdlog::sinks::syslog_sink>(logger_name, syslog_ident, syslog_option);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
//Create logger with multiple 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);
|
||||
}
|
||||
|
||||
|
||||
template <typename Sink, typename... Args>
|
||||
inline std::shared_ptr<spdlog::logger> spdlog::create(const std::string& logger_name, Args... args)
|
||||
{
|
||||
sink_ptr sink = std::make_shared<Sink>(args...);
|
||||
return details::registry::instance().create(logger_name, { sink });
|
||||
}
|
||||
|
||||
|
||||
template<class It>
|
||||
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);
|
||||
}
|
||||
|
||||
inline void spdlog::set_formatter(spdlog::formatter_ptr f)
|
||||
{
|
||||
details::registry::instance().formatter(f);
|
||||
}
|
||||
|
||||
inline void spdlog::set_pattern(const std::string& format_string)
|
||||
{
|
||||
return details::registry::instance().set_pattern(format_string);
|
||||
}
|
||||
|
||||
inline void spdlog::set_level(level::level_enum 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)
|
||||
{
|
||||
details::registry::instance().set_async_mode(queue_size, overflow_policy, worker_warmup_cb, flush_interval_ms);
|
||||
}
|
||||
|
||||
inline void spdlog::set_sync_mode()
|
||||
{
|
||||
details::registry::instance().set_sync_mode();
|
||||
}
|
||||
|
||||
inline void spdlog::drop_all()
|
||||
{
|
||||
details::registry::instance().drop_all();
|
||||
}
|
||||
|
||||
|
@ -1,45 +1,45 @@
|
||||
//
|
||||
// Copyright(c) 2015 Gabi Melman.
|
||||
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <spdlog/details/log_msg.h>
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <memory>
|
||||
|
||||
namespace spdlog
|
||||
{
|
||||
namespace details
|
||||
{
|
||||
class flag_formatter;
|
||||
}
|
||||
|
||||
class formatter
|
||||
{
|
||||
public:
|
||||
virtual ~formatter() {}
|
||||
virtual void format(details::log_msg& msg) = 0;
|
||||
};
|
||||
|
||||
class pattern_formatter : public formatter
|
||||
{
|
||||
|
||||
public:
|
||||
explicit pattern_formatter(const std::string& pattern);
|
||||
pattern_formatter(const pattern_formatter&) = delete;
|
||||
pattern_formatter& operator=(const pattern_formatter&) = delete;
|
||||
void format(details::log_msg& msg) override;
|
||||
private:
|
||||
const std::string _pattern;
|
||||
std::vector<std::unique_ptr<details::flag_formatter>> _formatters;
|
||||
void handle_flag(char flag);
|
||||
void compile_pattern(const std::string& pattern);
|
||||
};
|
||||
}
|
||||
|
||||
#include <spdlog/details/pattern_formatter_impl.h>
|
||||
|
||||
//
|
||||
// Copyright(c) 2015 Gabi Melman.
|
||||
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <spdlog/details/log_msg.h>
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <memory>
|
||||
|
||||
namespace spdlog
|
||||
{
|
||||
namespace details
|
||||
{
|
||||
class flag_formatter;
|
||||
}
|
||||
|
||||
class formatter
|
||||
{
|
||||
public:
|
||||
virtual ~formatter() {}
|
||||
virtual void format(details::log_msg& msg) = 0;
|
||||
};
|
||||
|
||||
class pattern_formatter : public formatter
|
||||
{
|
||||
|
||||
public:
|
||||
explicit pattern_formatter(const std::string& pattern);
|
||||
pattern_formatter(const pattern_formatter&) = delete;
|
||||
pattern_formatter& operator=(const pattern_formatter&) = delete;
|
||||
void format(details::log_msg& msg) override;
|
||||
private:
|
||||
const std::string _pattern;
|
||||
std::vector<std::unique_ptr<details::flag_formatter>> _formatters;
|
||||
void handle_flag(char flag);
|
||||
void compile_pattern(const std::string& pattern);
|
||||
};
|
||||
}
|
||||
|
||||
#include <spdlog/details/pattern_formatter_impl.h>
|
||||
|
||||
|
@ -1,112 +1,112 @@
|
||||
//
|
||||
// Copyright(c) 2015 Gabi Melman.
|
||||
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
// Thread safe logger
|
||||
// Has name, log level, vector of std::shared sink pointers and formatter
|
||||
// Upon each log write the logger:
|
||||
// 1. Checks if its log level is enough to log the message
|
||||
// 2. Format the message using the formatter function
|
||||
// 3. Pass the formatted message to its sinks to performa the actual logging
|
||||
|
||||
#include <spdlog/sinks/base_sink.h>
|
||||
#include <spdlog/common.h>
|
||||
#include <spdlog/details/line_logger_fwd.h>
|
||||
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
namespace spdlog
|
||||
{
|
||||
|
||||
class logger
|
||||
{
|
||||
public:
|
||||
logger(const std::string& logger_name, sink_ptr single_sink);
|
||||
logger(const std::string& name, sinks_init_list);
|
||||
template<class It>
|
||||
logger(const std::string& name, const It& begin, const It& end);
|
||||
|
||||
virtual ~logger();
|
||||
logger(const logger&) = delete;
|
||||
logger& operator=(const logger&) = delete;
|
||||
|
||||
void set_level(level::level_enum);
|
||||
level::level_enum level() const;
|
||||
|
||||
const std::string& name() const;
|
||||
bool should_log(level::level_enum) const;
|
||||
|
||||
// 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 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 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 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 alert(const char* fmt, const Args&... args);
|
||||
template <typename... Args> details::line_logger emerg(const char* fmt, const Args&... args);
|
||||
|
||||
|
||||
// logger.info(msg) << ".." call style
|
||||
template <typename T> details::line_logger trace(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 notice(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 critical(const T&);
|
||||
template <typename T> details::line_logger alert(const T&);
|
||||
template <typename T> details::line_logger emerg(const T&);
|
||||
|
||||
|
||||
// logger.info() << ".." call style
|
||||
details::line_logger trace();
|
||||
details::line_logger debug();
|
||||
details::line_logger info();
|
||||
details::line_logger notice();
|
||||
details::line_logger warn();
|
||||
details::line_logger error();
|
||||
details::line_logger critical();
|
||||
details::line_logger alert();
|
||||
details::line_logger emerg();
|
||||
|
||||
|
||||
|
||||
// Create log message with the given level, no matter what is the actual logger's level
|
||||
template <typename... 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
|
||||
void set_pattern(const std::string&);
|
||||
void set_formatter(formatter_ptr);
|
||||
|
||||
virtual void flush();
|
||||
|
||||
protected:
|
||||
virtual void _log_msg(details::log_msg&);
|
||||
virtual void _set_pattern(const std::string&);
|
||||
virtual void _set_formatter(formatter_ptr);
|
||||
details::line_logger _log_if_enabled(level::level_enum lvl);
|
||||
template <typename... Args>
|
||||
details::line_logger _log_if_enabled(level::level_enum lvl, const char* fmt, const Args&... args);
|
||||
template<typename T>
|
||||
inline details::line_logger _log_if_enabled(level::level_enum lvl, const T& msg);
|
||||
|
||||
|
||||
friend details::line_logger;
|
||||
std::string _name;
|
||||
std::vector<sink_ptr> _sinks;
|
||||
formatter_ptr _formatter;
|
||||
spdlog::level_t _level;
|
||||
};
|
||||
}
|
||||
|
||||
#include <spdlog/details/logger_impl.h>
|
||||
#include <spdlog/details/line_logger_impl.h>
|
||||
|
||||
//
|
||||
// Copyright(c) 2015 Gabi Melman.
|
||||
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
// Thread safe logger
|
||||
// Has name, log level, vector of std::shared sink pointers and formatter
|
||||
// Upon each log write the logger:
|
||||
// 1. Checks if its log level is enough to log the message
|
||||
// 2. Format the message using the formatter function
|
||||
// 3. Pass the formatted message to its sinks to performa the actual logging
|
||||
|
||||
#include <spdlog/sinks/base_sink.h>
|
||||
#include <spdlog/common.h>
|
||||
#include <spdlog/details/line_logger_fwd.h>
|
||||
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
namespace spdlog
|
||||
{
|
||||
|
||||
class logger
|
||||
{
|
||||
public:
|
||||
logger(const std::string& logger_name, sink_ptr single_sink);
|
||||
logger(const std::string& name, sinks_init_list);
|
||||
template<class It>
|
||||
logger(const std::string& name, const It& begin, const It& end);
|
||||
|
||||
virtual ~logger();
|
||||
logger(const logger&) = delete;
|
||||
logger& operator=(const logger&) = delete;
|
||||
|
||||
void set_level(level::level_enum);
|
||||
level::level_enum level() const;
|
||||
|
||||
const std::string& name() const;
|
||||
bool should_log(level::level_enum) const;
|
||||
|
||||
// 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 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 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 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 alert(const char* fmt, const Args&... args);
|
||||
template <typename... Args> details::line_logger emerg(const char* fmt, const Args&... args);
|
||||
|
||||
|
||||
// logger.info(msg) << ".." call style
|
||||
template <typename T> details::line_logger trace(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 notice(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 critical(const T&);
|
||||
template <typename T> details::line_logger alert(const T&);
|
||||
template <typename T> details::line_logger emerg(const T&);
|
||||
|
||||
|
||||
// logger.info() << ".." call style
|
||||
details::line_logger trace();
|
||||
details::line_logger debug();
|
||||
details::line_logger info();
|
||||
details::line_logger notice();
|
||||
details::line_logger warn();
|
||||
details::line_logger error();
|
||||
details::line_logger critical();
|
||||
details::line_logger alert();
|
||||
details::line_logger emerg();
|
||||
|
||||
|
||||
|
||||
// Create log message with the given level, no matter what is the actual logger's level
|
||||
template <typename... 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
|
||||
void set_pattern(const std::string&);
|
||||
void set_formatter(formatter_ptr);
|
||||
|
||||
virtual void flush();
|
||||
|
||||
protected:
|
||||
virtual void _log_msg(details::log_msg&);
|
||||
virtual void _set_pattern(const std::string&);
|
||||
virtual void _set_formatter(formatter_ptr);
|
||||
details::line_logger _log_if_enabled(level::level_enum lvl);
|
||||
template <typename... Args>
|
||||
details::line_logger _log_if_enabled(level::level_enum lvl, const char* fmt, const Args&... args);
|
||||
template<typename T>
|
||||
inline details::line_logger _log_if_enabled(level::level_enum lvl, const T& msg);
|
||||
|
||||
|
||||
friend details::line_logger;
|
||||
std::string _name;
|
||||
std::vector<sink_ptr> _sinks;
|
||||
formatter_ptr _formatter;
|
||||
spdlog::level_t _level;
|
||||
};
|
||||
}
|
||||
|
||||
#include <spdlog/details/logger_impl.h>
|
||||
#include <spdlog/details/line_logger_impl.h>
|
||||
|
||||
|
@ -1,92 +1,92 @@
|
||||
//
|
||||
// Copyright(c) 2015 Gabi Melman.
|
||||
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#if defined(__ANDROID__)
|
||||
|
||||
#include <spdlog/sinks/base_sink.h>
|
||||
#include <spdlog/details/null_mutex.h>
|
||||
|
||||
#include <android/log.h>
|
||||
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
|
||||
namespace spdlog
|
||||
{
|
||||
namespace sinks
|
||||
{
|
||||
/*
|
||||
* Android sink (logging using __android_log_write)
|
||||
*/
|
||||
template<class Mutex>
|
||||
class base_android_sink : public base_sink < Mutex >
|
||||
{
|
||||
public:
|
||||
explicit base_android_sink(std::string tag="spdlog"): _tag(tag)
|
||||
{
|
||||
}
|
||||
|
||||
void flush() override
|
||||
{
|
||||
}
|
||||
|
||||
protected:
|
||||
void _sink_it(const details::log_msg& msg) override
|
||||
{
|
||||
const android_LogPriority priority = convert_to_android(msg.level);
|
||||
const int expected_size = msg.formatted.size();
|
||||
const int size = __android_log_write(
|
||||
priority, _tag.c_str(), msg.formatted.c_str()
|
||||
);
|
||||
if (size > expected_size)
|
||||
{
|
||||
// Will write a little bit more than original message
|
||||
}
|
||||
else
|
||||
{
|
||||
throw spdlog_ex("Send to Android logcat failed");
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
static android_LogPriority convert_to_android(spdlog::level::level_enum level)
|
||||
{
|
||||
switch(level)
|
||||
{
|
||||
case spdlog::level::trace:
|
||||
return ANDROID_LOG_VERBOSE;
|
||||
case spdlog::level::debug:
|
||||
return ANDROID_LOG_DEBUG;
|
||||
case spdlog::level::info:
|
||||
return ANDROID_LOG_INFO;
|
||||
case spdlog::level::notice:
|
||||
return ANDROID_LOG_INFO;
|
||||
case spdlog::level::warn:
|
||||
return ANDROID_LOG_WARN;
|
||||
case spdlog::level::err:
|
||||
return ANDROID_LOG_ERROR;
|
||||
case spdlog::level::critical:
|
||||
return ANDROID_LOG_FATAL;
|
||||
case spdlog::level::alert:
|
||||
return ANDROID_LOG_FATAL;
|
||||
case spdlog::level::emerg:
|
||||
return ANDROID_LOG_FATAL;
|
||||
default:
|
||||
throw spdlog_ex("Incorrect level value");
|
||||
}
|
||||
}
|
||||
|
||||
std::string _tag;
|
||||
};
|
||||
|
||||
typedef base_android_sink<std::mutex> android_sink_mt;
|
||||
typedef base_android_sink<details::null_mutex> android_sink_st;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
//
|
||||
// Copyright(c) 2015 Gabi Melman.
|
||||
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#if defined(__ANDROID__)
|
||||
|
||||
#include <spdlog/sinks/base_sink.h>
|
||||
#include <spdlog/details/null_mutex.h>
|
||||
|
||||
#include <android/log.h>
|
||||
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
|
||||
namespace spdlog
|
||||
{
|
||||
namespace sinks
|
||||
{
|
||||
/*
|
||||
* Android sink (logging using __android_log_write)
|
||||
*/
|
||||
template<class Mutex>
|
||||
class base_android_sink : public base_sink < Mutex >
|
||||
{
|
||||
public:
|
||||
explicit base_android_sink(std::string tag="spdlog"): _tag(tag)
|
||||
{
|
||||
}
|
||||
|
||||
void flush() override
|
||||
{
|
||||
}
|
||||
|
||||
protected:
|
||||
void _sink_it(const details::log_msg& msg) override
|
||||
{
|
||||
const android_LogPriority priority = convert_to_android(msg.level);
|
||||
const int expected_size = msg.formatted.size();
|
||||
const int size = __android_log_write(
|
||||
priority, _tag.c_str(), msg.formatted.c_str()
|
||||
);
|
||||
if (size > expected_size)
|
||||
{
|
||||
// Will write a little bit more than original message
|
||||
}
|
||||
else
|
||||
{
|
||||
throw spdlog_ex("Send to Android logcat failed");
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
static android_LogPriority convert_to_android(spdlog::level::level_enum level)
|
||||
{
|
||||
switch(level)
|
||||
{
|
||||
case spdlog::level::trace:
|
||||
return ANDROID_LOG_VERBOSE;
|
||||
case spdlog::level::debug:
|
||||
return ANDROID_LOG_DEBUG;
|
||||
case spdlog::level::info:
|
||||
return ANDROID_LOG_INFO;
|
||||
case spdlog::level::notice:
|
||||
return ANDROID_LOG_INFO;
|
||||
case spdlog::level::warn:
|
||||
return ANDROID_LOG_WARN;
|
||||
case spdlog::level::err:
|
||||
return ANDROID_LOG_ERROR;
|
||||
case spdlog::level::critical:
|
||||
return ANDROID_LOG_FATAL;
|
||||
case spdlog::level::alert:
|
||||
return ANDROID_LOG_FATAL;
|
||||
case spdlog::level::emerg:
|
||||
return ANDROID_LOG_FATAL;
|
||||
default:
|
||||
throw spdlog_ex("Incorrect level value");
|
||||
}
|
||||
}
|
||||
|
||||
std::string _tag;
|
||||
};
|
||||
|
||||
typedef base_android_sink<std::mutex> android_sink_mt;
|
||||
typedef base_android_sink<details::null_mutex> android_sink_st;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -1,115 +1,115 @@
|
||||
//
|
||||
// Copyright(c) 2016 Kevin M. Godby (a modified version by spdlog).
|
||||
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <spdlog/sinks/base_sink.h>
|
||||
#include <spdlog/common.h>
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
|
||||
namespace spdlog
|
||||
{
|
||||
namespace sinks
|
||||
{
|
||||
|
||||
/**
|
||||
* @brief The ansi_color_sink is a decorator around another sink and prefixes
|
||||
* the output with an ANSI escape sequence color code depending on the severity
|
||||
* of the message.
|
||||
*/
|
||||
class ansicolor_sink : public sink
|
||||
{
|
||||
public:
|
||||
ansicolor_sink(sink_ptr wrapped_sink);
|
||||
virtual ~ansicolor_sink();
|
||||
|
||||
ansicolor_sink(const ansicolor_sink& other) = delete;
|
||||
ansicolor_sink& operator=(const ansicolor_sink& other) = delete;
|
||||
|
||||
virtual void log(const details::log_msg& msg) override;
|
||||
virtual void flush() override;
|
||||
|
||||
void set_color(level::level_enum level, const std::string& color);
|
||||
|
||||
/// Formatting codes
|
||||
const std::string reset = "\033[00m";
|
||||
const std::string bold = "\033[1m";
|
||||
const std::string dark = "\033[2m";
|
||||
const std::string underline = "\033[4m";
|
||||
const std::string blink = "\033[5m";
|
||||
const std::string reverse = "\033[7m";
|
||||
const std::string concealed = "\033[8m";
|
||||
|
||||
// Foreground colors
|
||||
const std::string grey = "\033[30m";
|
||||
const std::string red = "\033[31m";
|
||||
const std::string green = "\033[32m";
|
||||
const std::string yellow = "\033[33m";
|
||||
const std::string blue = "\033[34m";
|
||||
const std::string magenta = "\033[35m";
|
||||
const std::string cyan = "\033[36m";
|
||||
const std::string white = "\033[37m";
|
||||
|
||||
/// Background colors
|
||||
const std::string on_grey = "\033[40m";
|
||||
const std::string on_red = "\033[41m";
|
||||
const std::string on_green = "\033[42m";
|
||||
const std::string on_yellow = "\033[43m";
|
||||
const std::string on_blue = "\033[44m";
|
||||
const std::string on_magenta = "\033[45m";
|
||||
const std::string on_cyan = "\033[46m";
|
||||
const std::string on_white = "\033[47m";
|
||||
|
||||
|
||||
protected:
|
||||
sink_ptr sink_;
|
||||
std::map<level::level_enum, std::string> colors_;
|
||||
};
|
||||
|
||||
inline ansicolor_sink::ansicolor_sink(sink_ptr wrapped_sink) : sink_(wrapped_sink)
|
||||
{
|
||||
colors_[level::trace] = cyan;
|
||||
colors_[level::debug] = cyan;
|
||||
colors_[level::info] = white;
|
||||
colors_[level::notice] = bold + white;
|
||||
colors_[level::warn] = bold + yellow;
|
||||
colors_[level::err] = red;
|
||||
colors_[level::critical] = bold + red;
|
||||
colors_[level::alert] = bold + white + on_red;
|
||||
colors_[level::emerg] = bold + yellow + on_red;
|
||||
colors_[level::off] = reset;
|
||||
}
|
||||
|
||||
inline void ansicolor_sink::log(const details::log_msg& msg)
|
||||
{
|
||||
// Wrap the originally formatted message in color codes
|
||||
const std::string& prefix = colors_[msg.level];
|
||||
const std::string& s = msg.formatted.str();
|
||||
const std::string& suffix = reset;
|
||||
details::log_msg m;
|
||||
m.formatted << prefix << s << suffix;
|
||||
sink_->log(m);
|
||||
}
|
||||
|
||||
inline void ansicolor_sink::flush()
|
||||
{
|
||||
sink_->flush();
|
||||
}
|
||||
|
||||
inline void ansicolor_sink::set_color(level::level_enum level, const std::string& color)
|
||||
{
|
||||
colors_[level] = color;
|
||||
}
|
||||
|
||||
inline ansicolor_sink::~ansicolor_sink()
|
||||
{
|
||||
flush();
|
||||
}
|
||||
|
||||
} // namespace sinks
|
||||
} // namespace spdlog
|
||||
|
||||
//
|
||||
// Copyright(c) 2016 Kevin M. Godby (a modified version by spdlog).
|
||||
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <spdlog/sinks/base_sink.h>
|
||||
#include <spdlog/common.h>
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
|
||||
namespace spdlog
|
||||
{
|
||||
namespace sinks
|
||||
{
|
||||
|
||||
/**
|
||||
* @brief The ansi_color_sink is a decorator around another sink and prefixes
|
||||
* the output with an ANSI escape sequence color code depending on the severity
|
||||
* of the message.
|
||||
*/
|
||||
class ansicolor_sink : public sink
|
||||
{
|
||||
public:
|
||||
ansicolor_sink(sink_ptr wrapped_sink);
|
||||
virtual ~ansicolor_sink();
|
||||
|
||||
ansicolor_sink(const ansicolor_sink& other) = delete;
|
||||
ansicolor_sink& operator=(const ansicolor_sink& other) = delete;
|
||||
|
||||
virtual void log(const details::log_msg& msg) override;
|
||||
virtual void flush() override;
|
||||
|
||||
void set_color(level::level_enum level, const std::string& color);
|
||||
|
||||
/// Formatting codes
|
||||
const std::string reset = "\033[00m";
|
||||
const std::string bold = "\033[1m";
|
||||
const std::string dark = "\033[2m";
|
||||
const std::string underline = "\033[4m";
|
||||
const std::string blink = "\033[5m";
|
||||
const std::string reverse = "\033[7m";
|
||||
const std::string concealed = "\033[8m";
|
||||
|
||||
// Foreground colors
|
||||
const std::string grey = "\033[30m";
|
||||
const std::string red = "\033[31m";
|
||||
const std::string green = "\033[32m";
|
||||
const std::string yellow = "\033[33m";
|
||||
const std::string blue = "\033[34m";
|
||||
const std::string magenta = "\033[35m";
|
||||
const std::string cyan = "\033[36m";
|
||||
const std::string white = "\033[37m";
|
||||
|
||||
/// Background colors
|
||||
const std::string on_grey = "\033[40m";
|
||||
const std::string on_red = "\033[41m";
|
||||
const std::string on_green = "\033[42m";
|
||||
const std::string on_yellow = "\033[43m";
|
||||
const std::string on_blue = "\033[44m";
|
||||
const std::string on_magenta = "\033[45m";
|
||||
const std::string on_cyan = "\033[46m";
|
||||
const std::string on_white = "\033[47m";
|
||||
|
||||
|
||||
protected:
|
||||
sink_ptr sink_;
|
||||
std::map<level::level_enum, std::string> colors_;
|
||||
};
|
||||
|
||||
inline ansicolor_sink::ansicolor_sink(sink_ptr wrapped_sink) : sink_(wrapped_sink)
|
||||
{
|
||||
colors_[level::trace] = cyan;
|
||||
colors_[level::debug] = cyan;
|
||||
colors_[level::info] = white;
|
||||
colors_[level::notice] = bold + white;
|
||||
colors_[level::warn] = bold + yellow;
|
||||
colors_[level::err] = red;
|
||||
colors_[level::critical] = bold + red;
|
||||
colors_[level::alert] = bold + white + on_red;
|
||||
colors_[level::emerg] = bold + yellow + on_red;
|
||||
colors_[level::off] = reset;
|
||||
}
|
||||
|
||||
inline void ansicolor_sink::log(const details::log_msg& msg)
|
||||
{
|
||||
// Wrap the originally formatted message in color codes
|
||||
const std::string& prefix = colors_[msg.level];
|
||||
const std::string& s = msg.formatted.str();
|
||||
const std::string& suffix = reset;
|
||||
details::log_msg m;
|
||||
m.formatted << prefix << s << suffix;
|
||||
sink_->log(m);
|
||||
}
|
||||
|
||||
inline void ansicolor_sink::flush()
|
||||
{
|
||||
sink_->flush();
|
||||
}
|
||||
|
||||
inline void ansicolor_sink::set_color(level::level_enum level, const std::string& color)
|
||||
{
|
||||
colors_[level] = color;
|
||||
}
|
||||
|
||||
inline ansicolor_sink::~ansicolor_sink()
|
||||
{
|
||||
flush();
|
||||
}
|
||||
|
||||
} // namespace sinks
|
||||
} // namespace spdlog
|
||||
|
||||
|
@ -1,45 +1,45 @@
|
||||
//
|
||||
// Copyright(c) 2015 Gabi Melman.
|
||||
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||
//
|
||||
|
||||
#pragma once
|
||||
//
|
||||
// base sink templated over a mutex (either dummy or realy)
|
||||
// concrete implementation should only overrid the _sink_it method.
|
||||
// all locking is taken care of here so no locking needed by the implementors..
|
||||
//
|
||||
|
||||
#include <spdlog/sinks/sink.h>
|
||||
#include <spdlog/formatter.h>
|
||||
#include <spdlog/common.h>
|
||||
#include <spdlog/details/log_msg.h>
|
||||
|
||||
#include <mutex>
|
||||
|
||||
namespace spdlog
|
||||
{
|
||||
namespace sinks
|
||||
{
|
||||
template<class Mutex>
|
||||
class base_sink:public sink
|
||||
{
|
||||
public:
|
||||
base_sink():_mutex() {}
|
||||
virtual ~base_sink() = default;
|
||||
|
||||
base_sink(const base_sink&) = delete;
|
||||
base_sink& operator=(const base_sink&) = delete;
|
||||
|
||||
void log(const details::log_msg& msg) override
|
||||
{
|
||||
std::lock_guard<Mutex> lock(_mutex);
|
||||
_sink_it(msg);
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual void _sink_it(const details::log_msg& msg) = 0;
|
||||
Mutex _mutex;
|
||||
};
|
||||
}
|
||||
}
|
||||
//
|
||||
// Copyright(c) 2015 Gabi Melman.
|
||||
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||
//
|
||||
|
||||
#pragma once
|
||||
//
|
||||
// base sink templated over a mutex (either dummy or realy)
|
||||
// concrete implementation should only overrid the _sink_it method.
|
||||
// all locking is taken care of here so no locking needed by the implementors..
|
||||
//
|
||||
|
||||
#include <spdlog/sinks/sink.h>
|
||||
#include <spdlog/formatter.h>
|
||||
#include <spdlog/common.h>
|
||||
#include <spdlog/details/log_msg.h>
|
||||
|
||||
#include <mutex>
|
||||
|
||||
namespace spdlog
|
||||
{
|
||||
namespace sinks
|
||||
{
|
||||
template<class Mutex>
|
||||
class base_sink:public sink
|
||||
{
|
||||
public:
|
||||
base_sink():_mutex() {}
|
||||
virtual ~base_sink() = default;
|
||||
|
||||
base_sink(const base_sink&) = delete;
|
||||
base_sink& operator=(const base_sink&) = delete;
|
||||
|
||||
void log(const details::log_msg& msg) override
|
||||
{
|
||||
std::lock_guard<Mutex> lock(_mutex);
|
||||
_sink_it(msg);
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual void _sink_it(const details::log_msg& msg) = 0;
|
||||
Mutex _mutex;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -1,72 +1,72 @@
|
||||
//
|
||||
// Copyright (c) 2015 David Schury, Gabi Melman
|
||||
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <spdlog/details/log_msg.h>
|
||||
#include <spdlog/details/null_mutex.h>
|
||||
#include <spdlog/sinks/base_sink.h>
|
||||
#include <spdlog/sinks/sink.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <vector>
|
||||
|
||||
namespace spdlog
|
||||
{
|
||||
namespace sinks
|
||||
{
|
||||
template<class Mutex>
|
||||
class dist_sink: public base_sink<Mutex>
|
||||
{
|
||||
public:
|
||||
explicit dist_sink() :_sinks() {}
|
||||
dist_sink(const dist_sink&) = delete;
|
||||
dist_sink& operator=(const dist_sink&) = delete;
|
||||
virtual ~dist_sink() = default;
|
||||
|
||||
protected:
|
||||
void _sink_it(const details::log_msg& msg) override
|
||||
{
|
||||
for (auto iter = _sinks.begin(); iter != _sinks.end(); iter++)
|
||||
(*iter)->log(msg);
|
||||
}
|
||||
|
||||
std::vector<std::shared_ptr<sink>> _sinks;
|
||||
|
||||
public:
|
||||
void flush() override
|
||||
{
|
||||
std::lock_guard<Mutex> lock(base_sink<Mutex>::_mutex);
|
||||
for (auto iter = _sinks.begin(); iter != _sinks.end(); iter++)
|
||||
(*iter)->flush();
|
||||
}
|
||||
|
||||
void add_sink(std::shared_ptr<sink> sink)
|
||||
{
|
||||
std::lock_guard<Mutex> lock(base_sink<Mutex>::_mutex);
|
||||
if (sink &&
|
||||
_sinks.end() == std::find(_sinks.begin(), _sinks.end(), sink))
|
||||
{
|
||||
_sinks.push_back(sink);
|
||||
}
|
||||
}
|
||||
|
||||
void remove_sink(std::shared_ptr<sink> sink)
|
||||
{
|
||||
std::lock_guard<Mutex> lock(base_sink<Mutex>::_mutex);
|
||||
auto pos = std::find(_sinks.begin(), _sinks.end(), sink);
|
||||
if (pos != _sinks.end())
|
||||
{
|
||||
_sinks.erase(pos);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
typedef dist_sink<std::mutex> dist_sink_mt;
|
||||
typedef dist_sink<details::null_mutex> dist_sink_st;
|
||||
}
|
||||
}
|
||||
//
|
||||
// Copyright (c) 2015 David Schury, Gabi Melman
|
||||
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <spdlog/details/log_msg.h>
|
||||
#include <spdlog/details/null_mutex.h>
|
||||
#include <spdlog/sinks/base_sink.h>
|
||||
#include <spdlog/sinks/sink.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <vector>
|
||||
|
||||
namespace spdlog
|
||||
{
|
||||
namespace sinks
|
||||
{
|
||||
template<class Mutex>
|
||||
class dist_sink: public base_sink<Mutex>
|
||||
{
|
||||
public:
|
||||
explicit dist_sink() :_sinks() {}
|
||||
dist_sink(const dist_sink&) = delete;
|
||||
dist_sink& operator=(const dist_sink&) = delete;
|
||||
virtual ~dist_sink() = default;
|
||||
|
||||
protected:
|
||||
void _sink_it(const details::log_msg& msg) override
|
||||
{
|
||||
for (auto iter = _sinks.begin(); iter != _sinks.end(); iter++)
|
||||
(*iter)->log(msg);
|
||||
}
|
||||
|
||||
std::vector<std::shared_ptr<sink>> _sinks;
|
||||
|
||||
public:
|
||||
void flush() override
|
||||
{
|
||||
std::lock_guard<Mutex> lock(base_sink<Mutex>::_mutex);
|
||||
for (auto iter = _sinks.begin(); iter != _sinks.end(); iter++)
|
||||
(*iter)->flush();
|
||||
}
|
||||
|
||||
void add_sink(std::shared_ptr<sink> sink)
|
||||
{
|
||||
std::lock_guard<Mutex> lock(base_sink<Mutex>::_mutex);
|
||||
if (sink &&
|
||||
_sinks.end() == std::find(_sinks.begin(), _sinks.end(), sink))
|
||||
{
|
||||
_sinks.push_back(sink);
|
||||
}
|
||||
}
|
||||
|
||||
void remove_sink(std::shared_ptr<sink> sink)
|
||||
{
|
||||
std::lock_guard<Mutex> lock(base_sink<Mutex>::_mutex);
|
||||
auto pos = std::find(_sinks.begin(), _sinks.end(), sink);
|
||||
if (pos != _sinks.end())
|
||||
{
|
||||
_sinks.erase(pos);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
typedef dist_sink<std::mutex> dist_sink_mt;
|
||||
typedef dist_sink<details::null_mutex> dist_sink_st;
|
||||
}
|
||||
}
|
||||
|
@ -1,220 +1,220 @@
|
||||
//
|
||||
// Copyright(c) 2015 Gabi Melman.
|
||||
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <spdlog/sinks/base_sink.h>
|
||||
#include <spdlog/details/null_mutex.h>
|
||||
#include <spdlog/details/file_helper.h>
|
||||
#include <spdlog/details/format.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <chrono>
|
||||
#include <cstdio>
|
||||
#include <ctime>
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
|
||||
namespace spdlog
|
||||
{
|
||||
namespace sinks
|
||||
{
|
||||
/*
|
||||
* Trivial file sink with single file as target
|
||||
*/
|
||||
template<class Mutex>
|
||||
class simple_file_sink : public base_sink < Mutex >
|
||||
{
|
||||
public:
|
||||
explicit simple_file_sink(const filename_t &filename,
|
||||
bool force_flush = false) :
|
||||
_file_helper(force_flush)
|
||||
{
|
||||
_file_helper.open(filename);
|
||||
}
|
||||
void flush() override
|
||||
{
|
||||
_file_helper.flush();
|
||||
}
|
||||
|
||||
protected:
|
||||
void _sink_it(const details::log_msg& msg) override
|
||||
{
|
||||
_file_helper.write(msg);
|
||||
}
|
||||
private:
|
||||
details::file_helper _file_helper;
|
||||
};
|
||||
|
||||
typedef simple_file_sink<std::mutex> simple_file_sink_mt;
|
||||
typedef simple_file_sink<details::null_mutex> simple_file_sink_st;
|
||||
|
||||
/*
|
||||
* Rotating file sink based on size
|
||||
*/
|
||||
template<class Mutex>
|
||||
class rotating_file_sink : public base_sink < Mutex >
|
||||
{
|
||||
public:
|
||||
rotating_file_sink(const filename_t &base_filename, const filename_t &extension,
|
||||
std::size_t max_size, std::size_t max_files,
|
||||
bool force_flush = false) :
|
||||
_base_filename(base_filename),
|
||||
_extension(extension),
|
||||
_max_size(max_size),
|
||||
_max_files(max_files),
|
||||
_current_size(0),
|
||||
_file_helper(force_flush)
|
||||
{
|
||||
_file_helper.open(calc_filename(_base_filename, 0, _extension));
|
||||
_current_size = _file_helper.size(); //expensive. called only once
|
||||
}
|
||||
|
||||
void flush() override
|
||||
{
|
||||
_file_helper.flush();
|
||||
}
|
||||
|
||||
protected:
|
||||
void _sink_it(const details::log_msg& msg) override
|
||||
{
|
||||
_current_size += msg.formatted.size();
|
||||
if (_current_size > _max_size)
|
||||
{
|
||||
_rotate();
|
||||
_current_size = msg.formatted.size();
|
||||
}
|
||||
_file_helper.write(msg);
|
||||
}
|
||||
|
||||
private:
|
||||
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;
|
||||
if (index)
|
||||
w.write(SPDLOG_FILENAME_T("{}.{}.{}"), filename, index, extension);
|
||||
else
|
||||
w.write(SPDLOG_FILENAME_T("{}.{}"), filename, extension);
|
||||
return w.str();
|
||||
}
|
||||
|
||||
// Rotate files:
|
||||
// log.txt -> log.1.txt
|
||||
// log.1.txt -> log2.txt
|
||||
// log.2.txt -> log3.txt
|
||||
// log.3.txt -> delete
|
||||
|
||||
void _rotate()
|
||||
{
|
||||
_file_helper.close();
|
||||
for (auto i = _max_files; i > 0; --i)
|
||||
{
|
||||
filename_t src = calc_filename(_base_filename, i - 1, _extension);
|
||||
filename_t target = calc_filename(_base_filename, i, _extension);
|
||||
|
||||
if (details::file_helper::file_exists(target))
|
||||
{
|
||||
if (details::os::remove(target) != 0)
|
||||
{
|
||||
throw spdlog_ex("rotating_file_sink: failed removing " + filename_to_str(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));
|
||||
}
|
||||
}
|
||||
_file_helper.reopen(true);
|
||||
}
|
||||
filename_t _base_filename;
|
||||
filename_t _extension;
|
||||
std::size_t _max_size;
|
||||
std::size_t _max_files;
|
||||
std::size_t _current_size;
|
||||
details::file_helper _file_helper;
|
||||
};
|
||||
|
||||
typedef rotating_file_sink<std::mutex> rotating_file_sink_mt;
|
||||
typedef rotating_file_sink<details::null_mutex>rotating_file_sink_st;
|
||||
|
||||
/*
|
||||
* Rotating file sink based on date. rotates at midnight
|
||||
*/
|
||||
template<class Mutex>
|
||||
class daily_file_sink :public base_sink < Mutex >
|
||||
{
|
||||
public:
|
||||
//create daily file sink which rotates on given time
|
||||
daily_file_sink(
|
||||
const filename_t& base_filename,
|
||||
const filename_t& extension,
|
||||
int rotation_hour,
|
||||
int rotation_minute,
|
||||
bool force_flush = false) : _base_filename(base_filename),
|
||||
_extension(extension),
|
||||
_rotation_h(rotation_hour),
|
||||
_rotation_m(rotation_minute),
|
||||
_file_helper(force_flush)
|
||||
{
|
||||
if (rotation_hour < 0 || rotation_hour > 23 || rotation_minute < 0 || rotation_minute > 59)
|
||||
throw spdlog_ex("daily_file_sink: Invalid rotation time in ctor");
|
||||
_rotation_tp = _next_rotation_tp();
|
||||
_file_helper.open(calc_filename(_base_filename, _extension));
|
||||
}
|
||||
|
||||
void flush() override
|
||||
{
|
||||
_file_helper.flush();
|
||||
}
|
||||
|
||||
protected:
|
||||
void _sink_it(const details::log_msg& msg) override
|
||||
{
|
||||
if (std::chrono::system_clock::now() >= _rotation_tp)
|
||||
{
|
||||
_file_helper.open(calc_filename(_base_filename, _extension));
|
||||
_rotation_tp = _next_rotation_tp();
|
||||
}
|
||||
_file_helper.write(msg);
|
||||
}
|
||||
|
||||
private:
|
||||
std::chrono::system_clock::time_point _next_rotation_tp()
|
||||
{
|
||||
using namespace std::chrono;
|
||||
auto now = system_clock::now();
|
||||
time_t tnow = std::chrono::system_clock::to_time_t(now);
|
||||
tm date = spdlog::details::os::localtime(tnow);
|
||||
date.tm_hour = _rotation_h;
|
||||
date.tm_min = _rotation_m;
|
||||
date.tm_sec = 0;
|
||||
auto rotation_time = std::chrono::system_clock::from_time_t(std::mktime(&date));
|
||||
if (rotation_time > now)
|
||||
return rotation_time;
|
||||
else
|
||||
return system_clock::time_point(rotation_time + hours(24));
|
||||
}
|
||||
|
||||
//Create filename for the form basename.YYYY-MM-DD.extension
|
||||
static filename_t calc_filename(const filename_t& basename, const filename_t& extension)
|
||||
{
|
||||
std::tm tm = spdlog::details::os::localtime();
|
||||
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);
|
||||
return w.str();
|
||||
}
|
||||
|
||||
filename_t _base_filename;
|
||||
filename_t _extension;
|
||||
int _rotation_h;
|
||||
int _rotation_m;
|
||||
std::chrono::system_clock::time_point _rotation_tp;
|
||||
details::file_helper _file_helper;
|
||||
};
|
||||
|
||||
typedef daily_file_sink<std::mutex> daily_file_sink_mt;
|
||||
typedef daily_file_sink<details::null_mutex> daily_file_sink_st;
|
||||
}
|
||||
}
|
||||
//
|
||||
// Copyright(c) 2015 Gabi Melman.
|
||||
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <spdlog/sinks/base_sink.h>
|
||||
#include <spdlog/details/null_mutex.h>
|
||||
#include <spdlog/details/file_helper.h>
|
||||
#include <spdlog/details/format.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <chrono>
|
||||
#include <cstdio>
|
||||
#include <ctime>
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
|
||||
namespace spdlog
|
||||
{
|
||||
namespace sinks
|
||||
{
|
||||
/*
|
||||
* Trivial file sink with single file as target
|
||||
*/
|
||||
template<class Mutex>
|
||||
class simple_file_sink : public base_sink < Mutex >
|
||||
{
|
||||
public:
|
||||
explicit simple_file_sink(const filename_t &filename,
|
||||
bool force_flush = false) :
|
||||
_file_helper(force_flush)
|
||||
{
|
||||
_file_helper.open(filename);
|
||||
}
|
||||
void flush() override
|
||||
{
|
||||
_file_helper.flush();
|
||||
}
|
||||
|
||||
protected:
|
||||
void _sink_it(const details::log_msg& msg) override
|
||||
{
|
||||
_file_helper.write(msg);
|
||||
}
|
||||
private:
|
||||
details::file_helper _file_helper;
|
||||
};
|
||||
|
||||
typedef simple_file_sink<std::mutex> simple_file_sink_mt;
|
||||
typedef simple_file_sink<details::null_mutex> simple_file_sink_st;
|
||||
|
||||
/*
|
||||
* Rotating file sink based on size
|
||||
*/
|
||||
template<class Mutex>
|
||||
class rotating_file_sink : public base_sink < Mutex >
|
||||
{
|
||||
public:
|
||||
rotating_file_sink(const filename_t &base_filename, const filename_t &extension,
|
||||
std::size_t max_size, std::size_t max_files,
|
||||
bool force_flush = false) :
|
||||
_base_filename(base_filename),
|
||||
_extension(extension),
|
||||
_max_size(max_size),
|
||||
_max_files(max_files),
|
||||
_current_size(0),
|
||||
_file_helper(force_flush)
|
||||
{
|
||||
_file_helper.open(calc_filename(_base_filename, 0, _extension));
|
||||
_current_size = _file_helper.size(); //expensive. called only once
|
||||
}
|
||||
|
||||
void flush() override
|
||||
{
|
||||
_file_helper.flush();
|
||||
}
|
||||
|
||||
protected:
|
||||
void _sink_it(const details::log_msg& msg) override
|
||||
{
|
||||
_current_size += msg.formatted.size();
|
||||
if (_current_size > _max_size)
|
||||
{
|
||||
_rotate();
|
||||
_current_size = msg.formatted.size();
|
||||
}
|
||||
_file_helper.write(msg);
|
||||
}
|
||||
|
||||
private:
|
||||
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;
|
||||
if (index)
|
||||
w.write(SPDLOG_FILENAME_T("{}.{}.{}"), filename, index, extension);
|
||||
else
|
||||
w.write(SPDLOG_FILENAME_T("{}.{}"), filename, extension);
|
||||
return w.str();
|
||||
}
|
||||
|
||||
// Rotate files:
|
||||
// log.txt -> log.1.txt
|
||||
// log.1.txt -> log2.txt
|
||||
// log.2.txt -> log3.txt
|
||||
// log.3.txt -> delete
|
||||
|
||||
void _rotate()
|
||||
{
|
||||
_file_helper.close();
|
||||
for (auto i = _max_files; i > 0; --i)
|
||||
{
|
||||
filename_t src = calc_filename(_base_filename, i - 1, _extension);
|
||||
filename_t target = calc_filename(_base_filename, i, _extension);
|
||||
|
||||
if (details::file_helper::file_exists(target))
|
||||
{
|
||||
if (details::os::remove(target) != 0)
|
||||
{
|
||||
throw spdlog_ex("rotating_file_sink: failed removing " + filename_to_str(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));
|
||||
}
|
||||
}
|
||||
_file_helper.reopen(true);
|
||||
}
|
||||
filename_t _base_filename;
|
||||
filename_t _extension;
|
||||
std::size_t _max_size;
|
||||
std::size_t _max_files;
|
||||
std::size_t _current_size;
|
||||
details::file_helper _file_helper;
|
||||
};
|
||||
|
||||
typedef rotating_file_sink<std::mutex> rotating_file_sink_mt;
|
||||
typedef rotating_file_sink<details::null_mutex>rotating_file_sink_st;
|
||||
|
||||
/*
|
||||
* Rotating file sink based on date. rotates at midnight
|
||||
*/
|
||||
template<class Mutex>
|
||||
class daily_file_sink :public base_sink < Mutex >
|
||||
{
|
||||
public:
|
||||
//create daily file sink which rotates on given time
|
||||
daily_file_sink(
|
||||
const filename_t& base_filename,
|
||||
const filename_t& extension,
|
||||
int rotation_hour,
|
||||
int rotation_minute,
|
||||
bool force_flush = false) : _base_filename(base_filename),
|
||||
_extension(extension),
|
||||
_rotation_h(rotation_hour),
|
||||
_rotation_m(rotation_minute),
|
||||
_file_helper(force_flush)
|
||||
{
|
||||
if (rotation_hour < 0 || rotation_hour > 23 || rotation_minute < 0 || rotation_minute > 59)
|
||||
throw spdlog_ex("daily_file_sink: Invalid rotation time in ctor");
|
||||
_rotation_tp = _next_rotation_tp();
|
||||
_file_helper.open(calc_filename(_base_filename, _extension));
|
||||
}
|
||||
|
||||
void flush() override
|
||||
{
|
||||
_file_helper.flush();
|
||||
}
|
||||
|
||||
protected:
|
||||
void _sink_it(const details::log_msg& msg) override
|
||||
{
|
||||
if (std::chrono::system_clock::now() >= _rotation_tp)
|
||||
{
|
||||
_file_helper.open(calc_filename(_base_filename, _extension));
|
||||
_rotation_tp = _next_rotation_tp();
|
||||
}
|
||||
_file_helper.write(msg);
|
||||
}
|
||||
|
||||
private:
|
||||
std::chrono::system_clock::time_point _next_rotation_tp()
|
||||
{
|
||||
using namespace std::chrono;
|
||||
auto now = system_clock::now();
|
||||
time_t tnow = std::chrono::system_clock::to_time_t(now);
|
||||
tm date = spdlog::details::os::localtime(tnow);
|
||||
date.tm_hour = _rotation_h;
|
||||
date.tm_min = _rotation_m;
|
||||
date.tm_sec = 0;
|
||||
auto rotation_time = std::chrono::system_clock::from_time_t(std::mktime(&date));
|
||||
if (rotation_time > now)
|
||||
return rotation_time;
|
||||
else
|
||||
return system_clock::time_point(rotation_time + hours(24));
|
||||
}
|
||||
|
||||
//Create filename for the form basename.YYYY-MM-DD.extension
|
||||
static filename_t calc_filename(const filename_t& basename, const filename_t& extension)
|
||||
{
|
||||
std::tm tm = spdlog::details::os::localtime();
|
||||
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);
|
||||
return w.str();
|
||||
}
|
||||
|
||||
filename_t _base_filename;
|
||||
filename_t _extension;
|
||||
int _rotation_h;
|
||||
int _rotation_m;
|
||||
std::chrono::system_clock::time_point _rotation_tp;
|
||||
details::file_helper _file_helper;
|
||||
};
|
||||
|
||||
typedef daily_file_sink<std::mutex> daily_file_sink_mt;
|
||||
typedef daily_file_sink<details::null_mutex> daily_file_sink_st;
|
||||
}
|
||||
}
|
||||
|
@ -1,50 +1,50 @@
|
||||
//
|
||||
// Copyright(c) 2016 Alexander Dalshov.
|
||||
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
|
||||
#include <spdlog/sinks/base_sink.h>
|
||||
#include <spdlog/details/null_mutex.h>
|
||||
|
||||
#include <WinBase.h>
|
||||
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
|
||||
namespace spdlog
|
||||
{
|
||||
namespace sinks
|
||||
{
|
||||
/*
|
||||
* MSVC sink (logging using OutputDebugStringA)
|
||||
*/
|
||||
template<class Mutex>
|
||||
class msvc_sink : public base_sink < Mutex >
|
||||
{
|
||||
public:
|
||||
explicit msvc_sink()
|
||||
{
|
||||
}
|
||||
|
||||
void flush() override
|
||||
{
|
||||
}
|
||||
|
||||
protected:
|
||||
void _sink_it(const details::log_msg& msg) override
|
||||
{
|
||||
OutputDebugStringA(msg.formatted.c_str());
|
||||
}
|
||||
};
|
||||
|
||||
typedef msvc_sink<std::mutex> msvc_sink_mt;
|
||||
typedef msvc_sink<details::null_mutex> msvc_sink_st;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
//
|
||||
// Copyright(c) 2016 Alexander Dalshov.
|
||||
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
|
||||
#include <spdlog/sinks/base_sink.h>
|
||||
#include <spdlog/details/null_mutex.h>
|
||||
|
||||
#include <WinBase.h>
|
||||
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
|
||||
namespace spdlog
|
||||
{
|
||||
namespace sinks
|
||||
{
|
||||
/*
|
||||
* MSVC sink (logging using OutputDebugStringA)
|
||||
*/
|
||||
template<class Mutex>
|
||||
class msvc_sink : public base_sink < Mutex >
|
||||
{
|
||||
public:
|
||||
explicit msvc_sink()
|
||||
{
|
||||
}
|
||||
|
||||
void flush() override
|
||||
{
|
||||
}
|
||||
|
||||
protected:
|
||||
void _sink_it(const details::log_msg& msg) override
|
||||
{
|
||||
OutputDebugStringA(msg.formatted.c_str());
|
||||
}
|
||||
};
|
||||
|
||||
typedef msvc_sink<std::mutex> msvc_sink_mt;
|
||||
typedef msvc_sink<details::null_mutex> msvc_sink_st;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -1,34 +1,34 @@
|
||||
//
|
||||
// Copyright(c) 2015 Gabi Melman.
|
||||
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <spdlog/sinks/base_sink.h>
|
||||
#include <spdlog/details/null_mutex.h>
|
||||
|
||||
#include <mutex>
|
||||
|
||||
namespace spdlog
|
||||
{
|
||||
namespace sinks
|
||||
{
|
||||
|
||||
template <class Mutex>
|
||||
class null_sink : public base_sink < Mutex >
|
||||
{
|
||||
protected:
|
||||
void _sink_it(const details::log_msg&) override
|
||||
{}
|
||||
|
||||
void flush() override
|
||||
{}
|
||||
|
||||
};
|
||||
typedef null_sink<details::null_mutex> null_sink_st;
|
||||
typedef null_sink<std::mutex> null_sink_mt;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Copyright(c) 2015 Gabi Melman.
|
||||
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <spdlog/sinks/base_sink.h>
|
||||
#include <spdlog/details/null_mutex.h>
|
||||
|
||||
#include <mutex>
|
||||
|
||||
namespace spdlog
|
||||
{
|
||||
namespace sinks
|
||||
{
|
||||
|
||||
template <class Mutex>
|
||||
class null_sink : public base_sink < Mutex >
|
||||
{
|
||||
protected:
|
||||
void _sink_it(const details::log_msg&) override
|
||||
{}
|
||||
|
||||
void flush() override
|
||||
{}
|
||||
|
||||
};
|
||||
typedef null_sink<details::null_mutex> null_sink_st;
|
||||
typedef null_sink<std::mutex> null_sink_mt;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,47 +1,47 @@
|
||||
//
|
||||
// Copyright(c) 2015 Gabi Melman.
|
||||
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <spdlog/details/null_mutex.h>
|
||||
#include <spdlog/sinks/base_sink.h>
|
||||
|
||||
#include <ostream>
|
||||
#include <mutex>
|
||||
|
||||
namespace spdlog
|
||||
{
|
||||
namespace sinks
|
||||
{
|
||||
template<class Mutex>
|
||||
class ostream_sink: public base_sink<Mutex>
|
||||
{
|
||||
public:
|
||||
explicit ostream_sink(std::ostream& os, bool force_flush=false) :_ostream(os), _force_flush(force_flush) {}
|
||||
ostream_sink(const ostream_sink&) = delete;
|
||||
ostream_sink& operator=(const ostream_sink&) = delete;
|
||||
virtual ~ostream_sink() = default;
|
||||
|
||||
protected:
|
||||
void _sink_it(const details::log_msg& msg) override
|
||||
{
|
||||
_ostream.write(msg.formatted.data(), msg.formatted.size());
|
||||
if (_force_flush)
|
||||
_ostream.flush();
|
||||
}
|
||||
|
||||
void flush() override
|
||||
{
|
||||
_ostream.flush();
|
||||
}
|
||||
|
||||
std::ostream& _ostream;
|
||||
bool _force_flush;
|
||||
};
|
||||
|
||||
typedef ostream_sink<std::mutex> ostream_sink_mt;
|
||||
typedef ostream_sink<details::null_mutex> ostream_sink_st;
|
||||
}
|
||||
}
|
||||
//
|
||||
// Copyright(c) 2015 Gabi Melman.
|
||||
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <spdlog/details/null_mutex.h>
|
||||
#include <spdlog/sinks/base_sink.h>
|
||||
|
||||
#include <ostream>
|
||||
#include <mutex>
|
||||
|
||||
namespace spdlog
|
||||
{
|
||||
namespace sinks
|
||||
{
|
||||
template<class Mutex>
|
||||
class ostream_sink: public base_sink<Mutex>
|
||||
{
|
||||
public:
|
||||
explicit ostream_sink(std::ostream& os, bool force_flush=false) :_ostream(os), _force_flush(force_flush) {}
|
||||
ostream_sink(const ostream_sink&) = delete;
|
||||
ostream_sink& operator=(const ostream_sink&) = delete;
|
||||
virtual ~ostream_sink() = default;
|
||||
|
||||
protected:
|
||||
void _sink_it(const details::log_msg& msg) override
|
||||
{
|
||||
_ostream.write(msg.formatted.data(), msg.formatted.size());
|
||||
if (_force_flush)
|
||||
_ostream.flush();
|
||||
}
|
||||
|
||||
void flush() override
|
||||
{
|
||||
_ostream.flush();
|
||||
}
|
||||
|
||||
std::ostream& _ostream;
|
||||
bool _force_flush;
|
||||
};
|
||||
|
||||
typedef ostream_sink<std::mutex> ostream_sink_mt;
|
||||
typedef ostream_sink<details::null_mutex> ostream_sink_st;
|
||||
}
|
||||
}
|
||||
|
@ -1,24 +1,24 @@
|
||||
//
|
||||
// Copyright(c) 2015 Gabi Melman.
|
||||
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||
//
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <spdlog/details/log_msg.h>
|
||||
|
||||
namespace spdlog
|
||||
{
|
||||
namespace sinks
|
||||
{
|
||||
class sink
|
||||
{
|
||||
public:
|
||||
virtual ~sink() {}
|
||||
virtual void log(const details::log_msg& msg) = 0;
|
||||
virtual void flush() = 0;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Copyright(c) 2015 Gabi Melman.
|
||||
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||
//
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <spdlog/details/log_msg.h>
|
||||
|
||||
namespace spdlog
|
||||
{
|
||||
namespace sinks
|
||||
{
|
||||
class sink
|
||||
{
|
||||
public:
|
||||
virtual ~sink() {}
|
||||
virtual void log(const details::log_msg& msg) = 0;
|
||||
virtual void flush() = 0;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,74 +1,74 @@
|
||||
//
|
||||
// Copyright(c) 2015 Gabi Melman.
|
||||
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <spdlog/details/null_mutex.h>
|
||||
|
||||
#include <cstdio>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
|
||||
namespace spdlog
|
||||
{
|
||||
namespace sinks
|
||||
{
|
||||
|
||||
template <class Mutex>
|
||||
class stdout_sink : public base_sink<Mutex>
|
||||
{
|
||||
using MyType = stdout_sink<Mutex>;
|
||||
public:
|
||||
stdout_sink() {}
|
||||
static std::shared_ptr<MyType> instance()
|
||||
{
|
||||
static std::shared_ptr<MyType> instance = std::make_shared<MyType>();
|
||||
return instance;
|
||||
}
|
||||
|
||||
void _sink_it(const details::log_msg& msg) override
|
||||
{
|
||||
fwrite(msg.formatted.data(), sizeof(char), msg.formatted.size(), stdout);
|
||||
flush();
|
||||
}
|
||||
|
||||
void flush() override
|
||||
{
|
||||
fflush(stdout);
|
||||
}
|
||||
};
|
||||
|
||||
typedef stdout_sink<details::null_mutex> stdout_sink_st;
|
||||
typedef stdout_sink<std::mutex> stdout_sink_mt;
|
||||
|
||||
|
||||
template <class Mutex>
|
||||
class stderr_sink : public base_sink<Mutex>
|
||||
{
|
||||
using MyType = stderr_sink<Mutex>;
|
||||
public:
|
||||
stderr_sink() {}
|
||||
static std::shared_ptr<MyType> instance()
|
||||
{
|
||||
static std::shared_ptr<MyType> instance = std::make_shared<MyType>();
|
||||
return instance;
|
||||
}
|
||||
|
||||
void _sink_it(const details::log_msg& msg) override
|
||||
{
|
||||
fwrite(msg.formatted.data(), sizeof(char), msg.formatted.size(), stderr);
|
||||
flush();
|
||||
}
|
||||
|
||||
void flush() override
|
||||
{
|
||||
fflush(stderr);
|
||||
}
|
||||
};
|
||||
|
||||
typedef stderr_sink<std::mutex> stderr_sink_mt;
|
||||
typedef stderr_sink<details::null_mutex> stderr_sink_st;
|
||||
}
|
||||
}
|
||||
//
|
||||
// Copyright(c) 2015 Gabi Melman.
|
||||
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <spdlog/details/null_mutex.h>
|
||||
|
||||
#include <cstdio>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
|
||||
namespace spdlog
|
||||
{
|
||||
namespace sinks
|
||||
{
|
||||
|
||||
template <class Mutex>
|
||||
class stdout_sink : public base_sink<Mutex>
|
||||
{
|
||||
using MyType = stdout_sink<Mutex>;
|
||||
public:
|
||||
stdout_sink() {}
|
||||
static std::shared_ptr<MyType> instance()
|
||||
{
|
||||
static std::shared_ptr<MyType> instance = std::make_shared<MyType>();
|
||||
return instance;
|
||||
}
|
||||
|
||||
void _sink_it(const details::log_msg& msg) override
|
||||
{
|
||||
fwrite(msg.formatted.data(), sizeof(char), msg.formatted.size(), stdout);
|
||||
flush();
|
||||
}
|
||||
|
||||
void flush() override
|
||||
{
|
||||
fflush(stdout);
|
||||
}
|
||||
};
|
||||
|
||||
typedef stdout_sink<details::null_mutex> stdout_sink_st;
|
||||
typedef stdout_sink<std::mutex> stdout_sink_mt;
|
||||
|
||||
|
||||
template <class Mutex>
|
||||
class stderr_sink : public base_sink<Mutex>
|
||||
{
|
||||
using MyType = stderr_sink<Mutex>;
|
||||
public:
|
||||
stderr_sink() {}
|
||||
static std::shared_ptr<MyType> instance()
|
||||
{
|
||||
static std::shared_ptr<MyType> instance = std::make_shared<MyType>();
|
||||
return instance;
|
||||
}
|
||||
|
||||
void _sink_it(const details::log_msg& msg) override
|
||||
{
|
||||
fwrite(msg.formatted.data(), sizeof(char), msg.formatted.size(), stderr);
|
||||
flush();
|
||||
}
|
||||
|
||||
void flush() override
|
||||
{
|
||||
fflush(stderr);
|
||||
}
|
||||
};
|
||||
|
||||
typedef stderr_sink<std::mutex> stderr_sink_mt;
|
||||
typedef stderr_sink<details::null_mutex> stderr_sink_st;
|
||||
}
|
||||
}
|
||||
|
@ -1,83 +1,83 @@
|
||||
//
|
||||
// Copyright(c) 2015 Gabi Melman.
|
||||
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#if defined(__linux__) || defined(__APPLE__)
|
||||
|
||||
#include <spdlog/sinks/sink.h>
|
||||
#include <spdlog/common.h>
|
||||
#include <spdlog/details/log_msg.h>
|
||||
|
||||
#include <array>
|
||||
#include <string>
|
||||
#include <syslog.h>
|
||||
|
||||
|
||||
namespace spdlog
|
||||
{
|
||||
namespace sinks
|
||||
{
|
||||
/**
|
||||
* Sink that write to syslog using the `syscall()` library call.
|
||||
*
|
||||
* Locking is not needed, as `syslog()` itself is thread-safe.
|
||||
*/
|
||||
class syslog_sink : public sink
|
||||
{
|
||||
public:
|
||||
//
|
||||
syslog_sink(const std::string& ident = "", int syslog_option=0, int syslog_facility=LOG_USER):
|
||||
_ident(ident)
|
||||
{
|
||||
_priorities[static_cast<int>(level::trace)] = LOG_DEBUG;
|
||||
_priorities[static_cast<int>(level::debug)] = LOG_DEBUG;
|
||||
_priorities[static_cast<int>(level::info)] = LOG_INFO;
|
||||
_priorities[static_cast<int>(level::notice)] = LOG_NOTICE;
|
||||
_priorities[static_cast<int>(level::warn)] = LOG_WARNING;
|
||||
_priorities[static_cast<int>(level::err)] = LOG_ERR;
|
||||
_priorities[static_cast<int>(level::critical)] = LOG_CRIT;
|
||||
_priorities[static_cast<int>(level::alert)] = LOG_ALERT;
|
||||
_priorities[static_cast<int>(level::emerg)] = LOG_EMERG;
|
||||
_priorities[static_cast<int>(level::off)] = LOG_INFO;
|
||||
|
||||
//set ident to be program name if empty
|
||||
::openlog(_ident.empty()? nullptr:_ident.c_str(), syslog_option, syslog_facility);
|
||||
}
|
||||
~syslog_sink()
|
||||
{
|
||||
::closelog();
|
||||
}
|
||||
|
||||
syslog_sink(const syslog_sink&) = delete;
|
||||
syslog_sink& operator=(const syslog_sink&) = delete;
|
||||
|
||||
void log(const details::log_msg &msg) override
|
||||
{
|
||||
::syslog(syslog_prio_from_level(msg), "%s", msg.raw.str().c_str());
|
||||
}
|
||||
|
||||
void flush() override
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
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
|
||||
const std::string _ident;
|
||||
|
||||
//
|
||||
// Simply maps spdlog's log level to syslog priority level.
|
||||
//
|
||||
int syslog_prio_from_level(const details::log_msg &msg) const
|
||||
{
|
||||
return _priorities[static_cast<int>(msg.level)];
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
//
|
||||
// Copyright(c) 2015 Gabi Melman.
|
||||
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#if defined(__linux__) || defined(__APPLE__)
|
||||
|
||||
#include <spdlog/sinks/sink.h>
|
||||
#include <spdlog/common.h>
|
||||
#include <spdlog/details/log_msg.h>
|
||||
|
||||
#include <array>
|
||||
#include <string>
|
||||
#include <syslog.h>
|
||||
|
||||
|
||||
namespace spdlog
|
||||
{
|
||||
namespace sinks
|
||||
{
|
||||
/**
|
||||
* Sink that write to syslog using the `syscall()` library call.
|
||||
*
|
||||
* Locking is not needed, as `syslog()` itself is thread-safe.
|
||||
*/
|
||||
class syslog_sink : public sink
|
||||
{
|
||||
public:
|
||||
//
|
||||
syslog_sink(const std::string& ident = "", int syslog_option=0, int syslog_facility=LOG_USER):
|
||||
_ident(ident)
|
||||
{
|
||||
_priorities[static_cast<int>(level::trace)] = LOG_DEBUG;
|
||||
_priorities[static_cast<int>(level::debug)] = LOG_DEBUG;
|
||||
_priorities[static_cast<int>(level::info)] = LOG_INFO;
|
||||
_priorities[static_cast<int>(level::notice)] = LOG_NOTICE;
|
||||
_priorities[static_cast<int>(level::warn)] = LOG_WARNING;
|
||||
_priorities[static_cast<int>(level::err)] = LOG_ERR;
|
||||
_priorities[static_cast<int>(level::critical)] = LOG_CRIT;
|
||||
_priorities[static_cast<int>(level::alert)] = LOG_ALERT;
|
||||
_priorities[static_cast<int>(level::emerg)] = LOG_EMERG;
|
||||
_priorities[static_cast<int>(level::off)] = LOG_INFO;
|
||||
|
||||
//set ident to be program name if empty
|
||||
::openlog(_ident.empty()? nullptr:_ident.c_str(), syslog_option, syslog_facility);
|
||||
}
|
||||
~syslog_sink()
|
||||
{
|
||||
::closelog();
|
||||
}
|
||||
|
||||
syslog_sink(const syslog_sink&) = delete;
|
||||
syslog_sink& operator=(const syslog_sink&) = delete;
|
||||
|
||||
void log(const details::log_msg &msg) override
|
||||
{
|
||||
::syslog(syslog_prio_from_level(msg), "%s", msg.raw.str().c_str());
|
||||
}
|
||||
|
||||
void flush() override
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
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
|
||||
const std::string _ident;
|
||||
|
||||
//
|
||||
// Simply maps spdlog's log level to syslog priority level.
|
||||
//
|
||||
int syslog_prio_from_level(const details::log_msg &msg) const
|
||||
{
|
||||
return _priorities[static_cast<int>(msg.level)];
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -1,139 +1,139 @@
|
||||
//
|
||||
// Copyright(c) 2015 Gabi Melman.
|
||||
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||
//
|
||||
|
||||
// spdlog main header file.
|
||||
// see example.cpp for usage example
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <spdlog/tweakme.h>
|
||||
#include <spdlog/common.h>
|
||||
#include <spdlog/logger.h>
|
||||
|
||||
#include <memory>
|
||||
#include <functional>
|
||||
#include <chrono>
|
||||
#include <string>
|
||||
|
||||
namespace spdlog
|
||||
{
|
||||
// Return an existing logger or nullptr if a logger with such name doesn't exist.
|
||||
// Examples:
|
||||
//
|
||||
// spdlog::get("mylog")->info("Hello");
|
||||
// auto logger = spdlog::get("mylog");
|
||||
// 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);
|
||||
|
||||
//
|
||||
// Set global formatting
|
||||
// example: spdlog::set_pattern("%Y-%m-%d %H:%M:%S.%e %l : %v");
|
||||
//
|
||||
void set_pattern(const std::string& format_string);
|
||||
void set_formatter(formatter_ptr f);
|
||||
|
||||
//
|
||||
// Set global logging level for
|
||||
//
|
||||
void set_level(level::level_enum log_level);
|
||||
|
||||
//
|
||||
// Turn on async mode (off by default) and set the queue size for each async_logger.
|
||||
// effective only for loggers created after this call.
|
||||
// queue_size: size of queue (must be power of 2):
|
||||
// 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::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.
|
||||
//
|
||||
// worker_warmup_cb (optional):
|
||||
// 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());
|
||||
|
||||
// Turn off async mode
|
||||
void set_sync_mode();
|
||||
|
||||
//
|
||||
// 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_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):
|
||||
//
|
||||
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);
|
||||
|
||||
//
|
||||
// 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_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_st(const std::string& logger_name, bool color = false);
|
||||
|
||||
|
||||
//
|
||||
// Create and register a syslog logger
|
||||
//
|
||||
#if defined(__linux__) || defined(__APPLE__)
|
||||
std::shared_ptr<logger> syslog_logger(const std::string& logger_name, const std::string& ident = "", int syslog_option = 0);
|
||||
#endif
|
||||
|
||||
|
||||
// Create and register a logger with multiple sinks
|
||||
std::shared_ptr<logger> create(const std::string& logger_name, sinks_init_list sinks);
|
||||
template<class It>
|
||||
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
|
||||
// Example: spdlog::create<daily_file_sink_st>("mylog", "dailylog_filename", "txt");
|
||||
template <typename Sink, typename... Args>
|
||||
std::shared_ptr<spdlog::logger> create(const std::string& logger_name, Args...);
|
||||
|
||||
|
||||
// Register the given logger with the given name
|
||||
void register_logger(std::shared_ptr<logger> logger);
|
||||
|
||||
// Drop the reference to the given logger
|
||||
void drop(const std::string &name);
|
||||
|
||||
// Drop all references
|
||||
void drop_all();
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Macros to be display source file & line
|
||||
// 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.
|
||||
//
|
||||
// Example:
|
||||
// spdlog::set_level(spdlog::level::debug);
|
||||
// SPDLOG_DEBUG(my_logger, "Some debug message {} {}", 1, 3.2);
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifdef SPDLOG_TRACE_ON
|
||||
#define SPDLOG_TRACE(logger, ...) logger->trace(__VA_ARGS__) << " (" << __FILE__ << " #" << __LINE__ <<")";
|
||||
#else
|
||||
#define SPDLOG_TRACE(logger, ...)
|
||||
#endif
|
||||
|
||||
#ifdef SPDLOG_DEBUG_ON
|
||||
#define SPDLOG_DEBUG(logger, ...) logger->debug(__VA_ARGS__) << " (" << __FILE__ << " #" << __LINE__ <<")";
|
||||
#else
|
||||
#define SPDLOG_DEBUG(logger, ...)
|
||||
#endif
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
#include <spdlog/details/spdlog_impl.h>
|
||||
//
|
||||
// Copyright(c) 2015 Gabi Melman.
|
||||
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||
//
|
||||
|
||||
// spdlog main header file.
|
||||
// see example.cpp for usage example
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <spdlog/tweakme.h>
|
||||
#include <spdlog/common.h>
|
||||
#include <spdlog/logger.h>
|
||||
|
||||
#include <memory>
|
||||
#include <functional>
|
||||
#include <chrono>
|
||||
#include <string>
|
||||
|
||||
namespace spdlog
|
||||
{
|
||||
// Return an existing logger or nullptr if a logger with such name doesn't exist.
|
||||
// Examples:
|
||||
//
|
||||
// spdlog::get("mylog")->info("Hello");
|
||||
// auto logger = spdlog::get("mylog");
|
||||
// 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);
|
||||
|
||||
//
|
||||
// Set global formatting
|
||||
// example: spdlog::set_pattern("%Y-%m-%d %H:%M:%S.%e %l : %v");
|
||||
//
|
||||
void set_pattern(const std::string& format_string);
|
||||
void set_formatter(formatter_ptr f);
|
||||
|
||||
//
|
||||
// Set global logging level for
|
||||
//
|
||||
void set_level(level::level_enum log_level);
|
||||
|
||||
//
|
||||
// Turn on async mode (off by default) and set the queue size for each async_logger.
|
||||
// effective only for loggers created after this call.
|
||||
// queue_size: size of queue (must be power of 2):
|
||||
// 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::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.
|
||||
//
|
||||
// worker_warmup_cb (optional):
|
||||
// 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());
|
||||
|
||||
// Turn off async mode
|
||||
void set_sync_mode();
|
||||
|
||||
//
|
||||
// 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_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):
|
||||
//
|
||||
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);
|
||||
|
||||
//
|
||||
// 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_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_st(const std::string& logger_name, bool color = false);
|
||||
|
||||
|
||||
//
|
||||
// Create and register a syslog logger
|
||||
//
|
||||
#if defined(__linux__) || defined(__APPLE__)
|
||||
std::shared_ptr<logger> syslog_logger(const std::string& logger_name, const std::string& ident = "", int syslog_option = 0);
|
||||
#endif
|
||||
|
||||
|
||||
// Create and register a logger with multiple sinks
|
||||
std::shared_ptr<logger> create(const std::string& logger_name, sinks_init_list sinks);
|
||||
template<class It>
|
||||
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
|
||||
// Example: spdlog::create<daily_file_sink_st>("mylog", "dailylog_filename", "txt");
|
||||
template <typename Sink, typename... Args>
|
||||
std::shared_ptr<spdlog::logger> create(const std::string& logger_name, Args...);
|
||||
|
||||
|
||||
// Register the given logger with the given name
|
||||
void register_logger(std::shared_ptr<logger> logger);
|
||||
|
||||
// Drop the reference to the given logger
|
||||
void drop(const std::string &name);
|
||||
|
||||
// Drop all references
|
||||
void drop_all();
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Macros to be display source file & line
|
||||
// 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.
|
||||
//
|
||||
// Example:
|
||||
// spdlog::set_level(spdlog::level::debug);
|
||||
// SPDLOG_DEBUG(my_logger, "Some debug message {} {}", 1, 3.2);
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifdef SPDLOG_TRACE_ON
|
||||
#define SPDLOG_TRACE(logger, ...) logger->trace(__VA_ARGS__) << " (" << __FILE__ << " #" << __LINE__ <<")";
|
||||
#else
|
||||
#define SPDLOG_TRACE(logger, ...)
|
||||
#endif
|
||||
|
||||
#ifdef SPDLOG_DEBUG_ON
|
||||
#define SPDLOG_DEBUG(logger, ...) logger->debug(__VA_ARGS__) << " (" << __FILE__ << " #" << __LINE__ <<")";
|
||||
#else
|
||||
#define SPDLOG_DEBUG(logger, ...)
|
||||
#endif
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
#include <spdlog/details/spdlog_impl.h>
|
||||
|
@ -1,77 +1,77 @@
|
||||
/*
|
||||
* This content is released under the MIT License as specified in https://raw.githubusercontent.com/gabime/spdlog/master/LICENSE
|
||||
*/
|
||||
#include "includes.h"
|
||||
|
||||
using namespace spdlog::details;
|
||||
|
||||
static const std::string target_filename = "logs/file_helper_test.txt";
|
||||
|
||||
static void write_with_helper(file_helper &helper, size_t howmany)
|
||||
{
|
||||
log_msg msg;
|
||||
msg.formatted << std::string(howmany, '1');
|
||||
helper.write(msg);
|
||||
}
|
||||
|
||||
|
||||
TEST_CASE("file_helper_filename", "[file_helper::filename()]]")
|
||||
{
|
||||
prepare_logdir();
|
||||
|
||||
file_helper helper(false);
|
||||
helper.open(target_filename);
|
||||
REQUIRE(helper.filename() == target_filename);
|
||||
}
|
||||
|
||||
|
||||
|
||||
TEST_CASE("file_helper_size", "[file_helper::size()]]")
|
||||
{
|
||||
prepare_logdir();
|
||||
auto expected_size = 123;
|
||||
{
|
||||
file_helper helper(true);
|
||||
helper.open(target_filename);
|
||||
write_with_helper(helper, expected_size);
|
||||
REQUIRE(helper.size() == expected_size);
|
||||
}
|
||||
REQUIRE(get_filesize(target_filename) == expected_size);
|
||||
}
|
||||
|
||||
|
||||
TEST_CASE("file_helper_exists", "[file_helper::file_exists()]]")
|
||||
{
|
||||
prepare_logdir();
|
||||
REQUIRE(!file_helper::file_exists(target_filename));
|
||||
file_helper helper(false);
|
||||
helper.open(target_filename);
|
||||
REQUIRE(file_helper::file_exists(target_filename));
|
||||
}
|
||||
|
||||
TEST_CASE("file_helper_reopen", "[file_helper::reopen()]]")
|
||||
{
|
||||
prepare_logdir();
|
||||
file_helper helper(true);
|
||||
helper.open(target_filename);
|
||||
write_with_helper(helper, 12);
|
||||
REQUIRE(helper.size() == 12);
|
||||
helper.reopen(true);
|
||||
REQUIRE(helper.size() == 0);
|
||||
}
|
||||
|
||||
TEST_CASE("file_helper_reopen2", "[file_helper::reopen(false)]]")
|
||||
{
|
||||
prepare_logdir();
|
||||
auto expected_size = 14;
|
||||
file_helper helper(true);
|
||||
helper.open(target_filename);
|
||||
write_with_helper(helper, expected_size);
|
||||
REQUIRE(helper.size() == expected_size);
|
||||
helper.reopen(false);
|
||||
REQUIRE(helper.size() == expected_size);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* This content is released under the MIT License as specified in https://raw.githubusercontent.com/gabime/spdlog/master/LICENSE
|
||||
*/
|
||||
#include "includes.h"
|
||||
|
||||
using namespace spdlog::details;
|
||||
|
||||
static const std::string target_filename = "logs/file_helper_test.txt";
|
||||
|
||||
static void write_with_helper(file_helper &helper, size_t howmany)
|
||||
{
|
||||
log_msg msg;
|
||||
msg.formatted << std::string(howmany, '1');
|
||||
helper.write(msg);
|
||||
}
|
||||
|
||||
|
||||
TEST_CASE("file_helper_filename", "[file_helper::filename()]]")
|
||||
{
|
||||
prepare_logdir();
|
||||
|
||||
file_helper helper(false);
|
||||
helper.open(target_filename);
|
||||
REQUIRE(helper.filename() == target_filename);
|
||||
}
|
||||
|
||||
|
||||
|
||||
TEST_CASE("file_helper_size", "[file_helper::size()]]")
|
||||
{
|
||||
prepare_logdir();
|
||||
auto expected_size = 123;
|
||||
{
|
||||
file_helper helper(true);
|
||||
helper.open(target_filename);
|
||||
write_with_helper(helper, expected_size);
|
||||
REQUIRE(helper.size() == expected_size);
|
||||
}
|
||||
REQUIRE(get_filesize(target_filename) == expected_size);
|
||||
}
|
||||
|
||||
|
||||
TEST_CASE("file_helper_exists", "[file_helper::file_exists()]]")
|
||||
{
|
||||
prepare_logdir();
|
||||
REQUIRE(!file_helper::file_exists(target_filename));
|
||||
file_helper helper(false);
|
||||
helper.open(target_filename);
|
||||
REQUIRE(file_helper::file_exists(target_filename));
|
||||
}
|
||||
|
||||
TEST_CASE("file_helper_reopen", "[file_helper::reopen()]]")
|
||||
{
|
||||
prepare_logdir();
|
||||
file_helper helper(true);
|
||||
helper.open(target_filename);
|
||||
write_with_helper(helper, 12);
|
||||
REQUIRE(helper.size() == 12);
|
||||
helper.reopen(true);
|
||||
REQUIRE(helper.size() == 0);
|
||||
}
|
||||
|
||||
TEST_CASE("file_helper_reopen2", "[file_helper::reopen(false)]]")
|
||||
{
|
||||
prepare_logdir();
|
||||
auto expected_size = 14;
|
||||
file_helper helper(true);
|
||||
helper.open(target_filename);
|
||||
write_with_helper(helper, expected_size);
|
||||
REQUIRE(helper.size() == expected_size);
|
||||
helper.reopen(false);
|
||||
REQUIRE(helper.size() == expected_size);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -1,91 +1,91 @@
|
||||
/*
|
||||
* This content is released under the MIT License as specified in https://raw.githubusercontent.com/gabime/spdlog/master/LICENSE
|
||||
*/
|
||||
#include "includes.h"
|
||||
|
||||
|
||||
TEST_CASE("simple_file_logger", "[simple_logger]]")
|
||||
{
|
||||
prepare_logdir();
|
||||
std::string filename = "logs/simple_log.txt";
|
||||
|
||||
auto logger = spdlog::create<spdlog::sinks::simple_file_sink_mt>("logger", filename);
|
||||
logger->set_pattern("%v");
|
||||
|
||||
|
||||
logger->info("Test message {}", 1);
|
||||
logger->info("Test message {}", 2);
|
||||
logger->flush();
|
||||
REQUIRE(file_contents(filename) == std::string("Test message 1\nTest message 2\n"));
|
||||
REQUIRE(count_lines(filename) == 2);
|
||||
|
||||
}
|
||||
|
||||
TEST_CASE("rotating_file_logger1", "[rotating_logger]]")
|
||||
{
|
||||
prepare_logdir();
|
||||
std::string basename = "logs/rotating_log";
|
||||
auto logger = spdlog::rotating_logger_mt("logger", basename, 1024, 0, true);
|
||||
for (int i = 0; i < 10; ++i)
|
||||
logger->info("Test message {}", i);
|
||||
|
||||
auto filename = basename + ".txt";
|
||||
REQUIRE(count_lines(filename) == 10);
|
||||
for (int i = 0; i < 1000; i++)
|
||||
logger->info("Test message {}", i);
|
||||
|
||||
}
|
||||
|
||||
|
||||
TEST_CASE("rotating_file_logger2", "[rotating_logger]]")
|
||||
{
|
||||
prepare_logdir();
|
||||
std::string basename = "logs/rotating_log";
|
||||
auto logger = spdlog::rotating_logger_mt("logger", basename, 1024, 1, false);
|
||||
for (int i = 0; i < 10; ++i)
|
||||
logger->info("Test message {}", i);
|
||||
|
||||
logger->flush();
|
||||
auto filename = basename + ".txt";
|
||||
REQUIRE(count_lines(filename) == 10);
|
||||
for (int i = 0; i < 1000; i++)
|
||||
logger->info("Test message {}", i);
|
||||
|
||||
logger->flush();
|
||||
REQUIRE(get_filesize(filename) <= 1024);
|
||||
auto filename1 = basename + ".1.txt";
|
||||
REQUIRE(get_filesize(filename1) <= 1024);
|
||||
}
|
||||
|
||||
|
||||
TEST_CASE("daily_logger", "[daily_logger]]")
|
||||
{
|
||||
|
||||
prepare_logdir();
|
||||
//calculate filename (time based)
|
||||
std::string basename = "logs/daily_log";
|
||||
std::tm tm = spdlog::details::os::localtime();
|
||||
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);
|
||||
|
||||
auto logger = spdlog::daily_logger_mt("logger", basename, 0, 0, true);
|
||||
for (int i = 0; i < 10; ++i)
|
||||
logger->info("Test message {}", i);
|
||||
|
||||
auto filename = w.str();
|
||||
REQUIRE(count_lines(filename) == 10);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* This content is released under the MIT License as specified in https://raw.githubusercontent.com/gabime/spdlog/master/LICENSE
|
||||
*/
|
||||
#include "includes.h"
|
||||
|
||||
|
||||
TEST_CASE("simple_file_logger", "[simple_logger]]")
|
||||
{
|
||||
prepare_logdir();
|
||||
std::string filename = "logs/simple_log.txt";
|
||||
|
||||
auto logger = spdlog::create<spdlog::sinks::simple_file_sink_mt>("logger", filename);
|
||||
logger->set_pattern("%v");
|
||||
|
||||
|
||||
logger->info("Test message {}", 1);
|
||||
logger->info("Test message {}", 2);
|
||||
logger->flush();
|
||||
REQUIRE(file_contents(filename) == std::string("Test message 1\nTest message 2\n"));
|
||||
REQUIRE(count_lines(filename) == 2);
|
||||
|
||||
}
|
||||
|
||||
TEST_CASE("rotating_file_logger1", "[rotating_logger]]")
|
||||
{
|
||||
prepare_logdir();
|
||||
std::string basename = "logs/rotating_log";
|
||||
auto logger = spdlog::rotating_logger_mt("logger", basename, 1024, 0, true);
|
||||
for (int i = 0; i < 10; ++i)
|
||||
logger->info("Test message {}", i);
|
||||
|
||||
auto filename = basename + ".txt";
|
||||
REQUIRE(count_lines(filename) == 10);
|
||||
for (int i = 0; i < 1000; i++)
|
||||
logger->info("Test message {}", i);
|
||||
|
||||
}
|
||||
|
||||
|
||||
TEST_CASE("rotating_file_logger2", "[rotating_logger]]")
|
||||
{
|
||||
prepare_logdir();
|
||||
std::string basename = "logs/rotating_log";
|
||||
auto logger = spdlog::rotating_logger_mt("logger", basename, 1024, 1, false);
|
||||
for (int i = 0; i < 10; ++i)
|
||||
logger->info("Test message {}", i);
|
||||
|
||||
logger->flush();
|
||||
auto filename = basename + ".txt";
|
||||
REQUIRE(count_lines(filename) == 10);
|
||||
for (int i = 0; i < 1000; i++)
|
||||
logger->info("Test message {}", i);
|
||||
|
||||
logger->flush();
|
||||
REQUIRE(get_filesize(filename) <= 1024);
|
||||
auto filename1 = basename + ".1.txt";
|
||||
REQUIRE(get_filesize(filename1) <= 1024);
|
||||
}
|
||||
|
||||
|
||||
TEST_CASE("daily_logger", "[daily_logger]]")
|
||||
{
|
||||
|
||||
prepare_logdir();
|
||||
//calculate filename (time based)
|
||||
std::string basename = "logs/daily_log";
|
||||
std::tm tm = spdlog::details::os::localtime();
|
||||
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);
|
||||
|
||||
auto logger = spdlog::daily_logger_mt("logger", basename, 0, 0, true);
|
||||
for (int i = 0; i < 10; ++i)
|
||||
logger->info("Test message {}", i);
|
||||
|
||||
auto filename = w.str();
|
||||
REQUIRE(count_lines(filename) == 10);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -1,16 +1,16 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdio>
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
#include <ostream>
|
||||
#include <chrono>
|
||||
#include <exception>
|
||||
|
||||
#include "catch.hpp"
|
||||
#include "utils.h"
|
||||
|
||||
#include "../include/spdlog/spdlog.h"
|
||||
#include "../include/spdlog/sinks/null_sink.h"
|
||||
#include "../include/spdlog/sinks/ostream_sink.h"
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdio>
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
#include <ostream>
|
||||
#include <chrono>
|
||||
#include <exception>
|
||||
|
||||
#include "catch.hpp"
|
||||
#include "utils.h"
|
||||
|
||||
#include "../include/spdlog/spdlog.h"
|
||||
#include "../include/spdlog/sinks/null_sink.h"
|
||||
#include "../include/spdlog/sinks/ostream_sink.h"
|
||||
|
||||
|
@ -1,45 +1,45 @@
|
||||
#include "includes.h"
|
||||
|
||||
void prepare_logdir()
|
||||
{
|
||||
spdlog::drop_all();
|
||||
#ifdef _WIN32
|
||||
auto rv = system("del /F /Q logs\\*");
|
||||
#else
|
||||
auto rv = system("rm -f logs/*");
|
||||
#endif
|
||||
(void)rv;
|
||||
}
|
||||
|
||||
|
||||
std::string file_contents(const std::string& filename)
|
||||
{
|
||||
std::ifstream ifs(filename);
|
||||
if (!ifs)
|
||||
throw std::runtime_error("Failed open file ");
|
||||
return std::string((std::istreambuf_iterator<char>(ifs)),
|
||||
(std::istreambuf_iterator<char>()));
|
||||
|
||||
}
|
||||
|
||||
std::size_t count_lines(const std::string& filename)
|
||||
{
|
||||
std::ifstream ifs(filename);
|
||||
if (!ifs)
|
||||
throw std::runtime_error("Failed open file ");
|
||||
|
||||
std::string line;
|
||||
size_t counter = 0;
|
||||
while(std::getline(ifs, line))
|
||||
counter++;
|
||||
return counter;
|
||||
}
|
||||
|
||||
std::size_t get_filesize(const std::string& filename)
|
||||
{
|
||||
std::ifstream ifs(filename, std::ifstream::ate | std::ifstream::binary);
|
||||
if (!ifs)
|
||||
throw std::runtime_error("Failed open file ");
|
||||
|
||||
return ifs.tellg();
|
||||
}
|
||||
#include "includes.h"
|
||||
|
||||
void prepare_logdir()
|
||||
{
|
||||
spdlog::drop_all();
|
||||
#ifdef _WIN32
|
||||
auto rv = system("del /F /Q logs\\*");
|
||||
#else
|
||||
auto rv = system("rm -f logs/*");
|
||||
#endif
|
||||
(void)rv;
|
||||
}
|
||||
|
||||
|
||||
std::string file_contents(const std::string& filename)
|
||||
{
|
||||
std::ifstream ifs(filename);
|
||||
if (!ifs)
|
||||
throw std::runtime_error("Failed open file ");
|
||||
return std::string((std::istreambuf_iterator<char>(ifs)),
|
||||
(std::istreambuf_iterator<char>()));
|
||||
|
||||
}
|
||||
|
||||
std::size_t count_lines(const std::string& filename)
|
||||
{
|
||||
std::ifstream ifs(filename);
|
||||
if (!ifs)
|
||||
throw std::runtime_error("Failed open file ");
|
||||
|
||||
std::string line;
|
||||
size_t counter = 0;
|
||||
while(std::getline(ifs, line))
|
||||
counter++;
|
||||
return counter;
|
||||
}
|
||||
|
||||
std::size_t get_filesize(const std::string& filename)
|
||||
{
|
||||
std::ifstream ifs(filename, std::ifstream::ate | std::ifstream::binary);
|
||||
if (!ifs)
|
||||
throw std::runtime_error("Failed open file ");
|
||||
|
||||
return ifs.tellg();
|
||||
}
|
||||
|
@ -1,15 +1,15 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include<cstddef>
|
||||
|
||||
std::size_t count_lines(const std::string& filename);
|
||||
|
||||
void prepare_logdir();
|
||||
|
||||
std::string file_contents(const std::string& filename);
|
||||
|
||||
std::size_t count_lines(const std::string& filename);
|
||||
|
||||
std::size_t get_filesize(const std::string& filename);
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include<cstddef>
|
||||
|
||||
std::size_t count_lines(const std::string& filename);
|
||||
|
||||
void prepare_logdir();
|
||||
|
||||
std::string file_contents(const std::string& filename);
|
||||
|
||||
std::size_t count_lines(const std::string& filename);
|
||||
|
||||
std::size_t get_filesize(const std::string& filename);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user