http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b02af540/include/spdlog/details/line_logger.h ---------------------------------------------------------------------- diff --git a/include/spdlog/details/line_logger.h b/include/spdlog/details/line_logger.h new file mode 100644 index 0000000..80d7cc1 --- /dev/null +++ b/include/spdlog/details/line_logger.h @@ -0,0 +1,221 @@ +/*************************************************************************/ +/* 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 <type_traits> +#include "../common.h" +#include "../logger.h" + +// Line logger class - aggregates operator<< calls to fast ostream +// and logs upon destruction + +namespace spdlog +{ +namespace details +{ +class line_logger +{ +public: + line_logger(logger* callback_logger, level::level_enum msg_level, bool enabled): + _callback_logger(callback_logger), + _log_msg(msg_level), + _enabled(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) : + _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 + ~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 + // + + + void write(const char* what) + { + if (_enabled) + _log_msg.raw << what; + } + + template <typename... Args> + void 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<< + // + line_logger& operator<<(const char* what) + { + if (_enabled) + _log_msg.raw << what; + return *this; + } + + line_logger& operator<<(const std::string& what) + { + if (_enabled) + _log_msg.raw << what; + return *this; + } + + line_logger& operator<<(int what) + { + if (_enabled) + _log_msg.raw << what; + return *this; + } + + line_logger& operator<<(unsigned int what) + { + if (_enabled) + _log_msg.raw << what; + return *this; + } + + + line_logger& operator<<(long what) + { + if (_enabled) + _log_msg.raw << what; + return *this; + } + + line_logger& operator<<(unsigned long what) + { + if (_enabled) + _log_msg.raw << what; + return *this; + } + + line_logger& operator<<(long long what) + { + if (_enabled) + _log_msg.raw << what; + return *this; + } + + line_logger& operator<<(unsigned long long what) + { + if (_enabled) + _log_msg.raw << what; + return *this; + } + + line_logger& operator<<(double what) + { + if (_enabled) + _log_msg.raw << what; + return *this; + } + + line_logger& operator<<(long double what) + { + if (_enabled) + _log_msg.raw << what; + return *this; + } + + line_logger& operator<<(float what) + { + if (_enabled) + _log_msg.raw << what; + return *this; + } + + line_logger& operator<<(char what) + { + if (_enabled) + _log_msg.raw << what; + return *this; + } + + //Support user types which implements operator<< + template<typename T> + line_logger& operator<<(const T& what) + { + if (_enabled) + _log_msg.raw.write("{}", what); + return *this; + } + + + void disable() + { + _enabled = false; + } + + bool is_enabled() const + { + return _enabled; + } + + +private: + logger* _callback_logger; + log_msg _log_msg; + bool _enabled; +}; +} //Namespace details +} // Namespace spdlog
http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b02af540/include/spdlog/details/log_msg.h ---------------------------------------------------------------------- diff --git a/include/spdlog/details/log_msg.h b/include/spdlog/details/log_msg.h new file mode 100644 index 0000000..bf58aca --- /dev/null +++ b/include/spdlog/details/log_msg.h @@ -0,0 +1,98 @@ +/*************************************************************************/ +/* 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 <thread> +#include "../common.h" +#include "./format.h" + +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; +}; +} +} http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b02af540/include/spdlog/details/logger_impl.h ---------------------------------------------------------------------- diff --git a/include/spdlog/details/logger_impl.h b/include/spdlog/details/logger_impl.h new file mode 100644 index 0000000..d658ac0 --- /dev/null +++ b/include/spdlog/details/logger_impl.h @@ -0,0 +1,320 @@ +/*************************************************************************/ +/* 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 +// +// Logger implementation +// + +#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) : + _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(); +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b02af540/include/spdlog/details/mpmc_bounded_q.h ---------------------------------------------------------------------- diff --git a/include/spdlog/details/mpmc_bounded_q.h b/include/spdlog/details/mpmc_bounded_q.h new file mode 100644 index 0000000..7cbcfd7 --- /dev/null +++ b/include/spdlog/details/mpmc_bounded_q.h @@ -0,0 +1,175 @@ +/* +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: + +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 <atomic> +#include "../common.h" + +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 http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b02af540/include/spdlog/details/null_mutex.h ---------------------------------------------------------------------- diff --git a/include/spdlog/details/null_mutex.h b/include/spdlog/details/null_mutex.h new file mode 100644 index 0000000..ebb56a5 --- /dev/null +++ b/include/spdlog/details/null_mutex.h @@ -0,0 +1,43 @@ +/*************************************************************************/ +/* 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 + +// null, no cost mutex + +namespace spdlog +{ +namespace details +{ +struct null_mutex +{ + void lock() {} + void unlock() {} + bool try_lock() + { + return true; + } +}; +} +} http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b02af540/include/spdlog/details/os.h ---------------------------------------------------------------------- diff --git a/include/spdlog/details/os.h b/include/spdlog/details/os.h new file mode 100644 index 0000000..753b6d9 --- /dev/null +++ b/include/spdlog/details/os.h @@ -0,0 +1,198 @@ +/*************************************************************************/ +/* 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<string> +#include<cstdio> +#include<ctime> + +#ifdef _WIN32 +# 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 <unistd.h> +#else +#include <thread> +#endif + +#include "../common.h" + +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 std::string& filename, const char* mode) +{ +#ifdef _WIN32 + *fp = _fsopen((filename.c_str()), mode, _SH_DENYWR); + return *fp == nullptr; +#else + *fp = fopen((filename.c_str()), mode); + return *fp == nullptr; +#endif + + +} + +//Return utc offset in minutes or -1 on failure +inline int utc_minutes_offset(const std::tm& tm = details::os::localtime()) +{ + +#ifdef _WIN32 + (void)tm; // avoid unused param warning + DYNAMIC_TIME_ZONE_INFORMATION tzinfo; + auto rv = GetDynamicTimeZoneInformation(&tzinfo); + if (!rv) + return -1; + return -1 * (tzinfo.Bias + tzinfo.DaylightBias); +#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__ + 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 + + + http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b02af540/include/spdlog/details/pattern_formatter_impl.h ---------------------------------------------------------------------- diff --git a/include/spdlog/details/pattern_formatter_impl.h b/include/spdlog/details/pattern_formatter_impl.h new file mode 100644 index 0000000..a5b2d21 --- /dev/null +++ b/include/spdlog/details/pattern_formatter_impl.h @@ -0,0 +1,628 @@ +/*************************************************************************/ +/* 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 <string> +#include <chrono> +#include <memory> +#include <vector> +#include <thread> + + +#include "../formatter.h" +#include "./log_msg.h" +#include "./os.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 +/////////////////////////////////////////////////////////////////////// +namespace +{ +class name_formatter :public flag_formatter +{ + void format(details::log_msg& msg, const std::tm&) override + { + msg.formatted << msg.logger_name; + } +}; +} + +// log level appender +class level_formatter :public flag_formatter +{ + void format(details::log_msg& msg, const std::tm&) override + { + msg.formatted << level::to_str(msg.level); + } +}; + +// short log level appender +class short_level_formatter :public flag_formatter +{ + void format(details::log_msg& msg, const std::tm&) override + { + msg.formatted << level::to_short_str(msg.level); + } +}; + +/////////////////////////////////////////////////////////////////////// +// Date time pattern appenders +/////////////////////////////////////////////////////////////////////// + +static const char* ampm(const tm& t) +{ + return t.tm_hour >= 12 ? "PM" : "AM"; +} + +static int to12h(const tm& t) +{ + return t.tm_hour > 12 ? t.tm_hour - 12 : t.tm_hour; +} + +//Abbreviated weekday name +static const std::string days[] { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" }; +class a_formatter :public flag_formatter +{ + void format(details::log_msg& msg, const std::tm& tm_time) override + { + msg.formatted << days[tm_time.tm_wday]; + } +}; + +//Full weekday name +static const std::string full_days[] { "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" }; +class A_formatter :public flag_formatter +{ + void format(details::log_msg& msg, const std::tm& tm_time) override + { + msg.formatted << full_days[tm_time.tm_wday]; + } +}; + +//Abbreviated month +static const std::string months[] { "Jan", "Feb", "Mar", "Apr", "May", "June", "July", "Aug", "Sept", "Oct", "Nov", "Dec" }; +class b_formatter :public flag_formatter +{ + void format(details::log_msg& msg, const std::tm& tm_time) override + { + msg.formatted<< months[tm_time.tm_mon]; + } +}; + +//Full month name +static const std::string full_months[] { "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" }; +class B_formatter :public flag_formatter +{ + void format(details::log_msg& msg, const std::tm& tm_time) override + { + msg.formatted << full_months[tm_time.tm_mon]; + } +}; + + +//write 2 ints seperated by sep with padding of 2 +static fmt::MemoryWriter& pad_n_join(fmt::MemoryWriter& w, int v1, int v2, char sep) +{ + w << fmt::pad(v1, 2, '0') << sep << fmt::pad(v2, 2, '0'); + return w; +} + +//write 3 ints seperated by sep with padding of 2 +static fmt::MemoryWriter& pad_n_join(fmt::MemoryWriter& w, int v1, int v2, int v3, char sep) +{ + w << fmt::pad(v1, 2, '0') << sep << fmt::pad(v2, 2, '0') << sep << fmt::pad(v3, 2, '0'); + return w; +} + + +//Date and time representation (Thu Aug 23 15:35:46 2014) +class c_formatter :public flag_formatter +{ + void format(details::log_msg& msg, const std::tm& tm_time) override + { + msg.formatted << days[tm_time.tm_wday] << ' ' << months[tm_time.tm_mon] << ' ' << tm_time.tm_mday << ' '; + pad_n_join(msg.formatted, tm_time.tm_hour, tm_time.tm_min, tm_time.tm_sec, ':') << ' ' << tm_time.tm_year + 1900; + } +}; + + +// year - 2 digit +class C_formatter :public flag_formatter +{ + void format(details::log_msg& msg, const std::tm& tm_time) override + { + msg.formatted << fmt::pad(tm_time.tm_year % 100, 2, '0'); + } +}; + + + +// Short MM/DD/YY date, equivalent to %m/%d/%y 08/23/01 +class D_formatter :public flag_formatter +{ + void format(details::log_msg& msg, const std::tm& tm_time) override + { + pad_n_join(msg.formatted, tm_time.tm_mon + 1, tm_time.tm_mday, tm_time.tm_year % 100, '/'); + } +}; + + +// year - 4 digit +class Y_formatter :public flag_formatter +{ + void format(details::log_msg& msg, const std::tm& tm_time) override + { + msg.formatted << tm_time.tm_year + 1900; + } +}; + +// month 1-12 +class m_formatter :public flag_formatter +{ + void format(details::log_msg& msg, const std::tm& tm_time) override + { + msg.formatted << fmt::pad(tm_time.tm_mon + 1, 2, '0'); + } +}; + +// day of month 1-31 +class d_formatter :public flag_formatter +{ + void format(details::log_msg& msg, const std::tm& tm_time) override + { + msg.formatted << fmt::pad(tm_time.tm_mday, 2, '0'); + } +}; + +// hours in 24 format 0-23 +class H_formatter :public flag_formatter +{ + void format(details::log_msg& msg, const std::tm& tm_time) override + { + msg.formatted << fmt::pad(tm_time.tm_hour, 2, '0'); + } +}; + +// hours in 12 format 1-12 +class I_formatter :public flag_formatter +{ + void format(details::log_msg& msg, const std::tm& tm_time) override + { + msg.formatted << fmt::pad(to12h(tm_time), 2, '0'); + } +}; + +// ninutes 0-59 +class M_formatter :public flag_formatter +{ + void format(details::log_msg& msg, const std::tm& tm_time) override + { + msg.formatted << fmt::pad(tm_time.tm_min, 2, '0'); + } +}; + +// seconds 0-59 +class S_formatter :public flag_formatter +{ + void format(details::log_msg& msg, const std::tm& tm_time) override + { + msg.formatted << fmt::pad(tm_time.tm_sec, 2, '0'); + } +}; + +// milliseconds +class e_formatter :public flag_formatter +{ + void format(details::log_msg& msg, const std::tm&) override + { + auto duration = msg.time.time_since_epoch(); + auto millis = std::chrono::duration_cast<std::chrono::milliseconds>(duration).count() % 1000; + msg.formatted << fmt::pad(static_cast<int>(millis), 3, '0'); + } +}; + +// microseconds +class f_formatter :public flag_formatter +{ + void format(details::log_msg& msg, const std::tm&) override + { + auto duration = msg.time.time_since_epoch(); + auto micros = std::chrono::duration_cast<std::chrono::microseconds>(duration).count() % 1000000; + msg.formatted << fmt::pad(static_cast<int>(micros), 6, '0'); + } +}; + +// AM/PM +class p_formatter :public flag_formatter +{ + void format(details::log_msg& msg, const std::tm& tm_time) override + { + msg.formatted << ampm(tm_time); + } +}; + + +// 12 hour clock 02:55:02 pm +class r_formatter :public flag_formatter +{ + void format(details::log_msg& msg, const std::tm& tm_time) override + { + pad_n_join(msg.formatted, to12h(tm_time), tm_time.tm_min, tm_time.tm_sec, ':') << ' ' << ampm(tm_time); + } +}; + +// 24-hour HH:MM time, equivalent to %H:%M +class R_formatter :public flag_formatter +{ + void format(details::log_msg& msg, const std::tm& tm_time) override + { + pad_n_join(msg.formatted, tm_time.tm_hour, tm_time.tm_min, ':'); + } +}; + +// ISO 8601 time format (HH:MM:SS), equivalent to %H:%M:%S +class T_formatter :public flag_formatter +{ + void format(details::log_msg& msg, const std::tm& tm_time) override + { + pad_n_join(msg.formatted, tm_time.tm_hour, tm_time.tm_min, tm_time.tm_sec, ':'); + } +}; + + +// ISO 8601 offset from UTC in timezone (+-HH:MM) +class z_formatter :public flag_formatter +{ +public: + const std::chrono::seconds cache_refresh = std::chrono::seconds(5); + + z_formatter() :_last_update(std::chrono::seconds(0)) {} + z_formatter(const z_formatter&) = delete; + z_formatter& operator=(const z_formatter&) = delete; + + void format(details::log_msg& msg, const std::tm& tm_time) override + { +#ifdef _WIN32 + int total_minutes = get_cached_offset(msg, tm_time); +#else + // No need to chache under gcc, + // it is very fast (already stored in tm.tm_gmtoff) + int total_minutes = os::utc_minutes_offset(tm_time); +#endif + + int h = total_minutes / 60; + int m = total_minutes % 60; + char sign = h >= 0 ? '+' : '-'; + msg.formatted << sign; + pad_n_join(msg.formatted, h, m, ':'); + } +private: + log_clock::time_point _last_update; + int _offset_minutes; + std::mutex _mutex; + + int get_cached_offset(const log_msg& msg, const std::tm& tm_time) + { + using namespace std::chrono; + std::lock_guard<std::mutex> l(_mutex); + if (msg.time - _last_update >= cache_refresh) + { + _offset_minutes = os::utc_minutes_offset(tm_time); + _last_update = msg.time; + } + return _offset_minutes; + } +}; + + + +//Thread id +class t_formatter :public flag_formatter +{ + void format(details::log_msg& msg, const std::tm&) override + { + msg.formatted << msg.thread_id; + } +}; + + +class v_formatter :public flag_formatter +{ + void format(details::log_msg& msg, const std::tm&) override + { + msg.formatted << fmt::StringRef(msg.raw.data(), msg.raw.size()); + } +}; + +class ch_formatter :public flag_formatter +{ +public: + explicit ch_formatter(char ch) : _ch(ch) + {} + void format(details::log_msg& msg, const std::tm&) override + { + msg.formatted << _ch; + } +private: + char _ch; +}; + + +//aggregate user chars to display as is +class aggregate_formatter :public flag_formatter +{ +public: + aggregate_formatter() + {} + void add_ch(char ch) + { + _str += ch; + } + void format(details::log_msg& msg, const std::tm&) override + { + msg.formatted << _str; + } +private: + std::string _str; +}; + +// Full info formatter +// pattern: [%Y-%m-%d %H:%M:%S.%e] [%n] [%l] %v +class full_formatter :public flag_formatter +{ + void format(details::log_msg& msg, const std::tm& tm_time) override + { +#ifndef SPDLOG_NO_DATETIME + auto duration = msg.time.time_since_epoch(); + auto millis = std::chrono::duration_cast<std::chrono::milliseconds>(duration).count() % 1000; + + /* Slower version(while still very fast - about 3.2 million lines/sec under 10 threads), + msg.formatted.write("[{:d}-{:02d}-{:02d} {:02d}:{:02d}:{:02d}.{:03d}] [{}] [{}] {} ", + tm_time.tm_year + 1900, + tm_time.tm_mon + 1, + tm_time.tm_mday, + tm_time.tm_hour, + tm_time.tm_min, + tm_time.tm_sec, + static_cast<int>(millis), + msg.logger_name, + level::to_str(msg.level), + msg.raw.str());*/ + + + // Faster (albeit uglier) way to format the line (5.6 million lines/sec under 10 threads) + msg.formatted << '[' << static_cast<unsigned int>(tm_time.tm_year + 1900) << '-' + << fmt::pad(static_cast<unsigned int>(tm_time.tm_mon + 1), 2, '0') << '-' + << fmt::pad(static_cast<unsigned int>(tm_time.tm_mday), 2, '0') << ' ' + << fmt::pad(static_cast<unsigned int>(tm_time.tm_hour), 2, '0') << ':' + << fmt::pad(static_cast<unsigned int>(tm_time.tm_min), 2, '0') << ':' + << fmt::pad(static_cast<unsigned int>(tm_time.tm_sec), 2, '0') << '.' + << fmt::pad(static_cast<unsigned int>(millis), 3, '0') << "] "; + +//no datetime needed +#else + (void)tm_time; +#endif + +#ifndef SPDLOG_NO_NAME + msg.formatted << '[' << msg.logger_name << "] "; +#endif + + msg.formatted << '[' << level::to_str(msg.level) << "] "; + msg.formatted << fmt::StringRef(msg.raw.data(), msg.raw.size()); + } +}; + +} +} +/////////////////////////////////////////////////////////////////////////////// +// pattern_formatter inline impl +/////////////////////////////////////////////////////////////////////////////// +inline spdlog::pattern_formatter::pattern_formatter(const std::string& pattern) +{ + compile_pattern(pattern); +} + +inline void spdlog::pattern_formatter::compile_pattern(const std::string& pattern) +{ + auto end = pattern.end(); + std::unique_ptr<details::aggregate_formatter> user_chars; + for (auto it = pattern.begin(); it != end; ++it) + { + if (*it == '%') + { + if (user_chars) //append user chars found so far + _formatters.push_back(std::move(user_chars)); + + if (++it != end) + handle_flag(*it); + else + break; + } + else // chars not following the % sign should be displayed as is + { + if (!user_chars) + user_chars = std::unique_ptr<details::aggregate_formatter>(new details::aggregate_formatter()); + user_chars->add_ch(*it); + } + } + if (user_chars) //append raw chars found so far + { + _formatters.push_back(std::move(user_chars)); + } + +} +inline void spdlog::pattern_formatter::handle_flag(char flag) +{ + switch (flag) + { + // logger name + case 'n': + _formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::name_formatter())); + break; + + case 'l': + _formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::level_formatter())); + break; + + case 'L': + _formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::short_level_formatter())); + break; + + case('t') : + _formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::t_formatter())); + break; + + case('v') : + _formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::v_formatter())); + break; + + case('a') : + _formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::a_formatter())); + break; + + case('A') : + _formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::A_formatter())); + break; + + case('b') : + case('h') : + _formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::b_formatter())); + break; + + case('B') : + _formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::B_formatter())); + break; + case('c') : + _formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::c_formatter())); + break; + + case('C') : + _formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::C_formatter())); + break; + + case('Y') : + _formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::Y_formatter())); + break; + + case('D') : + case('x') : + + _formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::D_formatter())); + break; + + case('m') : + _formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::m_formatter())); + break; + + case('d') : + _formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::d_formatter())); + break; + + case('H') : + _formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::H_formatter())); + break; + + case('I') : + _formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::I_formatter())); + break; + + case('M') : + _formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::M_formatter())); + break; + + case('S') : + _formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::S_formatter())); + break; + + case('e') : + _formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::e_formatter())); + break; + + case('f') : + _formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::f_formatter())); + break; + + case('p') : + _formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::p_formatter())); + break; + + case('r') : + _formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::r_formatter())); + break; + + case('R') : + _formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::R_formatter())); + break; + + case('T') : + case('X') : + _formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::T_formatter())); + break; + + case('z') : + _formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::z_formatter())); + break; + + case ('+'): + _formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::full_formatter())); + break; + + default: //Unkown flag appears as is + _formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::ch_formatter('%'))); + _formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::ch_formatter(flag))); + break; + } +} + + +inline void spdlog::pattern_formatter::format(details::log_msg& msg) +{ + try + { + auto tm_time = details::os::localtime(log_clock::to_time_t(msg.time)); + for (auto &f : _formatters) + { + f->format(msg, tm_time); + } + //write eol + msg.formatted << details::os::eol(); + } + catch(const fmt::FormatError& e) + { + throw spdlog_ex(fmt::format("formatting error while processing format string: {}", e.what())); + } +} http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b02af540/include/spdlog/details/registry.h ---------------------------------------------------------------------- diff --git a/include/spdlog/details/registry.h b/include/spdlog/details/registry.h new file mode 100644 index 0000000..fd8e4be --- /dev/null +++ b/include/spdlog/details/registry.h @@ -0,0 +1,180 @@ +/*************************************************************************/ +/* 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 +// Loggers registy of unique name->logger pointer +// 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" + +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); + register_logger_impl(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::shared_ptr<logger> new_logger; + + std::lock_guard<Mutex> lock(_mutex); + + + 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); + register_logger_impl(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: + void register_logger_impl(std::shared_ptr<logger> logger) + { + auto logger_name = logger->name(); + if (_loggers.find(logger_name) != std::end(_loggers)) + throw spdlog_ex("logger with name " + logger_name + " already exists"); + _loggers[logger->name()] = logger; + } + registry_t<Mutex>(){} + registry_t<Mutex>(const registry_t<Mutex>&) = delete; + registry_t<Mutex>& operator=(const registry_t<Mutex>&) = delete; + 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 +} +} http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b02af540/include/spdlog/details/spdlog_impl.h ---------------------------------------------------------------------- diff --git a/include/spdlog/details/spdlog_impl.h b/include/spdlog/details/spdlog_impl.h new file mode 100644 index 0000000..cfd6f82 --- /dev/null +++ b/include/spdlog/details/spdlog_impl.h @@ -0,0 +1,154 @@ +/*************************************************************************/ +/* 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 + +// +// 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); +} + + +template <typename Sink, typename... Args> +inline 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 }); +} + + +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(); +} + http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b02af540/include/spdlog/formatter.h ---------------------------------------------------------------------- diff --git a/include/spdlog/formatter.h b/include/spdlog/formatter.h new file mode 100644 index 0000000..35ea041 --- /dev/null +++ b/include/spdlog/formatter.h @@ -0,0 +1,58 @@ +/*************************************************************************/ +/* 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 "details/log_msg.h" +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 "details/pattern_formatter_impl.h" + http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b02af540/include/spdlog/logger.h ---------------------------------------------------------------------- diff --git a/include/spdlog/logger.h b/include/spdlog/logger.h new file mode 100644 index 0000000..7aefcc7 --- /dev/null +++ b/include/spdlog/logger.h @@ -0,0 +1,132 @@ +/*************************************************************************/ +/* 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 + +// 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<vector> +#include<memory> +#include "sinks/base_sink.h" +#include "common.h" + +namespace spdlog +{ + +namespace details +{ +class line_logger; +} + +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); + + 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; + std::atomic_int _level; + +}; +} + +#include "details/logger_impl.h" http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b02af540/include/spdlog/sinks/base_sink.h ---------------------------------------------------------------------- diff --git a/include/spdlog/sinks/base_sink.h b/include/spdlog/sinks/base_sink.h new file mode 100644 index 0000000..12d63ea --- /dev/null +++ b/include/spdlog/sinks/base_sink.h @@ -0,0 +1,66 @@ +/*************************************************************************/ +/* 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 +// +// 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<string> +#include<mutex> +#include<atomic> +#include "./sink.h" +#include "../formatter.h" +#include "../common.h" +#include "../details/log_msg.h" + + +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; +}; +} +} http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b02af540/include/spdlog/sinks/file_sinks.h ---------------------------------------------------------------------- diff --git a/include/spdlog/sinks/file_sinks.h b/include/spdlog/sinks/file_sinks.h new file mode 100644 index 0000000..79cbb4e --- /dev/null +++ b/include/spdlog/sinks/file_sinks.h @@ -0,0 +1,232 @@ +/*************************************************************************/ +/* 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 <mutex> +#include "base_sink.h" +#include "../details/null_mutex.h" +#include "../details/file_helper.h" +#include "../details/format.h" + +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 std::string &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 std::string &base_filename, const std::string &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)); + } + + 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 std::string calc_filename(const std::string& filename, std::size_t index, const std::string& extension) + { + fmt::MemoryWriter w; + if (index) + w.write("{}.{}.{}", filename, index, extension); + else + w.write("{}.{}", 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) + { + std::string src = calc_filename(_base_filename, i - 1, _extension); + std::string target = calc_filename(_base_filename, i, _extension); + + if (details::file_helper::file_exists(target)) + { + if (std::remove(target.c_str()) != 0) + { + throw spdlog_ex("rotating_file_sink: failed removing " + target); + } + } + if (details::file_helper::file_exists(src) && std::rename(src.c_str(), target.c_str())) + { + throw spdlog_ex("rotating_file_sink: failed renaming " + src + " to " + target); + } + } + _file_helper.reopen(true); + } + std::string _base_filename; + std::string _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 std::string& base_filename, + const std::string& 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 std::string calc_filename(const std::string& basename, const std::string& extension) + { + std::tm tm = spdlog::details::os::localtime(); + fmt::MemoryWriter w; + w.write("{}_{:04d}-{:02d}-{:02d}_{:02d}-{:02d}.{}", basename, tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, extension); + return w.str(); + } + + std::string _base_filename; + std::string _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; +} +}