pull/121/merge
Grégoire Astruc 10 years ago
commit 16a63a5f75

@ -0,0 +1,17 @@
cmake_minimum_required(VERSION 3.0)
project(spdlog CXX)
set(${PROJECT_NAME}_SRCS
include/spdlog/details/spdlog_impl.cc
include/spdlog/details/logger_impl.cc
include/spdlog/details/async_logger_impl.cc
include/spdlog/details/async_log_helper.cc
include/spdlog/details/format.cc
include/spdlog/details/pattern_formatter_impl.cc
)
add_library(${PROJECT_NAME} STATIC ${${PROJECT_NAME}_SRCS})
set_property(TARGET ${PROJECT_NAME} PROPERTY CXX_STANDARD 11)
target_compile_definitions(${PROJECT_NAME} PUBLIC SPDLOG_LIBRARY)
target_include_directories(${PROJECT_NAME} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include)
add_subdirectory(tests)

@ -38,7 +38,6 @@
#include <functional>
#include "common.h"
#include "logger.h"
#include "spdlog.h"
namespace spdlog

@ -0,0 +1,236 @@
/*************************************************************************/
/* spdlog - an extremely fast and easy to use c++11 logging library. */
/* Copyright (c) 2014 Gabi Melman. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
// 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
#ifdef SPDLOG_LIBRARY
#include "./async_log_helper.h"
#else
#pragma once
#endif
#include "../formatter.h"
#include "../sinks/sink.h"
#include "./log_msg.h"
#include "./os.h"
#include "./config.h"
SPDLOG_INLINE spdlog::details::async_log_helper::async_msg::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))
{
}
SPDLOG_INLINE spdlog::details::async_log_helper::async_msg& spdlog::details::async_log_helper::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);
return *this;
}
// construct from log_msg
SPDLOG_INLINE spdlog::details::async_log_helper::async_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())
{
}
// copy into log_msg
SPDLOG_INLINE void spdlog::details::async_log_helper::async_msg::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;
}
///////////////////////////////////////////////////////////////////////////////
// async_sink class implementation
///////////////////////////////////////////////////////////////////////////////
SPDLOG_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),
_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
SPDLOG_INLINE spdlog::details::async_log_helper::~async_log_helper()
{
try
{
log(log_msg(level::off));
_worker_thread.join();
}
catch (...) //Dont crash if thread not joinable
{}
}
//Try to push and block until succeeded
SPDLOG_INLINE void spdlog::details::async_log_helper::log(const details::log_msg& msg)
{
throw_if_bad_worker();
async_msg new_msg(msg);
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)));
}
}
SPDLOG_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)
SPDLOG_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();
if(incoming_async_msg.level == level::off)
return false;
incoming_async_msg.fill_log_msg(incoming_log_msg);
_formatter->format(incoming_log_msg);
for (auto &s : _sinks)
s->log(incoming_log_msg);
}
else //empty queue
{
auto now = details::os::now();
handle_flush_interval(now, last_flush);
sleep_or_yield(now, last_pop);
}
return true;
}
SPDLOG_INLINE void spdlog::details::async_log_helper::handle_flush_interval(log_clock::time_point& now, log_clock::time_point& last_flush)
{
if (_flush_interval_ms != std::chrono::milliseconds::zero() && now - last_flush >= _flush_interval_ms)
{
for (auto &s : _sinks)
s->flush();
now = last_flush = details::os::now();
}
}
SPDLOG_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
SPDLOG_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
SPDLOG_INLINE void spdlog::details::async_log_helper::throw_if_bad_worker()
{
if (_last_workerthread_ex)
{
auto ex = std::move(_last_workerthread_ex);
throw *ex;
}
}

@ -32,24 +32,17 @@
// will be thrown in client's thread when tries to log the next message
#pragma once
#include <chrono>
#include <thread>
#include <atomic>
#include <functional>
#include <vector>
#include "../common.h"
#include "../sinks/sink.h"
#include "./mpmc_bounded_q.h"
#include "./log_msg.h"
#include "./format.h"
#include "os.h"
namespace spdlog
{
namespace details
{
class log_msg;
class async_log_helper
{
@ -66,46 +59,19 @@ class async_log_helper
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))
{}
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);
return *this;
}
async_msg(async_msg&& other) SPDLOG_NOEXCEPT;
async_msg& operator=(async_msg&& other) SPDLOG_NOEXCEPT;
// 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())
{}
async_msg(const details::log_msg& m);
// 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;
}
void fill_log_msg(log_msg &msg);
};
public:
@ -174,153 +140,6 @@ private:
}
}
///////////////////////////////////////////////////////////////////////////////
// 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),
_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
{
log(log_msg(level::off));
_worker_thread.join();
}
catch (...) //Dont crash if thread not joinable
{}
}
//Try to push and block until succeeded
inline void spdlog::details::async_log_helper::log(const details::log_msg& msg)
{
throw_if_bad_worker();
async_msg new_msg(msg);
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::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();
if(incoming_async_msg.level == level::off)
return false;
incoming_async_msg.fill_log_msg(incoming_log_msg);
_formatter->format(incoming_log_msg);
for (auto &s : _sinks)
s->log(incoming_log_msg);
}
else //empty queue
{
auto now = details::os::now();
handle_flush_interval(now, last_flush);
sleep_or_yield(now, last_pop);
}
return true;
}
inline void spdlog::details::async_log_helper::handle_flush_interval(log_clock::time_point& now, log_clock::time_point& last_flush)
{
if (_flush_interval_ms != std::chrono::milliseconds::zero() && now - last_flush >= _flush_interval_ms)
{
for (auto &s : _sinks)
s->flush();
now = last_flush = details::os::now();
}
}
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;
}
}
#ifndef SPDLOG_LIBRARY
#include "./async_log_helper.cc"
#endif

@ -0,0 +1,67 @@
/*************************************************************************/
/* spdlog - an extremely fast and easy to use c++11 logging library. */
/* Copyright (c) 2014 Gabi Melman. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#ifdef SPDLOG_LIBRARY
#include "../async_logger.h"
#else
#pragma once
#endif
#include "./async_log_helper.h"
#include "./config.h"
SPDLOG_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) {}
SPDLOG_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) {}
SPDLOG_INLINE void spdlog::async_logger::_set_formatter(spdlog::formatter_ptr msg_formatter)
{
_formatter = msg_formatter;
_async_log_helper->set_formatter(_formatter);
}
SPDLOG_INLINE void spdlog::async_logger::_set_pattern(const std::string& pattern)
{
_formatter = std::make_shared<pattern_formatter>(pattern);
_async_log_helper->set_formatter(_formatter);
}
SPDLOG_INLINE void spdlog::async_logger::_log_msg(details::log_msg& msg)
{
_async_log_helper->log(msg);
}

@ -46,37 +46,6 @@ inline spdlog::async_logger::async_logger(const std::string& logger_name,
{
}
inline spdlog::async_logger::async_logger(const std::string& logger_name,
sinks_init_list sinks,
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::_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);
}
#ifndef SPDLOG_LIBRARY
#include "./async_logger_impl.cc"
#endif

@ -0,0 +1,30 @@
/*************************************************************************/
/* spdlog - an extremely fast and easy to use c++11 logging library. */
/* Copyright (c) 2015 Gabi Melman. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#pragma once
#include "../tweakme.h"
#ifdef SPDLOG_LIBRARY
#define SPDLOG_INLINE
#else
#define SPDLOG_INLINE inline
#endif

@ -0,0 +1,39 @@
/*************************************************************************/
/* spdlog - an extremely fast and easy to use c++11 logging library. */
/* Copyright (c) 2014 Gabi Melman. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#pragma once
#include <ctime>
namespace spdlog
{
namespace details
{
class log_msg;
class flag_formatter
{
public:
virtual ~flag_formatter() {}
virtual void format(details::log_msg& msg, const std::tm& tm_time) = 0;
};
} // ns details
} // ns spdlog

@ -27,7 +27,9 @@
#ifndef FMT_FORMAT_H_
#define FMT_FORMAT_H_
#ifndef SPDLOG_LIBRARY
#define FMT_HEADER_ONLY
#endif
#include <stdint.h>
@ -3013,4 +3015,4 @@ FMT_VARIADIC(int, fprintf, std::FILE *, CStringRef)
# include "format.cc"
#endif
#endif // FMT_FORMAT_H_
#endif // FMT_FORMAT_H_

@ -26,6 +26,7 @@
#include <type_traits>
#include "../common.h"
#include "../logger.h"
#include "./os.h"
// Line logger class - aggregates operator<< calls to fast ostream
// and logs upon destruction

@ -0,0 +1,163 @@
/*************************************************************************/
/* spdlog - an extremely fast and easy to use c++11 logging library. */
/* Copyright (c) 2014 Gabi Melman. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#ifdef SPDLOG_LIBRARY
#include "../logger.h"
#else
#pragma once
#endif
#include "../sinks/sink.h"
#include "./line_logger.h"
#include "./config.h"
// ctor with sinks as init list
SPDLOG_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
SPDLOG_INLINE spdlog::logger::logger(const std::string& logger_name, spdlog::sink_ptr single_sink) :
logger(logger_name, {
single_sink
}) {}
SPDLOG_INLINE spdlog::logger::~logger() = default;
SPDLOG_INLINE void spdlog::logger::set_formatter(spdlog::formatter_ptr msg_formatter)
{
_set_formatter(msg_formatter);
}
SPDLOG_INLINE void spdlog::logger::set_pattern(const std::string& pattern)
{
_set_pattern(pattern);
}
//
// log only if given level>=logger's log level
//
SPDLOG_INLINE spdlog::details::line_logger spdlog::logger::_log_if_enabled(level::level_enum lvl)
{
return details::line_logger(this, lvl, should_log(lvl));
}
//
// logger.info() << ".." call style
//
SPDLOG_INLINE spdlog::details::line_logger spdlog::logger::trace()
{
return _log_if_enabled(level::trace);
}
SPDLOG_INLINE spdlog::details::line_logger spdlog::logger::debug()
{
return _log_if_enabled(level::debug);
}
SPDLOG_INLINE spdlog::details::line_logger spdlog::logger::info()
{
return _log_if_enabled(level::info);
}
SPDLOG_INLINE spdlog::details::line_logger spdlog::logger::notice()
{
return _log_if_enabled(level::notice);
}
SPDLOG_INLINE spdlog::details::line_logger spdlog::logger::warn()
{
return _log_if_enabled(level::warn);
}
SPDLOG_INLINE spdlog::details::line_logger spdlog::logger::error()
{
return _log_if_enabled(level::err);
}
SPDLOG_INLINE spdlog::details::line_logger spdlog::logger::critical()
{
return _log_if_enabled(level::critical);
}
SPDLOG_INLINE spdlog::details::line_logger spdlog::logger::alert()
{
return _log_if_enabled(level::alert);
}
SPDLOG_INLINE spdlog::details::line_logger spdlog::logger::emerg()
{
return _log_if_enabled(level::emerg);
}
//
// name and level
//
SPDLOG_INLINE const std::string& spdlog::logger::name() const
{
return _name;
}
SPDLOG_INLINE void spdlog::logger::set_level(spdlog::level::level_enum log_level)
{
_level.store(log_level);
}
SPDLOG_INLINE spdlog::level::level_enum spdlog::logger::level() const
{
return static_cast<spdlog::level::level_enum>(_level.load(std::memory_order_relaxed));
}
SPDLOG_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
//
SPDLOG_INLINE void spdlog::logger::_log_msg(details::log_msg& msg)
{
_formatter->format(msg);
for (auto &sink : _sinks)
sink->log(msg);
}
SPDLOG_INLINE void spdlog::logger::_set_pattern(const std::string& pattern)
{
_formatter = std::make_shared<pattern_formatter>(pattern);
}
SPDLOG_INLINE void spdlog::logger::_set_formatter(formatter_ptr msg_formatter)
{
_formatter = msg_formatter;
}
SPDLOG_INLINE void spdlog::logger::flush() {
for (auto& sink : _sinks)
sink->flush();
}

@ -26,14 +26,16 @@
//
// Logger implementation
//
#include "../formatter.h"
#include "./flag_formatter.h"
#include "./log_msg.h"
#include "./line_logger.h"
// 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) :
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>("%+"))
@ -43,31 +45,6 @@ inline spdlog::logger::logger(const std::string& logger_name, const It& begin, c
_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
//
@ -82,11 +59,6 @@ inline spdlog::details::line_logger spdlog::logger::_log_if_enabled(level::level
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)
{
@ -211,58 +183,6 @@ 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)
@ -272,49 +192,6 @@ inline spdlog::details::line_logger spdlog::logger::force_log(level::level_enum
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();
}
#ifndef SPDLOG_LIBRARY
#include "./logger_impl.cc"
#endif

@ -21,30 +21,24 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#ifdef SPDLOG_LIBRARY
#include "../formatter.h"
#else
#pragma once
#endif
#include <string>
#include <chrono>
#include <memory>
#include <vector>
#include <thread>
#include <mutex>
#include "../formatter.h"
#include "./flag_formatter.h"
#include "./log_msg.h"
#include "./os.h"
#include "./config.h"
namespace spdlog
{
namespace details
{
class flag_formatter
{
public:
virtual ~flag_formatter() {}
virtual void format(details::log_msg& msg, const std::tm& tm_time) = 0;
};
///////////////////////////////////////////////////////////////////////
// name & level pattern appenders
@ -462,12 +456,12 @@ class full_formatter :public flag_formatter
///////////////////////////////////////////////////////////////////////////////
// pattern_formatter inline impl
///////////////////////////////////////////////////////////////////////////////
inline spdlog::pattern_formatter::pattern_formatter(const std::string& pattern)
SPDLOG_INLINE spdlog::pattern_formatter::pattern_formatter(const std::string& pattern)
{
compile_pattern(pattern);
}
inline void spdlog::pattern_formatter::compile_pattern(const std::string& pattern)
SPDLOG_INLINE void spdlog::pattern_formatter::compile_pattern(const std::string& pattern)
{
auto end = pattern.end();
std::unique_ptr<details::aggregate_formatter> user_chars;
@ -496,7 +490,7 @@ inline void spdlog::pattern_formatter::compile_pattern(const std::string& patter
}
}
inline void spdlog::pattern_formatter::handle_flag(char flag)
SPDLOG_INLINE void spdlog::pattern_formatter::handle_flag(char flag)
{
switch (flag)
{
@ -623,7 +617,7 @@ inline void spdlog::pattern_formatter::handle_flag(char flag)
}
inline void spdlog::pattern_formatter::format(details::log_msg& msg)
SPDLOG_INLINE void spdlog::pattern_formatter::format(details::log_msg& msg)
{
try
{

@ -27,16 +27,11 @@
// An attempt to create a logger with an alreasy existing name will be ignored
// If user requests a non existing logger, nullptr will be returned
// This class is thread safe
#include <string>
#include <mutex>
#include <unordered_map>
#include <functional>
#include "./null_mutex.h"
#include "../logger.h"
#include "../async_logger.h"
#include "../common.h"
#include "./flag_formatter.h"
namespace spdlog
{

@ -0,0 +1,146 @@
/*************************************************************************/
/* spdlog - an extremely fast and easy to use c++11 logging library. */
/* Copyright (c) 2014 Gabi Melman. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#ifdef SPDLOG_LIBRARY
#include "../spdlog.h"
#else
#pragma once
#endif
//
// Global registry functions
//
#include "./registry.h"
#include "../sinks/file_sinks.h"
#include "../sinks/stdout_sinks.h"
#include "../sinks/syslog_sink.h"
#include "./config.h"
namespace spdlog
{
SPDLOG_INLINE void register_logger(std::shared_ptr<logger> logger)
{
return details::registry::instance().register_logger(logger);
}
SPDLOG_INLINE std::shared_ptr<logger> get(const std::string& name)
{
return details::registry::instance().get(name);
}
SPDLOG_INLINE void drop(const std::string &name)
{
details::registry::instance().drop(name);
}
// Create multi/single threaded rotating file logger
SPDLOG_INLINE std::shared_ptr<logger> rotating_logger_mt(const std::string& logger_name, const std::string& filename, size_t max_file_size, size_t max_files, bool force_flush)
{
return create<sinks::rotating_file_sink_mt>(logger_name, filename, "txt", max_file_size, max_files, force_flush);
}
SPDLOG_INLINE std::shared_ptr<logger> rotating_logger_st(const std::string& logger_name, const std::string& filename, size_t max_file_size, size_t max_files, bool force_flush)
{
return create<sinks::rotating_file_sink_st>(logger_name, filename, "txt", max_file_size, max_files, force_flush);
}
// Create file logger which creates new file at midnight):
SPDLOG_INLINE std::shared_ptr<logger> daily_logger_mt(const std::string& logger_name, const std::string& filename, int hour, int minute, bool force_flush)
{
return create<sinks::daily_file_sink_mt>(logger_name, filename, "txt", hour, minute, force_flush);
}
SPDLOG_INLINE std::shared_ptr<logger> daily_logger_st(const std::string& logger_name, const std::string& filename, int hour, int minute, bool force_flush)
{
return create<sinks::daily_file_sink_st>(logger_name, filename, "txt", hour, minute, force_flush);
}
// Create stdout/stderr loggers
SPDLOG_INLINE std::shared_ptr<logger> stdout_logger_mt(const std::string& logger_name)
{
return details::registry::instance().create(logger_name, sinks::stdout_sink_mt::instance());
}
SPDLOG_INLINE std::shared_ptr<logger> stdout_logger_st(const std::string& logger_name)
{
return details::registry::instance().create(logger_name, sinks::stdout_sink_st::instance());
}
SPDLOG_INLINE std::shared_ptr<logger> stderr_logger_mt(const std::string& logger_name)
{
return details::registry::instance().create(logger_name, sinks::stderr_sink_mt::instance());
}
SPDLOG_INLINE std::shared_ptr<logger> stderr_logger_st(const std::string& logger_name)
{
return details::registry::instance().create(logger_name, sinks::stderr_sink_st::instance());
}
#ifdef __linux__
// Create syslog logger
SPDLOG_INLINE std::shared_ptr<logger> syslog_logger(const std::string& logger_name, const std::string& syslog_ident, int syslog_option)
{
return create<sinks::syslog_sink>(logger_name, syslog_ident, syslog_option);
}
#endif
//Create logger with multiple sinks
SPDLOG_INLINE std::shared_ptr<logger> create(const std::string& logger_name, sinks_init_list sinks)
{
return details::registry::instance().create(logger_name, sinks);
}
SPDLOG_INLINE void set_formatter(formatter_ptr f)
{
details::registry::instance().formatter(f);
}
SPDLOG_INLINE void set_pattern(const std::string& format_string)
{
return details::registry::instance().set_pattern(format_string);
}
SPDLOG_INLINE void set_level(level::level_enum log_level)
{
return details::registry::instance().set_level(log_level);
}
SPDLOG_INLINE void 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);
}
SPDLOG_INLINE void set_sync_mode()
{
details::registry::instance().set_sync_mode();
}
SPDLOG_INLINE void drop_all()
{
details::registry::instance().drop_all();
}
}

@ -27,88 +27,10 @@
//
// Global registry functions
//
#include "registry.h"
#include "../sinks/file_sinks.h"
#include "../sinks/stdout_sinks.h"
#include "../sinks/syslog_sink.h"
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 std::string& filename, size_t max_file_size, size_t max_files, bool force_flush)
{
return create<spdlog::sinks::rotating_file_sink_mt>(logger_name, filename, "txt", max_file_size, max_files, force_flush);
}
inline std::shared_ptr<spdlog::logger> spdlog::rotating_logger_st(const std::string& logger_name, const std::string& filename, size_t max_file_size, size_t max_files, bool force_flush)
{
return create<spdlog::sinks::rotating_file_sink_st>(logger_name, filename, "txt", max_file_size, max_files, force_flush);
}
// Create file logger which creates new file at midnight):
inline std::shared_ptr<spdlog::logger> spdlog::daily_logger_mt(const std::string& logger_name, const std::string& filename, int hour, int minute, bool force_flush)
{
return create<spdlog::sinks::daily_file_sink_mt>(logger_name, filename, "txt", hour, minute, force_flush);
}
inline std::shared_ptr<spdlog::logger> spdlog::daily_logger_st(const std::string& logger_name, const std::string& filename, int hour, int minute, bool force_flush)
{
return create<spdlog::sinks::daily_file_sink_st>(logger_name, filename, "txt", hour, minute, force_flush);
}
// Create stdout/stderr loggers
inline std::shared_ptr<spdlog::logger> spdlog::stdout_logger_mt(const std::string& logger_name)
{
return details::registry::instance().create(logger_name, spdlog::sinks::stdout_sink_mt::instance());
}
inline std::shared_ptr<spdlog::logger> spdlog::stdout_logger_st(const std::string& logger_name)
{
return details::registry::instance().create(logger_name, spdlog::sinks::stdout_sink_st::instance());
}
inline std::shared_ptr<spdlog::logger> spdlog::stderr_logger_mt(const std::string& logger_name)
{
return details::registry::instance().create(logger_name, spdlog::sinks::stderr_sink_mt::instance());
}
inline std::shared_ptr<spdlog::logger> spdlog::stderr_logger_st(const std::string& logger_name)
{
return details::registry::instance().create(logger_name, spdlog::sinks::stderr_sink_st::instance());
}
#ifdef __linux__
// 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);
}
#include "./registry.h"
template <typename Sink, typename... Args>
inline std::shared_ptr<spdlog::logger> spdlog::create(const std::string& logger_name, const Args&... args)
std::shared_ptr<spdlog::logger> spdlog::create(const std::string& logger_name, const Args&... args)
{
sink_ptr sink = std::make_shared<Sink>(args...);
return details::registry::instance().create(logger_name, { sink });
@ -116,39 +38,11 @@ inline std::shared_ptr<spdlog::logger> spdlog::create(const std::string& logger_
template<class It>
inline std::shared_ptr<spdlog::logger> spdlog::create(const std::string& logger_name, const It& sinks_begin, const It& sinks_end)
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();
}
#ifndef SPDLOG_LIBRARY
#include "./spdlog_impl.cc"
#endif

@ -22,13 +22,16 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#pragma once
#include <memory>
#include <string>
#include <vector>
#include "details/log_msg.h"
namespace spdlog
{
namespace details
{
class flag_formatter;
class log_msg;
}
class formatter
@ -54,5 +57,7 @@ private:
};
}
#include "details/pattern_formatter_impl.h"
#ifndef SPDLOG_LIBRARY
#include "./details/pattern_formatter_impl.cc"
#endif

@ -31,9 +31,9 @@
// 2. Format the message using the formatter function
// 3. Pass the formatted message to its sinks to performa the actual logging
#include<vector>
#include<memory>
#include "sinks/base_sink.h"
#include <atomic>
#include <vector>
#include <memory>
#include "common.h"
namespace spdlog
@ -42,6 +42,7 @@ namespace spdlog
namespace details
{
class line_logger;
class log_msg;
}
class logger

@ -24,10 +24,9 @@
#pragma once
#include "../details/log_msg.h"
namespace spdlog
{
namespace details { struct log_msg; }
namespace sinks
{
class sink

@ -152,4 +152,4 @@ void drop_all();
}
#include "details/spdlog_impl.h"
#include "./details/spdlog_impl.h"

@ -72,3 +72,9 @@
// Note that upon creating a logger the registry is modified by spdlog..
// #define SPDLOG_NO_REGISTRY_MUTEX
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
// Uncomment if you want to compile as a static library
// #define SPDLOG_LIBRARY
///////////////////////////////////////////////////////////////////////////////

@ -0,0 +1,13 @@
cmake_minimum_required(VERSION 3.0)
set(TESTS_SRCS
file_log.cpp
format.cpp
main.cpp
registry.cpp
)
add_executable(spdlog-test ${TESTS_SRCS})
target_link_libraries(spdlog-test spdlog)
target_include_directories(spdlog-test PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
set_property(TARGET spdlog-test PROPERTY CXX_STANDARD 11)

@ -1,6 +1,7 @@
#pragma once
#include <cstdio>
#include <cstring>
#include <fstream>
#include <string>
#include <ostream>
@ -10,3 +11,5 @@
#include "catch.hpp"
#include "../include/spdlog/spdlog.h"
#include "../include/spdlog/sinks/null_sink.h"
#include "../include/spdlog/sinks/file_sinks.h"
#include "../include/spdlog/sinks/ostream_sink.h"

Loading…
Cancel
Save