From 07b70e0ac134f348f24c6cd2b7619b9da87225aa Mon Sep 17 00:00:00 2001 From: Nicolas Morales Date: Wed, 15 Nov 2023 14:48:40 -0800 Subject: [PATCH 01/11] #19: logging: add spdlog as a bundled dependency --- CMakeLists.txt | 2 + tpl/CMakeLists.txt | 1 + tpl/spdlog/CMakeLists.txt | 10 + tpl/spdlog/include/spdlog/async.h | 99 ++ tpl/spdlog/include/spdlog/async_logger-inl.h | 90 ++ tpl/spdlog/include/spdlog/async_logger.h | 68 + tpl/spdlog/include/spdlog/cfg/argv.h | 44 + tpl/spdlog/include/spdlog/cfg/env.h | 38 + tpl/spdlog/include/spdlog/cfg/helpers-inl.h | 120 ++ tpl/spdlog/include/spdlog/cfg/helpers.h | 29 + tpl/spdlog/include/spdlog/common-inl.h | 82 + tpl/spdlog/include/spdlog/common.h | 426 +++++ .../include/spdlog/details/backtracer-inl.h | 75 + .../include/spdlog/details/backtracer.h | 46 + .../include/spdlog/details/circular_q.h | 146 ++ .../include/spdlog/details/console_globals.h | 32 + .../include/spdlog/details/file_helper-inl.h | 180 +++ .../include/spdlog/details/file_helper.h | 62 + .../include/spdlog/details/fmt_helper.h | 164 ++ .../include/spdlog/details/log_msg-inl.h | 37 + tpl/spdlog/include/spdlog/details/log_msg.h | 37 + .../spdlog/details/log_msg_buffer-inl.h | 58 + .../include/spdlog/details/log_msg_buffer.h | 33 + .../include/spdlog/details/mpmc_blocking_q.h | 154 ++ .../include/spdlog/details/null_mutex.h | 45 + tpl/spdlog/include/spdlog/details/os-inl.h | 635 ++++++++ tpl/spdlog/include/spdlog/details/os.h | 122 ++ .../spdlog/details/periodic_worker-inl.h | 28 + .../include/spdlog/details/periodic_worker.h | 60 + .../include/spdlog/details/registry-inl.h | 315 ++++ tpl/spdlog/include/spdlog/details/registry.h | 123 ++ .../spdlog/details/synchronous_factory.h | 24 + .../spdlog/details/tcp_client-windows.h | 160 ++ .../include/spdlog/details/tcp_client.h | 146 ++ .../include/spdlog/details/thread_pool-inl.h | 137 ++ .../include/spdlog/details/thread_pool.h | 122 ++ .../spdlog/details/udp_client-windows.h | 113 ++ .../include/spdlog/details/udp_client.h | 94 ++ .../include/spdlog/details/windows_include.h | 11 + tpl/spdlog/include/spdlog/fmt/bin_to_hex.h | 248 +++ tpl/spdlog/include/spdlog/fmt/chrono.h | 22 + tpl/spdlog/include/spdlog/fmt/compile.h | 22 + tpl/spdlog/include/spdlog/fmt/fmt.h | 33 + tpl/spdlog/include/spdlog/fmt/ostr.h | 22 + tpl/spdlog/include/spdlog/fmt/ranges.h | 22 + tpl/spdlog/include/spdlog/fmt/std.h | 23 + tpl/spdlog/include/spdlog/fmt/xchar.h | 22 + tpl/spdlog/include/spdlog/formatter.h | 18 + tpl/spdlog/include/spdlog/fwd.h | 18 + tpl/spdlog/include/spdlog/logger-inl.h | 257 +++ tpl/spdlog/include/spdlog/logger.h | 427 +++++ .../include/spdlog/pattern_formatter-inl.h | 1436 +++++++++++++++++ tpl/spdlog/include/spdlog/pattern_formatter.h | 128 ++ .../include/spdlog/sinks/android_sink.h | 146 ++ .../include/spdlog/sinks/ansicolor_sink-inl.h | 145 ++ .../include/spdlog/sinks/ansicolor_sink.h | 118 ++ .../include/spdlog/sinks/base_sink-inl.h | 63 + tpl/spdlog/include/spdlog/sinks/base_sink.h | 52 + .../spdlog/sinks/basic_file_sink-inl.h | 44 + .../include/spdlog/sinks/basic_file_sink.h | 60 + .../include/spdlog/sinks/callback_sink.h | 61 + .../include/spdlog/sinks/daily_file_sink.h | 247 +++ tpl/spdlog/include/spdlog/sinks/dist_sink.h | 97 ++ .../include/spdlog/sinks/dup_filter_sink.h | 96 ++ .../include/spdlog/sinks/hourly_file_sink.h | 204 +++ tpl/spdlog/include/spdlog/sinks/kafka_sink.h | 133 ++ tpl/spdlog/include/spdlog/sinks/mongo_sink.h | 107 ++ tpl/spdlog/include/spdlog/sinks/msvc_sink.h | 71 + tpl/spdlog/include/spdlog/sinks/null_sink.h | 44 + .../include/spdlog/sinks/ostream_sink.h | 50 + tpl/spdlog/include/spdlog/sinks/qt_sinks.h | 292 ++++ .../include/spdlog/sinks/ringbuffer_sink.h | 74 + .../spdlog/sinks/rotating_file_sink-inl.h | 152 ++ .../include/spdlog/sinks/rotating_file_sink.h | 81 + tpl/spdlog/include/spdlog/sinks/sink-inl.h | 25 + tpl/spdlog/include/spdlog/sinks/sink.h | 35 + .../spdlog/sinks/stdout_color_sinks-inl.h | 38 + .../include/spdlog/sinks/stdout_color_sinks.h | 45 + .../include/spdlog/sinks/stdout_sinks-inl.h | 138 ++ .../include/spdlog/sinks/stdout_sinks.h | 87 + tpl/spdlog/include/spdlog/sinks/syslog_sink.h | 109 ++ .../include/spdlog/sinks/systemd_sink.h | 126 ++ tpl/spdlog/include/spdlog/sinks/tcp_sink.h | 81 + tpl/spdlog/include/spdlog/sinks/udp_sink.h | 74 + .../include/spdlog/sinks/win_eventlog_sink.h | 289 ++++ .../include/spdlog/sinks/wincolor_sink-inl.h | 175 ++ .../include/spdlog/sinks/wincolor_sink.h | 85 + tpl/spdlog/include/spdlog/spdlog-inl.h | 125 ++ tpl/spdlog/include/spdlog/spdlog.h | 363 +++++ tpl/spdlog/include/spdlog/stopwatch.h | 69 + tpl/spdlog/include/spdlog/tweakme.h | 140 ++ tpl/spdlog/include/spdlog/version.h | 10 + 92 files changed, 11217 insertions(+) create mode 100644 tpl/CMakeLists.txt create mode 100644 tpl/spdlog/CMakeLists.txt create mode 100644 tpl/spdlog/include/spdlog/async.h create mode 100644 tpl/spdlog/include/spdlog/async_logger-inl.h create mode 100644 tpl/spdlog/include/spdlog/async_logger.h create mode 100644 tpl/spdlog/include/spdlog/cfg/argv.h create mode 100644 tpl/spdlog/include/spdlog/cfg/env.h create mode 100644 tpl/spdlog/include/spdlog/cfg/helpers-inl.h create mode 100644 tpl/spdlog/include/spdlog/cfg/helpers.h create mode 100644 tpl/spdlog/include/spdlog/common-inl.h create mode 100644 tpl/spdlog/include/spdlog/common.h create mode 100644 tpl/spdlog/include/spdlog/details/backtracer-inl.h create mode 100644 tpl/spdlog/include/spdlog/details/backtracer.h create mode 100644 tpl/spdlog/include/spdlog/details/circular_q.h create mode 100644 tpl/spdlog/include/spdlog/details/console_globals.h create mode 100644 tpl/spdlog/include/spdlog/details/file_helper-inl.h create mode 100644 tpl/spdlog/include/spdlog/details/file_helper.h create mode 100644 tpl/spdlog/include/spdlog/details/fmt_helper.h create mode 100644 tpl/spdlog/include/spdlog/details/log_msg-inl.h create mode 100644 tpl/spdlog/include/spdlog/details/log_msg.h create mode 100644 tpl/spdlog/include/spdlog/details/log_msg_buffer-inl.h create mode 100644 tpl/spdlog/include/spdlog/details/log_msg_buffer.h create mode 100644 tpl/spdlog/include/spdlog/details/mpmc_blocking_q.h create mode 100644 tpl/spdlog/include/spdlog/details/null_mutex.h create mode 100644 tpl/spdlog/include/spdlog/details/os-inl.h create mode 100644 tpl/spdlog/include/spdlog/details/os.h create mode 100644 tpl/spdlog/include/spdlog/details/periodic_worker-inl.h create mode 100644 tpl/spdlog/include/spdlog/details/periodic_worker.h create mode 100644 tpl/spdlog/include/spdlog/details/registry-inl.h create mode 100644 tpl/spdlog/include/spdlog/details/registry.h create mode 100644 tpl/spdlog/include/spdlog/details/synchronous_factory.h create mode 100644 tpl/spdlog/include/spdlog/details/tcp_client-windows.h create mode 100644 tpl/spdlog/include/spdlog/details/tcp_client.h create mode 100644 tpl/spdlog/include/spdlog/details/thread_pool-inl.h create mode 100644 tpl/spdlog/include/spdlog/details/thread_pool.h create mode 100644 tpl/spdlog/include/spdlog/details/udp_client-windows.h create mode 100644 tpl/spdlog/include/spdlog/details/udp_client.h create mode 100644 tpl/spdlog/include/spdlog/details/windows_include.h create mode 100644 tpl/spdlog/include/spdlog/fmt/bin_to_hex.h create mode 100644 tpl/spdlog/include/spdlog/fmt/chrono.h create mode 100644 tpl/spdlog/include/spdlog/fmt/compile.h create mode 100644 tpl/spdlog/include/spdlog/fmt/fmt.h create mode 100644 tpl/spdlog/include/spdlog/fmt/ostr.h create mode 100644 tpl/spdlog/include/spdlog/fmt/ranges.h create mode 100644 tpl/spdlog/include/spdlog/fmt/std.h create mode 100644 tpl/spdlog/include/spdlog/fmt/xchar.h create mode 100644 tpl/spdlog/include/spdlog/formatter.h create mode 100644 tpl/spdlog/include/spdlog/fwd.h create mode 100644 tpl/spdlog/include/spdlog/logger-inl.h create mode 100644 tpl/spdlog/include/spdlog/logger.h create mode 100644 tpl/spdlog/include/spdlog/pattern_formatter-inl.h create mode 100644 tpl/spdlog/include/spdlog/pattern_formatter.h create mode 100644 tpl/spdlog/include/spdlog/sinks/android_sink.h create mode 100644 tpl/spdlog/include/spdlog/sinks/ansicolor_sink-inl.h create mode 100644 tpl/spdlog/include/spdlog/sinks/ansicolor_sink.h create mode 100644 tpl/spdlog/include/spdlog/sinks/base_sink-inl.h create mode 100644 tpl/spdlog/include/spdlog/sinks/base_sink.h create mode 100644 tpl/spdlog/include/spdlog/sinks/basic_file_sink-inl.h create mode 100644 tpl/spdlog/include/spdlog/sinks/basic_file_sink.h create mode 100644 tpl/spdlog/include/spdlog/sinks/callback_sink.h create mode 100644 tpl/spdlog/include/spdlog/sinks/daily_file_sink.h create mode 100644 tpl/spdlog/include/spdlog/sinks/dist_sink.h create mode 100644 tpl/spdlog/include/spdlog/sinks/dup_filter_sink.h create mode 100644 tpl/spdlog/include/spdlog/sinks/hourly_file_sink.h create mode 100644 tpl/spdlog/include/spdlog/sinks/kafka_sink.h create mode 100644 tpl/spdlog/include/spdlog/sinks/mongo_sink.h create mode 100644 tpl/spdlog/include/spdlog/sinks/msvc_sink.h create mode 100644 tpl/spdlog/include/spdlog/sinks/null_sink.h create mode 100644 tpl/spdlog/include/spdlog/sinks/ostream_sink.h create mode 100644 tpl/spdlog/include/spdlog/sinks/qt_sinks.h create mode 100644 tpl/spdlog/include/spdlog/sinks/ringbuffer_sink.h create mode 100644 tpl/spdlog/include/spdlog/sinks/rotating_file_sink-inl.h create mode 100644 tpl/spdlog/include/spdlog/sinks/rotating_file_sink.h create mode 100644 tpl/spdlog/include/spdlog/sinks/sink-inl.h create mode 100644 tpl/spdlog/include/spdlog/sinks/sink.h create mode 100644 tpl/spdlog/include/spdlog/sinks/stdout_color_sinks-inl.h create mode 100644 tpl/spdlog/include/spdlog/sinks/stdout_color_sinks.h create mode 100644 tpl/spdlog/include/spdlog/sinks/stdout_sinks-inl.h create mode 100644 tpl/spdlog/include/spdlog/sinks/stdout_sinks.h create mode 100644 tpl/spdlog/include/spdlog/sinks/syslog_sink.h create mode 100644 tpl/spdlog/include/spdlog/sinks/systemd_sink.h create mode 100644 tpl/spdlog/include/spdlog/sinks/tcp_sink.h create mode 100644 tpl/spdlog/include/spdlog/sinks/udp_sink.h create mode 100644 tpl/spdlog/include/spdlog/sinks/win_eventlog_sink.h create mode 100644 tpl/spdlog/include/spdlog/sinks/wincolor_sink-inl.h create mode 100644 tpl/spdlog/include/spdlog/sinks/wincolor_sink.h create mode 100644 tpl/spdlog/include/spdlog/spdlog-inl.h create mode 100644 tpl/spdlog/include/spdlog/spdlog.h create mode 100644 tpl/spdlog/include/spdlog/stopwatch.h create mode 100644 tpl/spdlog/include/spdlog/tweakme.h create mode 100644 tpl/spdlog/include/spdlog/version.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 0537c31..d497d00 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -57,6 +57,8 @@ target_include_directories(bvh INTERFACE $ ) +add_subdirectory(tpl) + # Various default compiler options target_compile_options(bvh PUBLIC $<$:-O0 -ggdb3 -fno-inline>) diff --git a/tpl/CMakeLists.txt b/tpl/CMakeLists.txt new file mode 100644 index 0000000..0fdf09c --- /dev/null +++ b/tpl/CMakeLists.txt @@ -0,0 +1 @@ +add_subdirectory(spdlog) diff --git a/tpl/spdlog/CMakeLists.txt b/tpl/spdlog/CMakeLists.txt new file mode 100644 index 0000000..8c1926d --- /dev/null +++ b/tpl/spdlog/CMakeLists.txt @@ -0,0 +1,10 @@ + +#find_package(fmt 10.0.0 REQUIRED) + +#target_link_libraries(bvh PUBLIC fmt::fmt) + +target_compile_definitions(bvh PUBLIC SPDLOG_FMT_EXTERNAL SPDLOG_ACTIVE_LEVEL=0) + +target_include_directories(bvh PUBLIC + $ + ) diff --git a/tpl/spdlog/include/spdlog/async.h b/tpl/spdlog/include/spdlog/async.h new file mode 100644 index 0000000..94f9f6d --- /dev/null +++ b/tpl/spdlog/include/spdlog/async.h @@ -0,0 +1,99 @@ +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) + +#pragma once + +// +// Async logging using global thread pool +// All loggers created here share same global thread pool. +// Each log message is pushed to a queue along with a shared pointer to the +// logger. +// If a logger deleted while having pending messages in the queue, it's actual +// destruction will defer +// until all its messages are processed by the thread pool. +// This is because each message in the queue holds a shared_ptr to the +// originating logger. + +#include +#include +#include + +#include +#include +#include + +namespace spdlog { + +namespace details { +static const size_t default_async_q_size = 8192; +} + +// async logger factory - creates async loggers backed with thread pool. +// if a global thread pool doesn't already exist, create it with default queue +// size of 8192 items and single thread. +template +struct async_factory_impl +{ + template + static std::shared_ptr create(std::string logger_name, SinkArgs &&...args) + { + auto ®istry_inst = details::registry::instance(); + + // create global thread pool if not already exists.. + + auto &mutex = registry_inst.tp_mutex(); + std::lock_guard tp_lock(mutex); + auto tp = registry_inst.get_tp(); + if (tp == nullptr) + { + tp = std::make_shared(details::default_async_q_size, 1U); + registry_inst.set_tp(tp); + } + + auto sink = std::make_shared(std::forward(args)...); + auto new_logger = std::make_shared(std::move(logger_name), std::move(sink), std::move(tp), OverflowPolicy); + registry_inst.initialize_logger(new_logger); + return new_logger; + } +}; + +using async_factory = async_factory_impl; +using async_factory_nonblock = async_factory_impl; + +template +inline std::shared_ptr create_async(std::string logger_name, SinkArgs &&...sink_args) +{ + return async_factory::create(std::move(logger_name), std::forward(sink_args)...); +} + +template +inline std::shared_ptr create_async_nb(std::string logger_name, SinkArgs &&...sink_args) +{ + return async_factory_nonblock::create(std::move(logger_name), std::forward(sink_args)...); +} + +// set global thread pool. +inline void init_thread_pool( + size_t q_size, size_t thread_count, std::function on_thread_start, std::function on_thread_stop) +{ + auto tp = std::make_shared(q_size, thread_count, on_thread_start, on_thread_stop); + details::registry::instance().set_tp(std::move(tp)); +} + +inline void init_thread_pool(size_t q_size, size_t thread_count, std::function on_thread_start) +{ + init_thread_pool(q_size, thread_count, on_thread_start, [] {}); +} + +inline void init_thread_pool(size_t q_size, size_t thread_count) +{ + init_thread_pool( + q_size, thread_count, [] {}, [] {}); +} + +// get the global thread pool. +inline std::shared_ptr thread_pool() +{ + return details::registry::instance().get_tp(); +} +} // namespace spdlog diff --git a/tpl/spdlog/include/spdlog/async_logger-inl.h b/tpl/spdlog/include/spdlog/async_logger-inl.h new file mode 100644 index 0000000..4de8382 --- /dev/null +++ b/tpl/spdlog/include/spdlog/async_logger-inl.h @@ -0,0 +1,90 @@ +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) + +#pragma once + +#ifndef SPDLOG_HEADER_ONLY +# include +#endif + +#include +#include + +#include +#include + +SPDLOG_INLINE spdlog::async_logger::async_logger( + std::string logger_name, sinks_init_list sinks_list, std::weak_ptr tp, async_overflow_policy overflow_policy) + : async_logger(std::move(logger_name), sinks_list.begin(), sinks_list.end(), std::move(tp), overflow_policy) +{} + +SPDLOG_INLINE spdlog::async_logger::async_logger( + std::string logger_name, sink_ptr single_sink, std::weak_ptr tp, async_overflow_policy overflow_policy) + : async_logger(std::move(logger_name), {std::move(single_sink)}, std::move(tp), overflow_policy) +{} + +// send the log message to the thread pool +SPDLOG_INLINE void spdlog::async_logger::sink_it_(const details::log_msg &msg){ + SPDLOG_TRY{if (auto pool_ptr = thread_pool_.lock()){pool_ptr->post_log(shared_from_this(), msg, overflow_policy_); +} +else +{ + throw_spdlog_ex("async log: thread pool doesn't exist anymore"); +} +} +SPDLOG_LOGGER_CATCH(msg.source) +} + +// send flush request to the thread pool +SPDLOG_INLINE void spdlog::async_logger::flush_(){ + SPDLOG_TRY{if (auto pool_ptr = thread_pool_.lock()){pool_ptr->post_flush(shared_from_this(), overflow_policy_); +} +else +{ + throw_spdlog_ex("async flush: thread pool doesn't exist anymore"); +} +} +SPDLOG_LOGGER_CATCH(source_loc()) +} + +// +// backend functions - called from the thread pool to do the actual job +// +SPDLOG_INLINE void spdlog::async_logger::backend_sink_it_(const details::log_msg &msg) +{ + for (auto &sink : sinks_) + { + if (sink->should_log(msg.level)) + { + SPDLOG_TRY + { + sink->log(msg); + } + SPDLOG_LOGGER_CATCH(msg.source) + } + } + + if (should_flush_(msg)) + { + backend_flush_(); + } +} + +SPDLOG_INLINE void spdlog::async_logger::backend_flush_() +{ + for (auto &sink : sinks_) + { + SPDLOG_TRY + { + sink->flush(); + } + SPDLOG_LOGGER_CATCH(source_loc()) + } +} + +SPDLOG_INLINE std::shared_ptr spdlog::async_logger::clone(std::string new_name) +{ + auto cloned = std::make_shared(*this); + cloned->name_ = std::move(new_name); + return cloned; +} diff --git a/tpl/spdlog/include/spdlog/async_logger.h b/tpl/spdlog/include/spdlog/async_logger.h new file mode 100644 index 0000000..91a93fc --- /dev/null +++ b/tpl/spdlog/include/spdlog/async_logger.h @@ -0,0 +1,68 @@ +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) + +#pragma once + +// Fast asynchronous logger. +// Uses pre allocated queue. +// Creates a single back thread to pop messages from the queue and log them. +// +// Upon each log write the logger: +// 1. Checks if its log level is enough to log the message +// 2. Push a new copy of the message to a queue (or block the caller until +// space is available in the queue) +// Upon destruction, logs all remaining messages in the queue before +// destructing.. + +#include + +namespace spdlog { + +// Async overflow policy - block by default. +enum class async_overflow_policy +{ + block, // Block until message can be enqueued + overrun_oldest // Discard oldest message in the queue if full when trying to + // add new item. +}; + +namespace details { +class thread_pool; +} + +class SPDLOG_API async_logger final : public std::enable_shared_from_this, public logger +{ + friend class details::thread_pool; + +public: + template + async_logger(std::string logger_name, It begin, It end, std::weak_ptr tp, + async_overflow_policy overflow_policy = async_overflow_policy::block) + : logger(std::move(logger_name), begin, end) + , thread_pool_(std::move(tp)) + , overflow_policy_(overflow_policy) + {} + + async_logger(std::string logger_name, sinks_init_list sinks_list, std::weak_ptr tp, + async_overflow_policy overflow_policy = async_overflow_policy::block); + + async_logger(std::string logger_name, sink_ptr single_sink, std::weak_ptr tp, + async_overflow_policy overflow_policy = async_overflow_policy::block); + + std::shared_ptr clone(std::string new_name) override; + +protected: + void sink_it_(const details::log_msg &msg) override; + void flush_() override; + void backend_sink_it_(const details::log_msg &incoming_log_msg); + void backend_flush_(); + +private: + std::weak_ptr thread_pool_; + async_overflow_policy overflow_policy_; +}; +} // namespace spdlog + +#ifdef SPDLOG_HEADER_ONLY +# include "async_logger-inl.h" +#endif diff --git a/tpl/spdlog/include/spdlog/cfg/argv.h b/tpl/spdlog/include/spdlog/cfg/argv.h new file mode 100644 index 0000000..36d9f1c --- /dev/null +++ b/tpl/spdlog/include/spdlog/cfg/argv.h @@ -0,0 +1,44 @@ +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) + +#pragma once +#include +#include + +// +// Init log levels using each argv entry that starts with "SPDLOG_LEVEL=" +// +// set all loggers to debug level: +// example.exe "SPDLOG_LEVEL=debug" + +// set logger1 to trace level +// example.exe "SPDLOG_LEVEL=logger1=trace" + +// turn off all logging except for logger1 and logger2: +// example.exe "SPDLOG_LEVEL=off,logger1=debug,logger2=info" + +namespace spdlog { +namespace cfg { + +// search for SPDLOG_LEVEL= in the args and use it to init the levels +inline void load_argv_levels(int argc, const char **argv) +{ + const std::string spdlog_level_prefix = "SPDLOG_LEVEL="; + for (int i = 1; i < argc; i++) + { + std::string arg = argv[i]; + if (arg.find(spdlog_level_prefix) == 0) + { + auto levels_string = arg.substr(spdlog_level_prefix.size()); + helpers::load_levels(levels_string); + } + } +} + +inline void load_argv_levels(int argc, char **argv) +{ + load_argv_levels(argc, const_cast(argv)); +} + +} // namespace cfg +} // namespace spdlog diff --git a/tpl/spdlog/include/spdlog/cfg/env.h b/tpl/spdlog/include/spdlog/cfg/env.h new file mode 100644 index 0000000..1f39ebb --- /dev/null +++ b/tpl/spdlog/include/spdlog/cfg/env.h @@ -0,0 +1,38 @@ +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) + +#pragma once +#include +#include +#include + +// +// Init levels and patterns from env variables SPDLOG_LEVEL +// Inspired from Rust's "env_logger" crate (https://crates.io/crates/env_logger). +// Note - fallback to "info" level on unrecognized levels +// +// Examples: +// +// set global level to debug: +// export SPDLOG_LEVEL=debug +// +// turn off all logging except for logger1: +// export SPDLOG_LEVEL="*=off,logger1=debug" +// + +// turn off all logging except for logger1 and logger2: +// export SPDLOG_LEVEL="off,logger1=debug,logger2=info" + +namespace spdlog { +namespace cfg { +inline void load_env_levels() +{ + auto env_val = details::os::getenv("SPDLOG_LEVEL"); + if (!env_val.empty()) + { + helpers::load_levels(env_val); + } +} + +} // namespace cfg +} // namespace spdlog diff --git a/tpl/spdlog/include/spdlog/cfg/helpers-inl.h b/tpl/spdlog/include/spdlog/cfg/helpers-inl.h new file mode 100644 index 0000000..675a13a --- /dev/null +++ b/tpl/spdlog/include/spdlog/cfg/helpers-inl.h @@ -0,0 +1,120 @@ +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) + +#pragma once + +#ifndef SPDLOG_HEADER_ONLY +# include +#endif + +#include +#include +#include + +#include +#include +#include +#include + +namespace spdlog { +namespace cfg { +namespace helpers { + +// inplace convert to lowercase +inline std::string &to_lower_(std::string &str) +{ + std::transform( + str.begin(), str.end(), str.begin(), [](char ch) { return static_cast((ch >= 'A' && ch <= 'Z') ? ch + ('a' - 'A') : ch); }); + return str; +} + +// inplace trim spaces +inline std::string &trim_(std::string &str) +{ + const char *spaces = " \n\r\t"; + str.erase(str.find_last_not_of(spaces) + 1); + str.erase(0, str.find_first_not_of(spaces)); + return str; +} + +// return (name,value) trimmed pair from given "name=value" string. +// return empty string on missing parts +// "key=val" => ("key", "val") +// " key = val " => ("key", "val") +// "key=" => ("key", "") +// "val" => ("", "val") + +inline std::pair extract_kv_(char sep, const std::string &str) +{ + auto n = str.find(sep); + std::string k, v; + if (n == std::string::npos) + { + v = str; + } + else + { + k = str.substr(0, n); + v = str.substr(n + 1); + } + return std::make_pair(trim_(k), trim_(v)); +} + +// return vector of key/value pairs from sequence of "K1=V1,K2=V2,.." +// "a=AAA,b=BBB,c=CCC,.." => {("a","AAA"),("b","BBB"),("c", "CCC"),...} +inline std::unordered_map extract_key_vals_(const std::string &str) +{ + std::string token; + std::istringstream token_stream(str); + std::unordered_map rv{}; + while (std::getline(token_stream, token, ',')) + { + if (token.empty()) + { + continue; + } + auto kv = extract_kv_('=', token); + rv[kv.first] = kv.second; + } + return rv; +} + +SPDLOG_INLINE void load_levels(const std::string &input) +{ + if (input.empty() || input.size() > 512) + { + return; + } + + auto key_vals = extract_key_vals_(input); + std::unordered_map levels; + level::level_enum global_level = level::info; + bool global_level_found = false; + + for (auto &name_level : key_vals) + { + auto &logger_name = name_level.first; + auto level_name = to_lower_(name_level.second); + auto level = level::from_str(level_name); + // ignore unrecognized level names + if (level == level::off && level_name != "off") + { + continue; + } + if (logger_name.empty()) // no logger name indicate global level + { + global_level_found = true; + global_level = level; + } + else + { + levels[logger_name] = level; + } + } + + details::registry::instance().set_levels(std::move(levels), global_level_found ? &global_level : nullptr); +} + +} // namespace helpers +} // namespace cfg +} // namespace spdlog diff --git a/tpl/spdlog/include/spdlog/cfg/helpers.h b/tpl/spdlog/include/spdlog/cfg/helpers.h new file mode 100644 index 0000000..ab7584e --- /dev/null +++ b/tpl/spdlog/include/spdlog/cfg/helpers.h @@ -0,0 +1,29 @@ +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) + +#pragma once + +#include +#include + +namespace spdlog { +namespace cfg { +namespace helpers { +// +// Init levels from given string +// +// Examples: +// +// set global level to debug: "debug" +// turn off all logging except for logger1: "off,logger1=debug" +// turn off all logging except for logger1 and logger2: "off,logger1=debug,logger2=info" +// +SPDLOG_API void load_levels(const std::string &txt); +} // namespace helpers + +} // namespace cfg +} // namespace spdlog + +#ifdef SPDLOG_HEADER_ONLY +# include "helpers-inl.h" +#endif // SPDLOG_HEADER_ONLY diff --git a/tpl/spdlog/include/spdlog/common-inl.h b/tpl/spdlog/include/spdlog/common-inl.h new file mode 100644 index 0000000..728f983 --- /dev/null +++ b/tpl/spdlog/include/spdlog/common-inl.h @@ -0,0 +1,82 @@ +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) + +#pragma once + +#ifndef SPDLOG_HEADER_ONLY +# include +#endif + +#include +#include + +namespace spdlog { +namespace level { + +#if __cplusplus >= 201703L +constexpr +#endif + static string_view_t level_string_views[] SPDLOG_LEVEL_NAMES; + +static const char *short_level_names[] SPDLOG_SHORT_LEVEL_NAMES; + +SPDLOG_INLINE const string_view_t &to_string_view(spdlog::level::level_enum l) SPDLOG_NOEXCEPT +{ + return level_string_views[l]; +} + +SPDLOG_INLINE const char *to_short_c_str(spdlog::level::level_enum l) SPDLOG_NOEXCEPT +{ + return short_level_names[l]; +} + +SPDLOG_INLINE spdlog::level::level_enum from_str(const std::string &name) SPDLOG_NOEXCEPT +{ + auto it = std::find(std::begin(level_string_views), std::end(level_string_views), name); + if (it != std::end(level_string_views)) + return static_cast(std::distance(std::begin(level_string_views), it)); + + // check also for "warn" and "err" before giving up.. + if (name == "warn") + { + return level::warn; + } + if (name == "err") + { + return level::err; + } + return level::off; +} +} // namespace level + +SPDLOG_INLINE spdlog_ex::spdlog_ex(std::string msg) + : msg_(std::move(msg)) +{} + +SPDLOG_INLINE spdlog_ex::spdlog_ex(const std::string &msg, int last_errno) +{ +#ifdef SPDLOG_USE_STD_FORMAT + msg_ = std::system_error(std::error_code(last_errno, std::generic_category()), msg).what(); +#else + memory_buf_t outbuf; + fmt::format_system_error(outbuf, last_errno, msg.c_str()); + msg_ = fmt::to_string(outbuf); +#endif +} + +SPDLOG_INLINE const char *spdlog_ex::what() const SPDLOG_NOEXCEPT +{ + return msg_.c_str(); +} + +SPDLOG_INLINE void throw_spdlog_ex(const std::string &msg, int last_errno) +{ + SPDLOG_THROW(spdlog_ex(msg, last_errno)); +} + +SPDLOG_INLINE void throw_spdlog_ex(std::string msg) +{ + SPDLOG_THROW(spdlog_ex(std::move(msg))); +} + +} // namespace spdlog diff --git a/tpl/spdlog/include/spdlog/common.h b/tpl/spdlog/include/spdlog/common.h new file mode 100644 index 0000000..2f1f9fd --- /dev/null +++ b/tpl/spdlog/include/spdlog/common.h @@ -0,0 +1,426 @@ +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) + +#pragma once + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef SPDLOG_USE_STD_FORMAT +# include +# if __cpp_lib_format >= 202207L +# include +# else +# include +# endif +#endif + +#ifdef SPDLOG_COMPILED_LIB +# undef SPDLOG_HEADER_ONLY +# if defined(SPDLOG_SHARED_LIB) +# if defined(_WIN32) +# ifdef spdlog_EXPORTS +# define SPDLOG_API __declspec(dllexport) +# else // !spdlog_EXPORTS +# define SPDLOG_API __declspec(dllimport) +# endif +# else // !defined(_WIN32) +# define SPDLOG_API __attribute__((visibility("default"))) +# endif +# else // !defined(SPDLOG_SHARED_LIB) +# define SPDLOG_API +# endif +# define SPDLOG_INLINE +#else // !defined(SPDLOG_COMPILED_LIB) +# define SPDLOG_API +# define SPDLOG_HEADER_ONLY +# define SPDLOG_INLINE inline +#endif // #ifdef SPDLOG_COMPILED_LIB + +#include + +#if !defined(SPDLOG_USE_STD_FORMAT) && FMT_VERSION >= 80000 // backward compatibility with fmt versions older than 8 +# define SPDLOG_FMT_RUNTIME(format_string) fmt::runtime(format_string) +# define SPDLOG_FMT_STRING(format_string) FMT_STRING(format_string) +# if defined(SPDLOG_WCHAR_FILENAMES) || defined(SPDLOG_WCHAR_TO_UTF8_SUPPORT) +# include +# endif +#else +# define SPDLOG_FMT_RUNTIME(format_string) format_string +# define SPDLOG_FMT_STRING(format_string) format_string +#endif + +// visual studio up to 2013 does not support noexcept nor constexpr +#if defined(_MSC_VER) && (_MSC_VER < 1900) +# define SPDLOG_NOEXCEPT _NOEXCEPT +# define SPDLOG_CONSTEXPR +# define SPDLOG_CONSTEXPR_FUNC inline +#else +# define SPDLOG_NOEXCEPT noexcept +# define SPDLOG_CONSTEXPR constexpr +#if __cplusplus >= 201402L && FMT_VERSION >= 80000 +# define SPDLOG_CONSTEXPR_FUNC constexpr +# else +# define SPDLOG_CONSTEXPR_FUNC inline +# endif +#endif + +#if defined(__GNUC__) || defined(__clang__) +# define SPDLOG_DEPRECATED __attribute__((deprecated)) +#elif defined(_MSC_VER) +# define SPDLOG_DEPRECATED __declspec(deprecated) +#else +# define SPDLOG_DEPRECATED +#endif + +// disable thread local on msvc 2013 +#ifndef SPDLOG_NO_TLS +# if (defined(_MSC_VER) && (_MSC_VER < 1900)) || defined(__cplusplus_winrt) +# define SPDLOG_NO_TLS 1 +# endif +#endif + +#ifndef SPDLOG_FUNCTION +# define SPDLOG_FUNCTION static_cast(__FUNCTION__) +#endif + +#ifdef SPDLOG_NO_EXCEPTIONS +# define SPDLOG_TRY +# define SPDLOG_THROW(ex) \ + do \ + { \ + printf("spdlog fatal error: %s\n", ex.what()); \ + std::abort(); \ + } while (0) +# define SPDLOG_CATCH_STD +#else +# define SPDLOG_TRY try +# define SPDLOG_THROW(ex) throw(ex) +# define SPDLOG_CATCH_STD \ + catch (const std::exception &) \ + {} +#endif + +namespace spdlog { + +class formatter; + +namespace sinks { +class sink; +} + +#if defined(_WIN32) && defined(SPDLOG_WCHAR_FILENAMES) +using filename_t = std::wstring; +// allow macro expansion to occur in SPDLOG_FILENAME_T +# define SPDLOG_FILENAME_T_INNER(s) L##s +# define SPDLOG_FILENAME_T(s) SPDLOG_FILENAME_T_INNER(s) +#else +using filename_t = std::string; +# define SPDLOG_FILENAME_T(s) s +#endif + +using log_clock = std::chrono::system_clock; +using sink_ptr = std::shared_ptr; +using sinks_init_list = std::initializer_list; +using err_handler = std::function; +#ifdef SPDLOG_USE_STD_FORMAT +namespace fmt_lib = std; + +using string_view_t = std::string_view; +using memory_buf_t = std::string; + +template +# if __cpp_lib_format >= 202207L +using format_string_t = std::format_string; +# else +using format_string_t = std::string_view; +# endif + +template +struct is_convertible_to_basic_format_string : std::integral_constant>::value> +{}; + +# if defined(SPDLOG_WCHAR_FILENAMES) || defined(SPDLOG_WCHAR_TO_UTF8_SUPPORT) +using wstring_view_t = std::wstring_view; +using wmemory_buf_t = std::wstring; + +template +# if __cpp_lib_format >= 202207L +using wformat_string_t = std::wformat_string; +# else +using wformat_string_t = std::wstring_view; +# endif +# endif +# define SPDLOG_BUF_TO_STRING(x) x +#else // use fmt lib instead of std::format +namespace fmt_lib = fmt; + +using string_view_t = fmt::basic_string_view; +using memory_buf_t = fmt::basic_memory_buffer; + +template< typename... Args > +#if FMT_VERSION >= 90101 +using format_string_t = fmt::format_string< Args... >; +#else +using format_string_t = std::string_view; +#endif + +template +using remove_cvref_t = typename std::remove_cv::type>::type; + +template +# if FMT_VERSION >= 90101 +using fmt_runtime_string = fmt::runtime_format_string; +# elif FMT_VERSION >= 80000 +using fmt_runtime_string = fmt::basic_runtime; +#else +using fmt_runtime_string = std::basic_string_view; +# endif + +// clang doesn't like SFINAE disabled constructor in std::is_convertible<> so have to repeat the condition from basic_format_string here, +// in addition, fmt::basic_runtime is only convertible to basic_format_string but not basic_string_view +template +struct is_convertible_to_basic_format_string + : std::integral_constant>::value || std::is_same, fmt_runtime_string>::value> +{}; + +# if defined(SPDLOG_WCHAR_FILENAMES) || defined(SPDLOG_WCHAR_TO_UTF8_SUPPORT) +using wstring_view_t = fmt::basic_string_view; +using wmemory_buf_t = fmt::basic_memory_buffer; + +template +using wformat_string_t = fmt::wformat_string; +# endif +# define SPDLOG_BUF_TO_STRING(x) fmt::to_string(x) +#endif + +#ifdef SPDLOG_WCHAR_TO_UTF8_SUPPORT +# ifndef _WIN32 +# error SPDLOG_WCHAR_TO_UTF8_SUPPORT only supported on windows +# endif // _WIN32 +#endif // SPDLOG_WCHAR_TO_UTF8_SUPPORT + +template +struct is_convertible_to_any_format_string : std::integral_constant::value || + is_convertible_to_basic_format_string::value> +{}; + +#if defined(SPDLOG_NO_ATOMIC_LEVELS) +using level_t = details::null_atomic_int; +#else +using level_t = std::atomic; +#endif + +#define SPDLOG_LEVEL_TRACE 0 +#define SPDLOG_LEVEL_DEBUG 1 +#define SPDLOG_LEVEL_INFO 2 +#define SPDLOG_LEVEL_WARN 3 +#define SPDLOG_LEVEL_ERROR 4 +#define SPDLOG_LEVEL_CRITICAL 5 +#define SPDLOG_LEVEL_OFF 6 + +#if !defined(SPDLOG_ACTIVE_LEVEL) +# define SPDLOG_ACTIVE_LEVEL SPDLOG_LEVEL_INFO +#endif + +// Log level enum +namespace level { +enum level_enum : int +{ + trace = SPDLOG_LEVEL_TRACE, + debug = SPDLOG_LEVEL_DEBUG, + info = SPDLOG_LEVEL_INFO, + warn = SPDLOG_LEVEL_WARN, + err = SPDLOG_LEVEL_ERROR, + critical = SPDLOG_LEVEL_CRITICAL, + off = SPDLOG_LEVEL_OFF, + n_levels +}; + +#define SPDLOG_LEVEL_NAME_TRACE spdlog::string_view_t("trace", 5) +#define SPDLOG_LEVEL_NAME_DEBUG spdlog::string_view_t("debug", 5) +#define SPDLOG_LEVEL_NAME_INFO spdlog::string_view_t("info", 4) +#define SPDLOG_LEVEL_NAME_WARNING spdlog::string_view_t("warning", 7) +#define SPDLOG_LEVEL_NAME_ERROR spdlog::string_view_t("error", 5) +#define SPDLOG_LEVEL_NAME_CRITICAL spdlog::string_view_t("critical", 8) +#define SPDLOG_LEVEL_NAME_OFF spdlog::string_view_t("off", 3) + +#if !defined(SPDLOG_LEVEL_NAMES) +# define SPDLOG_LEVEL_NAMES \ + { \ + SPDLOG_LEVEL_NAME_TRACE, SPDLOG_LEVEL_NAME_DEBUG, SPDLOG_LEVEL_NAME_INFO, SPDLOG_LEVEL_NAME_WARNING, SPDLOG_LEVEL_NAME_ERROR, \ + SPDLOG_LEVEL_NAME_CRITICAL, SPDLOG_LEVEL_NAME_OFF \ + } +#endif + +#if !defined(SPDLOG_SHORT_LEVEL_NAMES) + +# define SPDLOG_SHORT_LEVEL_NAMES \ + { \ + "T", "D", "I", "W", "E", "C", "O" \ + } +#endif + +SPDLOG_API const string_view_t &to_string_view(spdlog::level::level_enum l) SPDLOG_NOEXCEPT; +SPDLOG_API const char *to_short_c_str(spdlog::level::level_enum l) SPDLOG_NOEXCEPT; +SPDLOG_API spdlog::level::level_enum from_str(const std::string &name) SPDLOG_NOEXCEPT; + +} // namespace level + +// +// Color mode used by sinks with color support. +// +enum class color_mode +{ + always, + automatic, + never +}; + +// +// Pattern time - specific time getting to use for pattern_formatter. +// local time by default +// +enum class pattern_time_type +{ + local, // log localtime + utc // log utc +}; + +// +// Log exception +// +class SPDLOG_API spdlog_ex : public std::exception +{ +public: + explicit spdlog_ex(std::string msg); + spdlog_ex(const std::string &msg, int last_errno); + const char *what() const SPDLOG_NOEXCEPT override; + +private: + std::string msg_; +}; + +[[noreturn]] SPDLOG_API void throw_spdlog_ex(const std::string &msg, int last_errno); +[[noreturn]] SPDLOG_API void throw_spdlog_ex(std::string msg); + +struct source_loc +{ + SPDLOG_CONSTEXPR source_loc() = default; + SPDLOG_CONSTEXPR source_loc(const char *filename_in, int line_in, const char *funcname_in) + : filename{filename_in} + , line{line_in} + , funcname{funcname_in} + {} + + SPDLOG_CONSTEXPR bool empty() const SPDLOG_NOEXCEPT + { + return line == 0; + } + const char *filename{nullptr}; + int line{0}; + const char *funcname{nullptr}; +}; + +struct file_event_handlers +{ + file_event_handlers() + : before_open(nullptr) + , after_open(nullptr) + , before_close(nullptr) + , after_close(nullptr) + {} + + std::function before_open; + std::function after_open; + std::function before_close; + std::function after_close; +}; + +namespace details { + +// to_string_view + +SPDLOG_CONSTEXPR_FUNC spdlog::string_view_t to_string_view(const memory_buf_t &buf) SPDLOG_NOEXCEPT +{ + return spdlog::string_view_t{buf.data(), buf.size()}; +} + +SPDLOG_CONSTEXPR_FUNC spdlog::string_view_t to_string_view(spdlog::string_view_t str) SPDLOG_NOEXCEPT +{ + return str; +} + +#if defined(SPDLOG_WCHAR_FILENAMES) || defined(SPDLOG_WCHAR_TO_UTF8_SUPPORT) +SPDLOG_CONSTEXPR_FUNC spdlog::wstring_view_t to_string_view(const wmemory_buf_t &buf) SPDLOG_NOEXCEPT +{ + return spdlog::wstring_view_t{buf.data(), buf.size()}; +} + +SPDLOG_CONSTEXPR_FUNC spdlog::wstring_view_t to_string_view(spdlog::wstring_view_t str) SPDLOG_NOEXCEPT +{ + return str; +} +#endif + +#if !defined( SPDLOG_USE_STD_FORMAT ) && FMT_VERSION >= 80000 +template +inline fmt::basic_string_view to_string_view(fmt::basic_format_string fmt) +{ + return fmt; +} +#elif __cpp_lib_format >= 202207L +template +SPDLOG_CONSTEXPR_FUNC std::basic_string_view to_string_view(std::basic_format_string fmt) SPDLOG_NOEXCEPT +{ + return fmt.get(); +} +#endif + +// make_unique support for pre c++14 + +#if __cplusplus >= 201402L // C++14 and beyond +using std::enable_if_t; +using std::make_unique; +#else +template +using enable_if_t = typename std::enable_if::type; + +template +std::unique_ptr make_unique(Args &&...args) +{ + static_assert(!std::is_array::value, "arrays not supported"); + return std::unique_ptr(new T(std::forward(args)...)); +} +#endif + +// to avoid useless casts (see https://github.com/nlohmann/json/issues/2893#issuecomment-889152324) +template::value, int> = 0> +constexpr T conditional_static_cast(U value) +{ + return static_cast(value); +} + +template::value, int> = 0> +constexpr T conditional_static_cast(U value) +{ + return value; +} + +} // namespace details +} // namespace spdlog + +#ifdef SPDLOG_HEADER_ONLY +# include "common-inl.h" +#endif diff --git a/tpl/spdlog/include/spdlog/details/backtracer-inl.h b/tpl/spdlog/include/spdlog/details/backtracer-inl.h new file mode 100644 index 0000000..40eba40 --- /dev/null +++ b/tpl/spdlog/include/spdlog/details/backtracer-inl.h @@ -0,0 +1,75 @@ +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) + +#pragma once + +#ifndef SPDLOG_HEADER_ONLY +# include +#endif +namespace spdlog { +namespace details { +SPDLOG_INLINE backtracer::backtracer(const backtracer &other) +{ + std::lock_guard lock(other.mutex_); + enabled_ = other.enabled(); + messages_ = other.messages_; +} + +SPDLOG_INLINE backtracer::backtracer(backtracer &&other) SPDLOG_NOEXCEPT +{ + std::lock_guard lock(other.mutex_); + enabled_ = other.enabled(); + messages_ = std::move(other.messages_); +} + +SPDLOG_INLINE backtracer &backtracer::operator=(backtracer other) +{ + std::lock_guard lock(mutex_); + enabled_ = other.enabled(); + messages_ = std::move(other.messages_); + return *this; +} + +SPDLOG_INLINE void backtracer::enable(size_t size) +{ + std::lock_guard lock{mutex_}; + enabled_.store(true, std::memory_order_relaxed); + messages_ = circular_q{size}; +} + +SPDLOG_INLINE void backtracer::disable() +{ + std::lock_guard lock{mutex_}; + enabled_.store(false, std::memory_order_relaxed); +} + +SPDLOG_INLINE bool backtracer::enabled() const +{ + return enabled_.load(std::memory_order_relaxed); +} + +SPDLOG_INLINE void backtracer::push_back(const log_msg &msg) +{ + std::lock_guard lock{mutex_}; + messages_.push_back(log_msg_buffer{msg}); +} + +SPDLOG_INLINE bool backtracer::empty() const +{ + std::lock_guard lock{mutex_}; + return messages_.empty(); +} + +// pop all items in the q and apply the given fun on each of them. +SPDLOG_INLINE void backtracer::foreach_pop(std::function fun) +{ + std::lock_guard lock{mutex_}; + while (!messages_.empty()) + { + auto &front_msg = messages_.front(); + fun(front_msg); + messages_.pop_front(); + } +} +} // namespace details +} // namespace spdlog diff --git a/tpl/spdlog/include/spdlog/details/backtracer.h b/tpl/spdlog/include/spdlog/details/backtracer.h new file mode 100644 index 0000000..13785d8 --- /dev/null +++ b/tpl/spdlog/include/spdlog/details/backtracer.h @@ -0,0 +1,46 @@ +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) + +#pragma once + +#include +#include + +#include +#include +#include + +// Store log messages in circular buffer. +// Useful for storing debug data in case of error/warning happens. + +namespace spdlog { +namespace details { +class SPDLOG_API backtracer +{ + mutable std::mutex mutex_; + std::atomic enabled_{false}; + circular_q messages_; + +public: + backtracer() = default; + backtracer(const backtracer &other); + + backtracer(backtracer &&other) SPDLOG_NOEXCEPT; + backtracer &operator=(backtracer other); + + void enable(size_t size); + void disable(); + bool enabled() const; + void push_back(const log_msg &msg); + bool empty() const; + + // pop all items in the q and apply the given fun on each of them. + void foreach_pop(std::function fun); +}; + +} // namespace details +} // namespace spdlog + +#ifdef SPDLOG_HEADER_ONLY +# include "backtracer-inl.h" +#endif diff --git a/tpl/spdlog/include/spdlog/details/circular_q.h b/tpl/spdlog/include/spdlog/details/circular_q.h new file mode 100644 index 0000000..e4fd5fd --- /dev/null +++ b/tpl/spdlog/include/spdlog/details/circular_q.h @@ -0,0 +1,146 @@ +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) + +// circular q view of std::vector. +#pragma once + +#include +#include + +namespace spdlog { +namespace details { +template +class circular_q +{ + size_t max_items_ = 0; + typename std::vector::size_type head_ = 0; + typename std::vector::size_type tail_ = 0; + size_t overrun_counter_ = 0; + std::vector v_; + +public: + using value_type = T; + + // empty ctor - create a disabled queue with no elements allocated at all + circular_q() = default; + + explicit circular_q(size_t max_items) + : max_items_(max_items + 1) // one item is reserved as marker for full q + , v_(max_items_) + {} + + circular_q(const circular_q &) = default; + circular_q &operator=(const circular_q &) = default; + + // move cannot be default, + // since we need to reset head_, tail_, etc to zero in the moved object + circular_q(circular_q &&other) SPDLOG_NOEXCEPT + { + copy_moveable(std::move(other)); + } + + circular_q &operator=(circular_q &&other) SPDLOG_NOEXCEPT + { + copy_moveable(std::move(other)); + return *this; + } + + // push back, overrun (oldest) item if no room left + void push_back(T &&item) + { + if (max_items_ > 0) + { + v_[tail_] = std::move(item); + tail_ = (tail_ + 1) % max_items_; + + if (tail_ == head_) // overrun last item if full + { + head_ = (head_ + 1) % max_items_; + ++overrun_counter_; + } + } + } + + // Return reference to the front item. + // If there are no elements in the container, the behavior is undefined. + const T &front() const + { + return v_[head_]; + } + + T &front() + { + return v_[head_]; + } + + // Return number of elements actually stored + size_t size() const + { + if (tail_ >= head_) + { + return tail_ - head_; + } + else + { + return max_items_ - (head_ - tail_); + } + } + + // Return const reference to item by index. + // If index is out of range 0…size()-1, the behavior is undefined. + const T &at(size_t i) const + { + assert(i < size()); + return v_[(head_ + i) % max_items_]; + } + + // Pop item from front. + // If there are no elements in the container, the behavior is undefined. + void pop_front() + { + head_ = (head_ + 1) % max_items_; + } + + bool empty() const + { + return tail_ == head_; + } + + bool full() const + { + // head is ahead of the tail by 1 + if (max_items_ > 0) + { + return ((tail_ + 1) % max_items_) == head_; + } + return false; + } + + size_t overrun_counter() const + { + return overrun_counter_; + } + + void reset_overrun_counter() + { + overrun_counter_ = 0; + } + +private: + // copy from other&& and reset it to disabled state + void copy_moveable(circular_q &&other) SPDLOG_NOEXCEPT + { + max_items_ = other.max_items_; + head_ = other.head_; + tail_ = other.tail_; + overrun_counter_ = other.overrun_counter_; + v_ = std::move(other.v_); + + // put &&other in disabled, but valid state + other.max_items_ = 0; + other.head_ = other.tail_ = 0; + other.overrun_counter_ = 0; + } +}; +} // namespace details +} // namespace spdlog diff --git a/tpl/spdlog/include/spdlog/details/console_globals.h b/tpl/spdlog/include/spdlog/details/console_globals.h new file mode 100644 index 0000000..665201d --- /dev/null +++ b/tpl/spdlog/include/spdlog/details/console_globals.h @@ -0,0 +1,32 @@ +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) + +#pragma once + +#include +#include + +namespace spdlog { +namespace details { + +struct console_mutex +{ + using mutex_t = std::mutex; + static mutex_t &mutex() + { + static mutex_t s_mutex; + return s_mutex; + } +}; + +struct console_nullmutex +{ + using mutex_t = null_mutex; + static mutex_t &mutex() + { + static mutex_t s_mutex; + return s_mutex; + } +}; +} // namespace details +} // namespace spdlog diff --git a/tpl/spdlog/include/spdlog/details/file_helper-inl.h b/tpl/spdlog/include/spdlog/details/file_helper-inl.h new file mode 100644 index 0000000..74c89a8 --- /dev/null +++ b/tpl/spdlog/include/spdlog/details/file_helper-inl.h @@ -0,0 +1,180 @@ +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) + +#pragma once + +#ifndef SPDLOG_HEADER_ONLY +# include +#endif + +#include +#include + +#include +#include +#include +#include +#include +#include + +namespace spdlog { +namespace details { + +SPDLOG_INLINE file_helper::file_helper(const file_event_handlers &event_handlers) + : event_handlers_(event_handlers) +{} + +SPDLOG_INLINE file_helper::~file_helper() +{ + close(); +} + +SPDLOG_INLINE void file_helper::open(const filename_t &fname, bool truncate) +{ + close(); + filename_ = fname; + + auto *mode = SPDLOG_FILENAME_T("ab"); + auto *trunc_mode = SPDLOG_FILENAME_T("wb"); + + if (event_handlers_.before_open) + { + event_handlers_.before_open(filename_); + } + for (int tries = 0; tries < open_tries_; ++tries) + { + // create containing folder if not exists already. + os::create_dir(os::dir_name(fname)); + if (truncate) + { + // Truncate by opening-and-closing a tmp file in "wb" mode, always + // opening the actual log-we-write-to in "ab" mode, since that + // interacts more politely with eternal processes that might + // rotate/truncate the file underneath us. + std::FILE *tmp; + if (os::fopen_s(&tmp, fname, trunc_mode)) + { + continue; + } + std::fclose(tmp); + } + if (!os::fopen_s(&fd_, fname, mode)) + { + if (event_handlers_.after_open) + { + event_handlers_.after_open(filename_, fd_); + } + return; + } + + details::os::sleep_for_millis(open_interval_); + } + + throw_spdlog_ex("Failed opening file " + os::filename_to_str(filename_) + " for writing", errno); +} + +SPDLOG_INLINE void file_helper::reopen(bool truncate) +{ + if (filename_.empty()) + { + throw_spdlog_ex("Failed re opening file - was not opened before"); + } + this->open(filename_, truncate); +} + +SPDLOG_INLINE void file_helper::flush() +{ + if (std::fflush(fd_) != 0) + { + throw_spdlog_ex("Failed flush to file " + os::filename_to_str(filename_), errno); + } +} + +SPDLOG_INLINE void file_helper::sync() +{ + if (!os::fsync(fd_)) + { + throw_spdlog_ex("Failed to fsync file " + os::filename_to_str(filename_), errno); + } +} + +SPDLOG_INLINE void file_helper::close() +{ + if (fd_ != nullptr) + { + if (event_handlers_.before_close) + { + event_handlers_.before_close(filename_, fd_); + } + + std::fclose(fd_); + fd_ = nullptr; + + if (event_handlers_.after_close) + { + event_handlers_.after_close(filename_); + } + } +} + +SPDLOG_INLINE void file_helper::write(const memory_buf_t &buf) +{ + size_t msg_size = buf.size(); + auto data = buf.data(); + if (std::fwrite(data, 1, msg_size, fd_) != msg_size) + { + throw_spdlog_ex("Failed writing to file " + os::filename_to_str(filename_), errno); + } +} + +SPDLOG_INLINE size_t file_helper::size() const +{ + if (fd_ == nullptr) + { + throw_spdlog_ex("Cannot use size() on closed file " + os::filename_to_str(filename_)); + } + return os::filesize(fd_); +} + +SPDLOG_INLINE const filename_t &file_helper::filename() const +{ + return filename_; +} + +// +// return file path and its extension: +// +// "mylog.txt" => ("mylog", ".txt") +// "mylog" => ("mylog", "") +// "mylog." => ("mylog.", "") +// "/dir1/dir2/mylog.txt" => ("/dir1/dir2/mylog", ".txt") +// +// the starting dot in filenames is ignored (hidden files): +// +// ".mylog" => (".mylog". "") +// "my_folder/.mylog" => ("my_folder/.mylog", "") +// "my_folder/.mylog.txt" => ("my_folder/.mylog", ".txt") +SPDLOG_INLINE std::tuple file_helper::split_by_extension(const filename_t &fname) +{ + auto ext_index = fname.rfind('.'); + + // no valid extension found - return whole path and empty string as + // extension + if (ext_index == filename_t::npos || ext_index == 0 || ext_index == fname.size() - 1) + { + return std::make_tuple(fname, filename_t()); + } + + // treat cases like "/etc/rc.d/somelogfile or "/abc/.hiddenfile" + auto folder_index = fname.find_last_of(details::os::folder_seps_filename); + if (folder_index != filename_t::npos && folder_index >= ext_index - 1) + { + return std::make_tuple(fname, filename_t()); + } + + // finally - return a valid base and extension tuple + return std::make_tuple(fname.substr(0, ext_index), fname.substr(ext_index)); +} + +} // namespace details +} // namespace spdlog diff --git a/tpl/spdlog/include/spdlog/details/file_helper.h b/tpl/spdlog/include/spdlog/details/file_helper.h new file mode 100644 index 0000000..f42a5eb --- /dev/null +++ b/tpl/spdlog/include/spdlog/details/file_helper.h @@ -0,0 +1,62 @@ +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) + +#pragma once + +#include +#include + +namespace spdlog { +namespace details { + +// Helper class for file sinks. +// When failing to open a file, retry several times(5) with a delay interval(10 ms). +// Throw spdlog_ex exception on errors. + +class SPDLOG_API file_helper +{ +public: + file_helper() = default; + explicit file_helper(const file_event_handlers &event_handlers); + + file_helper(const file_helper &) = delete; + file_helper &operator=(const file_helper &) = delete; + ~file_helper(); + + void open(const filename_t &fname, bool truncate = false); + void reopen(bool truncate); + void flush(); + void sync(); + void close(); + void write(const memory_buf_t &buf); + size_t size() const; + const filename_t &filename() const; + + // + // return file path and its extension: + // + // "mylog.txt" => ("mylog", ".txt") + // "mylog" => ("mylog", "") + // "mylog." => ("mylog.", "") + // "/dir1/dir2/mylog.txt" => ("/dir1/dir2/mylog", ".txt") + // + // the starting dot in filenames is ignored (hidden files): + // + // ".mylog" => (".mylog". "") + // "my_folder/.mylog" => ("my_folder/.mylog", "") + // "my_folder/.mylog.txt" => ("my_folder/.mylog", ".txt") + static std::tuple split_by_extension(const filename_t &fname); + +private: + const int open_tries_ = 5; + const unsigned int open_interval_ = 10; + std::FILE *fd_{nullptr}; + filename_t filename_; + file_event_handlers event_handlers_; +}; +} // namespace details +} // namespace spdlog + +#ifdef SPDLOG_HEADER_ONLY +# include "file_helper-inl.h" +#endif diff --git a/tpl/spdlog/include/spdlog/details/fmt_helper.h b/tpl/spdlog/include/spdlog/details/fmt_helper.h new file mode 100644 index 0000000..d986718 --- /dev/null +++ b/tpl/spdlog/include/spdlog/details/fmt_helper.h @@ -0,0 +1,164 @@ +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) +#pragma once + +#include +#include +#include +#include +#include + +#ifdef SPDLOG_USE_STD_FORMAT +# include +# include +#endif + +// Some fmt helpers to efficiently format and pad ints and strings +namespace spdlog { +namespace details { +namespace fmt_helper { + +inline void append_string_view(spdlog::string_view_t view, memory_buf_t &dest) +{ + auto *buf_ptr = view.data(); + dest.append(buf_ptr, buf_ptr + view.size()); +} + +#ifdef SPDLOG_USE_STD_FORMAT +template +inline void append_int(T n, memory_buf_t &dest) +{ + // Buffer should be large enough to hold all digits (digits10 + 1) and a sign + SPDLOG_CONSTEXPR const auto BUF_SIZE = std::numeric_limits::digits10 + 2; + char buf[BUF_SIZE]; + + auto [ptr, ec] = std::to_chars(buf, buf + BUF_SIZE, n, 10); + if (ec == std::errc()) + { + dest.append(buf, ptr); + } + else + { + throw_spdlog_ex("Failed to format int", static_cast(ec)); + } +} +#else +template +inline void append_int(T n, memory_buf_t &dest) +{ + fmt::format_int i(n); + dest.append(i.data(), i.data() + i.size()); +} +#endif + +template +SPDLOG_CONSTEXPR_FUNC unsigned int count_digits_fallback(T n) +{ + // taken from fmt: https://github.com/fmtlib/fmt/blob/8.0.1/include/fmt/format.h#L899-L912 + unsigned int count = 1; + for (;;) + { + // Integer division is slow so do it for a group of four digits instead + // of for every digit. The idea comes from the talk by Alexandrescu + // "Three Optimization Tips for C++". See speed-test for a comparison. + if (n < 10) + return count; + if (n < 100) + return count + 1; + if (n < 1000) + return count + 2; + if (n < 10000) + return count + 3; + n /= 10000u; + count += 4; + } +} + +template +inline unsigned int count_digits(T n) +{ + using count_type = typename std::conditional<(sizeof(T) > sizeof(uint32_t)), uint64_t, uint32_t>::type; +#ifdef SPDLOG_USE_STD_FORMAT + return count_digits_fallback(static_cast(n)); +#else + return static_cast(fmt:: +// fmt 7.0.0 renamed the internal namespace to detail. +// See: https://github.com/fmtlib/fmt/issues/1538 +# if FMT_VERSION < 70000 + internal +# else + detail +# endif + ::count_digits(static_cast(n))); +#endif +} + +inline void pad2(int n, memory_buf_t &dest) +{ + if (n >= 0 && n < 100) // 0-99 + { + dest.push_back(static_cast('0' + n / 10)); + dest.push_back(static_cast('0' + n % 10)); + } + else // unlikely, but just in case, let fmt deal with it + { + fmt_lib::format_to(std::back_inserter(dest), SPDLOG_FMT_STRING("{:02}"), n); + } +} + +template +inline void pad_uint(T n, unsigned int width, memory_buf_t &dest) +{ + static_assert(std::is_unsigned::value, "pad_uint must get unsigned T"); + for (auto digits = count_digits(n); digits < width; digits++) + { + dest.push_back('0'); + } + append_int(n, dest); +} + +template +inline void pad3(T n, memory_buf_t &dest) +{ + static_assert(std::is_unsigned::value, "pad3 must get unsigned T"); + if (n < 1000) + { + dest.push_back(static_cast(n / 100 + '0')); + n = n % 100; + dest.push_back(static_cast((n / 10) + '0')); + dest.push_back(static_cast((n % 10) + '0')); + } + else + { + append_int(n, dest); + } +} + +template +inline void pad6(T n, memory_buf_t &dest) +{ + pad_uint(n, 6, dest); +} + +template +inline void pad9(T n, memory_buf_t &dest) +{ + pad_uint(n, 9, dest); +} + +// return fraction of a second of the given time_point. +// e.g. +// fraction(tp) -> will return the millis part of the second +template +inline ToDuration time_fraction(log_clock::time_point tp) +{ + using std::chrono::duration_cast; + using std::chrono::seconds; + auto duration = tp.time_since_epoch(); + auto secs = duration_cast(duration); + return duration_cast(duration) - duration_cast(secs); +} + +} // namespace fmt_helper +} // namespace details +} // namespace spdlog diff --git a/tpl/spdlog/include/spdlog/details/log_msg-inl.h b/tpl/spdlog/include/spdlog/details/log_msg-inl.h new file mode 100644 index 0000000..c6e8a7e --- /dev/null +++ b/tpl/spdlog/include/spdlog/details/log_msg-inl.h @@ -0,0 +1,37 @@ +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) + +#pragma once + +#ifndef SPDLOG_HEADER_ONLY +# include +#endif + +#include + +namespace spdlog { +namespace details { + +SPDLOG_INLINE log_msg::log_msg(spdlog::log_clock::time_point log_time, spdlog::source_loc loc, string_view_t a_logger_name, + spdlog::level::level_enum lvl, spdlog::string_view_t msg) + : logger_name(a_logger_name) + , level(lvl) + , time(log_time) +#ifndef SPDLOG_NO_THREAD_ID + , thread_id(os::thread_id()) +#endif + , source(loc) + , payload(msg) +{} + +SPDLOG_INLINE log_msg::log_msg( + spdlog::source_loc loc, string_view_t a_logger_name, spdlog::level::level_enum lvl, spdlog::string_view_t msg) + : log_msg(os::now(), loc, a_logger_name, lvl, msg) +{} + +SPDLOG_INLINE log_msg::log_msg(string_view_t a_logger_name, spdlog::level::level_enum lvl, spdlog::string_view_t msg) + : log_msg(os::now(), source_loc{}, a_logger_name, lvl, msg) +{} + +} // namespace details +} // namespace spdlog diff --git a/tpl/spdlog/include/spdlog/details/log_msg.h b/tpl/spdlog/include/spdlog/details/log_msg.h new file mode 100644 index 0000000..fed51ab --- /dev/null +++ b/tpl/spdlog/include/spdlog/details/log_msg.h @@ -0,0 +1,37 @@ +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) + +#pragma once + +#include +#include + +namespace spdlog { +namespace details { +struct SPDLOG_API log_msg +{ + log_msg() = default; + log_msg(log_clock::time_point log_time, source_loc loc, string_view_t logger_name, level::level_enum lvl, string_view_t msg); + log_msg(source_loc loc, string_view_t logger_name, level::level_enum lvl, string_view_t msg); + log_msg(string_view_t logger_name, level::level_enum lvl, string_view_t msg); + log_msg(const log_msg &other) = default; + log_msg &operator=(const log_msg &other) = default; + + string_view_t logger_name; + level::level_enum level{level::off}; + log_clock::time_point time; + size_t thread_id{0}; + + // wrapping the formatted text with color (updated by pattern_formatter). + mutable size_t color_range_start{0}; + mutable size_t color_range_end{0}; + + source_loc source; + string_view_t payload; +}; +} // namespace details +} // namespace spdlog + +#ifdef SPDLOG_HEADER_ONLY +# include "log_msg-inl.h" +#endif diff --git a/tpl/spdlog/include/spdlog/details/log_msg_buffer-inl.h b/tpl/spdlog/include/spdlog/details/log_msg_buffer-inl.h new file mode 100644 index 0000000..84d83dc --- /dev/null +++ b/tpl/spdlog/include/spdlog/details/log_msg_buffer-inl.h @@ -0,0 +1,58 @@ +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) + +#pragma once + +#ifndef SPDLOG_HEADER_ONLY +# include +#endif + +namespace spdlog { +namespace details { + +SPDLOG_INLINE log_msg_buffer::log_msg_buffer(const log_msg &orig_msg) + : log_msg{orig_msg} +{ + buffer.append(logger_name.begin(), logger_name.end()); + buffer.append(payload.begin(), payload.end()); + update_string_views(); +} + +SPDLOG_INLINE log_msg_buffer::log_msg_buffer(const log_msg_buffer &other) + : log_msg{other} +{ + buffer.append(logger_name.begin(), logger_name.end()); + buffer.append(payload.begin(), payload.end()); + update_string_views(); +} + +SPDLOG_INLINE log_msg_buffer::log_msg_buffer(log_msg_buffer &&other) SPDLOG_NOEXCEPT : log_msg{other}, buffer{std::move(other.buffer)} +{ + update_string_views(); +} + +SPDLOG_INLINE log_msg_buffer &log_msg_buffer::operator=(const log_msg_buffer &other) +{ + log_msg::operator=(other); + buffer.clear(); + buffer.append(other.buffer.data(), other.buffer.data() + other.buffer.size()); + update_string_views(); + return *this; +} + +SPDLOG_INLINE log_msg_buffer &log_msg_buffer::operator=(log_msg_buffer &&other) SPDLOG_NOEXCEPT +{ + log_msg::operator=(other); + buffer = std::move(other.buffer); + update_string_views(); + return *this; +} + +SPDLOG_INLINE void log_msg_buffer::update_string_views() +{ + logger_name = string_view_t{buffer.data(), logger_name.size()}; + payload = string_view_t{buffer.data() + logger_name.size(), payload.size()}; +} + +} // namespace details +} // namespace spdlog diff --git a/tpl/spdlog/include/spdlog/details/log_msg_buffer.h b/tpl/spdlog/include/spdlog/details/log_msg_buffer.h new file mode 100644 index 0000000..8105506 --- /dev/null +++ b/tpl/spdlog/include/spdlog/details/log_msg_buffer.h @@ -0,0 +1,33 @@ +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) + +#pragma once + +#include + +namespace spdlog { +namespace details { + +// Extend log_msg with internal buffer to store its payload. +// This is needed since log_msg holds string_views that points to stack data. + +class SPDLOG_API log_msg_buffer : public log_msg +{ + memory_buf_t buffer; + void update_string_views(); + +public: + log_msg_buffer() = default; + explicit log_msg_buffer(const log_msg &orig_msg); + log_msg_buffer(const log_msg_buffer &other); + log_msg_buffer(log_msg_buffer &&other) SPDLOG_NOEXCEPT; + log_msg_buffer &operator=(const log_msg_buffer &other); + log_msg_buffer &operator=(log_msg_buffer &&other) SPDLOG_NOEXCEPT; +}; + +} // namespace details +} // namespace spdlog + +#ifdef SPDLOG_HEADER_ONLY +# include "log_msg_buffer-inl.h" +#endif diff --git a/tpl/spdlog/include/spdlog/details/mpmc_blocking_q.h b/tpl/spdlog/include/spdlog/details/mpmc_blocking_q.h new file mode 100644 index 0000000..101ea8c --- /dev/null +++ b/tpl/spdlog/include/spdlog/details/mpmc_blocking_q.h @@ -0,0 +1,154 @@ +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) + +#pragma once + +// multi producer-multi consumer blocking queue. +// enqueue(..) - will block until room found to put the new message. +// enqueue_nowait(..) - will return immediately with false if no room left in +// the queue. +// dequeue_for(..) - will block until the queue is not empty or timeout have +// passed. + +#include + +#include +#include + +namespace spdlog { +namespace details { + +template +class mpmc_blocking_queue +{ +public: + using item_type = T; + explicit mpmc_blocking_queue(size_t max_items) + : q_(max_items) + {} + +#ifndef __MINGW32__ + // try to enqueue and block if no room left + void enqueue(T &&item) + { + { + std::unique_lock lock(queue_mutex_); + pop_cv_.wait(lock, [this] { return !this->q_.full(); }); + q_.push_back(std::move(item)); + } + push_cv_.notify_one(); + } + + // enqueue immediately. overrun oldest message in the queue if no room left. + void enqueue_nowait(T &&item) + { + { + std::unique_lock lock(queue_mutex_); + q_.push_back(std::move(item)); + } + push_cv_.notify_one(); + } + + // dequeue with a timeout. + // Return true, if succeeded dequeue item, false otherwise + bool dequeue_for(T &popped_item, std::chrono::milliseconds wait_duration) + { + { + std::unique_lock lock(queue_mutex_); + if (!push_cv_.wait_for(lock, wait_duration, [this] { return !this->q_.empty(); })) + { + return false; + } + popped_item = std::move(q_.front()); + q_.pop_front(); + } + pop_cv_.notify_one(); + return true; + } + + // blocking dequeue without a timeout. + void dequeue(T &popped_item) + { + { + std::unique_lock lock(queue_mutex_); + push_cv_.wait(lock, [this] { return !this->q_.empty(); }); + popped_item = std::move(q_.front()); + q_.pop_front(); + } + pop_cv_.notify_one(); + } + +#else + // apparently mingw deadlocks if the mutex is released before cv.notify_one(), + // so release the mutex at the very end each function. + + // try to enqueue and block if no room left + void enqueue(T &&item) + { + std::unique_lock lock(queue_mutex_); + pop_cv_.wait(lock, [this] { return !this->q_.full(); }); + q_.push_back(std::move(item)); + push_cv_.notify_one(); + } + + // enqueue immediately. overrun oldest message in the queue if no room left. + void enqueue_nowait(T &&item) + { + std::unique_lock lock(queue_mutex_); + q_.push_back(std::move(item)); + push_cv_.notify_one(); + } + + // dequeue with a timeout. + // Return true, if succeeded dequeue item, false otherwise + bool dequeue_for(T &popped_item, std::chrono::milliseconds wait_duration) + { + std::unique_lock lock(queue_mutex_); + if (!push_cv_.wait_for(lock, wait_duration, [this] { return !this->q_.empty(); })) + { + return false; + } + popped_item = std::move(q_.front()); + q_.pop_front(); + pop_cv_.notify_one(); + return true; + } + + // blocking dequeue without a timeout. + void dequeue(T &popped_item) + { + std::unique_lock lock(queue_mutex_); + push_cv_.wait(lock, [this] { return !this->q_.empty(); }); + popped_item = std::move(q_.front()); + q_.pop_front(); + pop_cv_.notify_one(); + } + +#endif + + size_t overrun_counter() + { + std::unique_lock lock(queue_mutex_); + return q_.overrun_counter(); + } + + size_t size() + { + std::unique_lock lock(queue_mutex_); + return q_.size(); + } + + void reset_overrun_counter() + { + std::unique_lock lock(queue_mutex_); + q_.reset_overrun_counter(); + } + +private: + std::mutex queue_mutex_; + std::condition_variable push_cv_; + std::condition_variable pop_cv_; + spdlog::details::circular_q q_; +}; +} // namespace details +} // namespace spdlog diff --git a/tpl/spdlog/include/spdlog/details/null_mutex.h b/tpl/spdlog/include/spdlog/details/null_mutex.h new file mode 100644 index 0000000..6550a7b --- /dev/null +++ b/tpl/spdlog/include/spdlog/details/null_mutex.h @@ -0,0 +1,45 @@ +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) + +#pragma once + +#include +#include +// null, no cost dummy "mutex" and dummy "atomic" int + +namespace spdlog { +namespace details { +struct null_mutex +{ + void lock() const {} + void unlock() const {} +}; + +struct null_atomic_int +{ + int value; + null_atomic_int() = default; + + explicit null_atomic_int(int new_value) + : value(new_value) + {} + + int load(std::memory_order = std::memory_order_relaxed) const + { + return value; + } + + void store(int new_value, std::memory_order = std::memory_order_relaxed) + { + value = new_value; + } + + int exchange(int new_value, std::memory_order = std::memory_order_relaxed) + { + std::swap(new_value, value); + return new_value; // return value before the call + } +}; + +} // namespace details +} // namespace spdlog diff --git a/tpl/spdlog/include/spdlog/details/os-inl.h b/tpl/spdlog/include/spdlog/details/os-inl.h new file mode 100644 index 0000000..ea8864e --- /dev/null +++ b/tpl/spdlog/include/spdlog/details/os-inl.h @@ -0,0 +1,635 @@ +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) + +#pragma once + +#ifndef SPDLOG_HEADER_ONLY +# include +#endif + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef _WIN32 + +# include // for _get_osfhandle, _isatty, _fileno +# include // for _get_pid +# include +# include // for FlushFileBuffers + +# ifdef __MINGW32__ +# include +# endif + +# if defined(SPDLOG_WCHAR_TO_UTF8_SUPPORT) || defined(SPDLOG_WCHAR_FILENAMES) +# include +# include +# endif + +# include // for _mkdir/_wmkdir + +#else // unix + +# include +# include + +# ifdef __linux__ +# include //Use gettid() syscall under linux to get thread id + +# elif defined(_AIX) +# include // for pthread_getthrds_np + +# elif defined(__DragonFly__) || defined(__FreeBSD__) +# include // for pthread_getthreadid_np + +# elif defined(__NetBSD__) +# include // for _lwp_self + +# elif defined(__sun) +# include // for thr_self +# endif + +#endif // unix + +#if defined __APPLE__ +# include +#endif + +#ifndef __has_feature // Clang - feature checking macros. +# define __has_feature(x) 0 // Compatibility with non-clang compilers. +#endif + +namespace spdlog { +namespace details { +namespace os { + +SPDLOG_INLINE spdlog::log_clock::time_point now() SPDLOG_NOEXCEPT +{ + +#if defined __linux__ && defined SPDLOG_CLOCK_COARSE + timespec ts; + ::clock_gettime(CLOCK_REALTIME_COARSE, &ts); + return std::chrono::time_point( + std::chrono::duration_cast(std::chrono::seconds(ts.tv_sec) + std::chrono::nanoseconds(ts.tv_nsec))); + +#else + return log_clock::now(); +#endif +} +SPDLOG_INLINE std::tm localtime(const std::time_t &time_tt) SPDLOG_NOEXCEPT +{ + +#ifdef _WIN32 + std::tm tm; + ::localtime_s(&tm, &time_tt); +#else + std::tm tm; + ::localtime_r(&time_tt, &tm); +#endif + return tm; +} + +SPDLOG_INLINE std::tm localtime() SPDLOG_NOEXCEPT +{ + std::time_t now_t = ::time(nullptr); + return localtime(now_t); +} + +SPDLOG_INLINE std::tm gmtime(const std::time_t &time_tt) SPDLOG_NOEXCEPT +{ + +#ifdef _WIN32 + std::tm tm; + ::gmtime_s(&tm, &time_tt); +#else + std::tm tm; + ::gmtime_r(&time_tt, &tm); +#endif + return tm; +} + +SPDLOG_INLINE std::tm gmtime() SPDLOG_NOEXCEPT +{ + std::time_t now_t = ::time(nullptr); + return gmtime(now_t); +} + +// fopen_s on non windows for writing +SPDLOG_INLINE bool fopen_s(FILE **fp, const filename_t &filename, const filename_t &mode) +{ +#ifdef _WIN32 +# ifdef SPDLOG_WCHAR_FILENAMES + *fp = ::_wfsopen((filename.c_str()), mode.c_str(), _SH_DENYNO); +# else + *fp = ::_fsopen((filename.c_str()), mode.c_str(), _SH_DENYNO); +# endif +# if defined(SPDLOG_PREVENT_CHILD_FD) + if (*fp != nullptr) + { + auto file_handle = reinterpret_cast(_get_osfhandle(::_fileno(*fp))); + if (!::SetHandleInformation(file_handle, HANDLE_FLAG_INHERIT, 0)) + { + ::fclose(*fp); + *fp = nullptr; + } + } +# endif +#else // unix +# if defined(SPDLOG_PREVENT_CHILD_FD) + const int mode_flag = mode == SPDLOG_FILENAME_T("ab") ? O_APPEND : O_TRUNC; + const int fd = ::open((filename.c_str()), O_CREAT | O_WRONLY | O_CLOEXEC | mode_flag, mode_t(0644)); + if (fd == -1) + { + return true; + } + *fp = ::fdopen(fd, mode.c_str()); + if (*fp == nullptr) + { + ::close(fd); + } +# else + *fp = ::fopen((filename.c_str()), mode.c_str()); +# endif +#endif + + return *fp == nullptr; +} + +SPDLOG_INLINE int remove(const filename_t &filename) SPDLOG_NOEXCEPT +{ +#if defined(_WIN32) && defined(SPDLOG_WCHAR_FILENAMES) + return ::_wremove(filename.c_str()); +#else + return std::remove(filename.c_str()); +#endif +} + +SPDLOG_INLINE int remove_if_exists(const filename_t &filename) SPDLOG_NOEXCEPT +{ + return path_exists(filename) ? remove(filename) : 0; +} + +SPDLOG_INLINE int rename(const filename_t &filename1, const filename_t &filename2) SPDLOG_NOEXCEPT +{ +#if defined(_WIN32) && defined(SPDLOG_WCHAR_FILENAMES) + return ::_wrename(filename1.c_str(), filename2.c_str()); +#else + return std::rename(filename1.c_str(), filename2.c_str()); +#endif +} + +// Return true if path exists (file or directory) +SPDLOG_INLINE bool path_exists(const filename_t &filename) SPDLOG_NOEXCEPT +{ +#ifdef _WIN32 +# ifdef SPDLOG_WCHAR_FILENAMES + auto attribs = ::GetFileAttributesW(filename.c_str()); +# else + auto attribs = ::GetFileAttributesA(filename.c_str()); +# endif + return attribs != INVALID_FILE_ATTRIBUTES; +#else // common linux/unix all have the stat system call + struct stat buffer; + return (::stat(filename.c_str(), &buffer) == 0); +#endif +} + +#ifdef _MSC_VER +// avoid warning about unreachable statement at the end of filesize() +# pragma warning(push) +# pragma warning(disable : 4702) +#endif + +// Return file size according to open FILE* object +SPDLOG_INLINE size_t filesize(FILE *f) +{ + if (f == nullptr) + { + throw_spdlog_ex("Failed getting file size. fd is null"); + } +#if defined(_WIN32) && !defined(__CYGWIN__) + int fd = ::_fileno(f); +# if defined(_WIN64) // 64 bits + __int64 ret = ::_filelengthi64(fd); + if (ret >= 0) + { + return static_cast(ret); + } + +# else // windows 32 bits + long ret = ::_filelength(fd); + if (ret >= 0) + { + return static_cast(ret); + } +# endif + +#else // unix +// OpenBSD and AIX doesn't compile with :: before the fileno(..) +# if defined(__OpenBSD__) || defined(_AIX) + int fd = fileno(f); +# else + int fd = ::fileno(f); +# endif +// 64 bits(but not in osx, linux/musl or cygwin, where fstat64 is deprecated) +# if ((defined(__linux__) && defined(__GLIBC__)) || defined(__sun) || defined(_AIX)) && (defined(__LP64__) || defined(_LP64)) + struct stat64 st; + if (::fstat64(fd, &st) == 0) + { + return static_cast(st.st_size); + } +# else // other unix or linux 32 bits or cygwin + struct stat st; + if (::fstat(fd, &st) == 0) + { + return static_cast(st.st_size); + } +# endif +#endif + throw_spdlog_ex("Failed getting file size from fd", errno); + return 0; // will not be reached. +} + +#ifdef _MSC_VER +# pragma warning(pop) +#endif + +// Return utc offset in minutes or throw spdlog_ex on failure +SPDLOG_INLINE int utc_minutes_offset(const std::tm &tm) +{ + +#ifdef _WIN32 +# if _WIN32_WINNT < _WIN32_WINNT_WS08 + TIME_ZONE_INFORMATION tzinfo; + auto rv = ::GetTimeZoneInformation(&tzinfo); +# else + DYNAMIC_TIME_ZONE_INFORMATION tzinfo; + auto rv = ::GetDynamicTimeZoneInformation(&tzinfo); +# endif + if (rv == TIME_ZONE_ID_INVALID) + throw_spdlog_ex("Failed getting timezone info. ", errno); + + int offset = -tzinfo.Bias; + if (tm.tm_isdst) + { + offset -= tzinfo.DaylightBias; + } + else + { + offset -= tzinfo.StandardBias; + } + return offset; +#else + +# if defined(sun) || defined(__sun) || defined(_AIX) || (defined(__NEWLIB__) && !defined(__TM_GMTOFF)) || \ + (!defined(_BSD_SOURCE) && !defined(_GNU_SOURCE)) + // 'tm_gmtoff' field is BSD extension and it's missing on SunOS/Solaris + struct helper + { + static long int calculate_gmt_offset(const std::tm &localtm = details::os::localtime(), const std::tm &gmtm = details::os::gmtime()) + { + int local_year = localtm.tm_year + (1900 - 1); + int gmt_year = gmtm.tm_year + (1900 - 1); + + long int days = ( + // difference in day of year + localtm.tm_yday - + gmtm.tm_yday + + // + intervening leap days + + ((local_year >> 2) - (gmt_year >> 2)) - (local_year / 100 - gmt_year / 100) + + ((local_year / 100 >> 2) - (gmt_year / 100 >> 2)) + + // + difference in years * 365 */ + + static_cast(local_year - gmt_year) * 365); + + long int hours = (24 * days) + (localtm.tm_hour - gmtm.tm_hour); + long int mins = (60 * hours) + (localtm.tm_min - gmtm.tm_min); + long int secs = (60 * mins) + (localtm.tm_sec - gmtm.tm_sec); + + return secs; + } + }; + + auto offset_seconds = helper::calculate_gmt_offset(tm); +# else + auto offset_seconds = tm.tm_gmtoff; +# endif + + return static_cast(offset_seconds / 60); +#endif +} + +// Return current thread id as size_t +// It exists because the std::this_thread::get_id() is much slower(especially +// under VS 2013) +SPDLOG_INLINE size_t _thread_id() SPDLOG_NOEXCEPT +{ +#ifdef _WIN32 + return static_cast(::GetCurrentThreadId()); +#elif defined(__linux__) +# if defined(__ANDROID__) && defined(__ANDROID_API__) && (__ANDROID_API__ < 21) +# define SYS_gettid __NR_gettid +# endif + return static_cast(::syscall(SYS_gettid)); +#elif defined(_AIX) + struct __pthrdsinfo buf; + int reg_size = 0; + pthread_t pt = pthread_self(); + int retval = pthread_getthrds_np(&pt, PTHRDSINFO_QUERY_TID, &buf, sizeof(buf), NULL, ®_size); + int tid = (!retval) ? buf.__pi_tid : 0; + return static_cast(tid); +#elif defined(__DragonFly__) || defined(__FreeBSD__) + return static_cast(::pthread_getthreadid_np()); +#elif defined(__NetBSD__) + return static_cast(::_lwp_self()); +#elif defined(__OpenBSD__) + return static_cast(::getthrid()); +#elif defined(__sun) + return static_cast(::thr_self()); +#elif __APPLE__ + uint64_t tid; + // There is no pthread_threadid_np prior to 10.6, and it is not supported on any PPC, + // including 10.6.8 Rosetta. __POWERPC__ is Apple-specific define encompassing ppc and ppc64. +# if (MAC_OS_X_VERSION_MAX_ALLOWED < 1060) || defined(__POWERPC__) + tid = pthread_mach_thread_np(pthread_self()); +# elif MAC_OS_X_VERSION_MIN_REQUIRED < 1060 + if (&pthread_threadid_np) + { + pthread_threadid_np(nullptr, &tid); + } + else + { + tid = pthread_mach_thread_np(pthread_self()); + } +# else + pthread_threadid_np(nullptr, &tid); +# endif + return static_cast(tid); +#else // Default to standard C++11 (other Unix) + return static_cast(std::hash()(std::this_thread::get_id())); +#endif +} + +// Return current thread id as size_t (from thread local storage) +SPDLOG_INLINE size_t thread_id() SPDLOG_NOEXCEPT +{ +#if defined(SPDLOG_NO_TLS) + return _thread_id(); +#else // cache thread id in tls + static thread_local const size_t tid = _thread_id(); + return tid; +#endif +} + +// This is avoid msvc issue in sleep_for that happens if the clock changes. +// See https://github.com/gabime/spdlog/issues/609 +SPDLOG_INLINE void sleep_for_millis(unsigned int milliseconds) SPDLOG_NOEXCEPT +{ +#if defined(_WIN32) + ::Sleep(milliseconds); +#else + std::this_thread::sleep_for(std::chrono::milliseconds(milliseconds)); +#endif +} + +// wchar support for windows file names (SPDLOG_WCHAR_FILENAMES must be defined) +#if defined(_WIN32) && defined(SPDLOG_WCHAR_FILENAMES) +SPDLOG_INLINE std::string filename_to_str(const filename_t &filename) +{ + memory_buf_t buf; + wstr_to_utf8buf(filename, buf); + return SPDLOG_BUF_TO_STRING(buf); +} +#else +SPDLOG_INLINE std::string filename_to_str(const filename_t &filename) +{ + return filename; +} +#endif + +SPDLOG_INLINE int pid() SPDLOG_NOEXCEPT +{ + +#ifdef _WIN32 + return conditional_static_cast(::GetCurrentProcessId()); +#else + return conditional_static_cast(::getpid()); +#endif +} + +// Determine if the terminal supports colors +// Based on: https://github.com/agauniyal/rang/ +SPDLOG_INLINE bool is_color_terminal() SPDLOG_NOEXCEPT +{ +#ifdef _WIN32 + return true; +#else + + static const bool result = []() { + const char *env_colorterm_p = std::getenv("COLORTERM"); + if (env_colorterm_p != nullptr) + { + return true; + } + + static constexpr std::array terms = {{"ansi", "color", "console", "cygwin", "gnome", "konsole", "kterm", "linux", + "msys", "putty", "rxvt", "screen", "vt100", "xterm", "alacritty", "vt102"}}; + + const char *env_term_p = std::getenv("TERM"); + if (env_term_p == nullptr) + { + return false; + } + + return std::any_of(terms.begin(), terms.end(), [&](const char *term) { return std::strstr(env_term_p, term) != nullptr; }); + }(); + + return result; +#endif +} + +// Determine if the terminal attached +// Source: https://github.com/agauniyal/rang/ +SPDLOG_INLINE bool in_terminal(FILE *file) SPDLOG_NOEXCEPT +{ + +#ifdef _WIN32 + return ::_isatty(_fileno(file)) != 0; +#else + return ::isatty(fileno(file)) != 0; +#endif +} + +#if (defined(SPDLOG_WCHAR_TO_UTF8_SUPPORT) || defined(SPDLOG_WCHAR_FILENAMES)) && defined(_WIN32) +SPDLOG_INLINE void wstr_to_utf8buf(wstring_view_t wstr, memory_buf_t &target) +{ + if (wstr.size() > static_cast((std::numeric_limits::max)()) / 2 - 1) + { + throw_spdlog_ex("UTF-16 string is too big to be converted to UTF-8"); + } + + int wstr_size = static_cast(wstr.size()); + if (wstr_size == 0) + { + target.resize(0); + return; + } + + int result_size = static_cast(target.capacity()); + if ((wstr_size + 1) * 2 > result_size) + { + result_size = ::WideCharToMultiByte(CP_UTF8, 0, wstr.data(), wstr_size, NULL, 0, NULL, NULL); + } + + if (result_size > 0) + { + target.resize(result_size); + result_size = ::WideCharToMultiByte(CP_UTF8, 0, wstr.data(), wstr_size, target.data(), result_size, NULL, NULL); + + if (result_size > 0) + { + target.resize(result_size); + return; + } + } + + throw_spdlog_ex(fmt_lib::format("WideCharToMultiByte failed. Last error: {}", ::GetLastError())); +} + +SPDLOG_INLINE void utf8_to_wstrbuf(string_view_t str, wmemory_buf_t &target) +{ + if (str.size() > static_cast((std::numeric_limits::max)()) - 1) + { + throw_spdlog_ex("UTF-8 string is too big to be converted to UTF-16"); + } + + int str_size = static_cast(str.size()); + if (str_size == 0) + { + target.resize(0); + return; + } + + // find the size to allocate for the result buffer + int result_size = ::MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, str.data(), str_size, NULL, 0); + + if (result_size > 0) + { + target.resize(result_size); + result_size = ::MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, str.data(), str_size, target.data(), result_size); + if (result_size > 0) + { + assert(result_size == target.size()); + return; + } + } + + throw_spdlog_ex(fmt_lib::format("MultiByteToWideChar failed. Last error: {}", ::GetLastError())); +} +#endif // (defined(SPDLOG_WCHAR_TO_UTF8_SUPPORT) || defined(SPDLOG_WCHAR_FILENAMES)) && defined(_WIN32) + +// return true on success +static SPDLOG_INLINE bool mkdir_(const filename_t &path) +{ +#ifdef _WIN32 +# ifdef SPDLOG_WCHAR_FILENAMES + return ::_wmkdir(path.c_str()) == 0; +# else + return ::_mkdir(path.c_str()) == 0; +# endif +#else + return ::mkdir(path.c_str(), mode_t(0755)) == 0; +#endif +} + +// create the given directory - and all directories leading to it +// return true on success or if the directory already exists +SPDLOG_INLINE bool create_dir(const filename_t &path) +{ + if (path_exists(path)) + { + return true; + } + + if (path.empty()) + { + return false; + } + + size_t search_offset = 0; + do + { + auto token_pos = path.find_first_of(folder_seps_filename, search_offset); + // treat the entire path as a folder if no folder separator not found + if (token_pos == filename_t::npos) + { + token_pos = path.size(); + } + + auto subdir = path.substr(0, token_pos); + + if (!subdir.empty() && !path_exists(subdir) && !mkdir_(subdir)) + { + return false; // return error if failed creating dir + } + search_offset = token_pos + 1; + } while (search_offset < path.size()); + + return true; +} + +// Return directory name from given path or empty string +// "abc/file" => "abc" +// "abc/" => "abc" +// "abc" => "" +// "abc///" => "abc//" +SPDLOG_INLINE filename_t dir_name(const filename_t &path) +{ + auto pos = path.find_last_of(folder_seps_filename); + return pos != filename_t::npos ? path.substr(0, pos) : filename_t{}; +} + +std::string SPDLOG_INLINE getenv(const char *field) +{ + +#if defined(_MSC_VER) +# if defined(__cplusplus_winrt) + return std::string{}; // not supported under uwp +# else + size_t len = 0; + char buf[128]; + bool ok = ::getenv_s(&len, buf, sizeof(buf), field) == 0; + return ok ? buf : std::string{}; +# endif +#else // revert to getenv + char *buf = ::getenv(field); + return buf ? buf : std::string{}; +#endif +} + +// Do fsync by FILE handlerpointer +// Return true on success +SPDLOG_INLINE bool fsync(FILE *fp) +{ +#ifdef _WIN32 + return FlushFileBuffers(reinterpret_cast(_get_osfhandle(_fileno(fp)))) != 0; +#else + return ::fsync(fileno(fp)) == 0; +#endif +} + +} // namespace os +} // namespace details +} // namespace spdlog diff --git a/tpl/spdlog/include/spdlog/details/os.h b/tpl/spdlog/include/spdlog/details/os.h new file mode 100644 index 0000000..37b0087 --- /dev/null +++ b/tpl/spdlog/include/spdlog/details/os.h @@ -0,0 +1,122 @@ +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) + +#pragma once + +#include +#include // std::time_t + +namespace spdlog { +namespace details { +namespace os { + +SPDLOG_API spdlog::log_clock::time_point now() SPDLOG_NOEXCEPT; + +SPDLOG_API std::tm localtime(const std::time_t &time_tt) SPDLOG_NOEXCEPT; + +SPDLOG_API std::tm localtime() SPDLOG_NOEXCEPT; + +SPDLOG_API std::tm gmtime(const std::time_t &time_tt) SPDLOG_NOEXCEPT; + +SPDLOG_API std::tm gmtime() SPDLOG_NOEXCEPT; + +// eol definition +#if !defined(SPDLOG_EOL) +# ifdef _WIN32 +# define SPDLOG_EOL "\r\n" +# else +# define SPDLOG_EOL "\n" +# endif +#endif + +SPDLOG_CONSTEXPR static const char *default_eol = SPDLOG_EOL; + +// folder separator +#if !defined(SPDLOG_FOLDER_SEPS) +# ifdef _WIN32 +# define SPDLOG_FOLDER_SEPS "\\/" +# else +# define SPDLOG_FOLDER_SEPS "/" +# endif +#endif + +SPDLOG_CONSTEXPR static const char folder_seps[] = SPDLOG_FOLDER_SEPS; +SPDLOG_CONSTEXPR static const filename_t::value_type folder_seps_filename[] = SPDLOG_FILENAME_T(SPDLOG_FOLDER_SEPS); + +// fopen_s on non windows for writing +SPDLOG_API bool fopen_s(FILE **fp, const filename_t &filename, const filename_t &mode); + +// Remove filename. return 0 on success +SPDLOG_API int remove(const filename_t &filename) SPDLOG_NOEXCEPT; + +// Remove file if exists. return 0 on success +// Note: Non atomic (might return failure to delete if concurrently deleted by other process/thread) +SPDLOG_API int remove_if_exists(const filename_t &filename) SPDLOG_NOEXCEPT; + +SPDLOG_API int rename(const filename_t &filename1, const filename_t &filename2) SPDLOG_NOEXCEPT; + +// Return if file exists. +SPDLOG_API bool path_exists(const filename_t &filename) SPDLOG_NOEXCEPT; + +// Return file size according to open FILE* object +SPDLOG_API size_t filesize(FILE *f); + +// Return utc offset in minutes or throw spdlog_ex on failure +SPDLOG_API int utc_minutes_offset(const std::tm &tm = details::os::localtime()); + +// Return current thread id as size_t +// It exists because the std::this_thread::get_id() is much slower(especially +// under VS 2013) +SPDLOG_API size_t _thread_id() SPDLOG_NOEXCEPT; + +// Return current thread id as size_t (from thread local storage) +SPDLOG_API size_t thread_id() SPDLOG_NOEXCEPT; + +// This is avoid msvc issue in sleep_for that happens if the clock changes. +// See https://github.com/gabime/spdlog/issues/609 +SPDLOG_API void sleep_for_millis(unsigned int milliseconds) SPDLOG_NOEXCEPT; + +SPDLOG_API std::string filename_to_str(const filename_t &filename); + +SPDLOG_API int pid() SPDLOG_NOEXCEPT; + +// Determine if the terminal supports colors +// Source: https://github.com/agauniyal/rang/ +SPDLOG_API bool is_color_terminal() SPDLOG_NOEXCEPT; + +// Determine if the terminal attached +// Source: https://github.com/agauniyal/rang/ +SPDLOG_API bool in_terminal(FILE *file) SPDLOG_NOEXCEPT; + +#if (defined(SPDLOG_WCHAR_TO_UTF8_SUPPORT) || defined(SPDLOG_WCHAR_FILENAMES)) && defined(_WIN32) +SPDLOG_API void wstr_to_utf8buf(wstring_view_t wstr, memory_buf_t &target); + +SPDLOG_API void utf8_to_wstrbuf(string_view_t str, wmemory_buf_t &target); +#endif + +// Return directory name from given path or empty string +// "abc/file" => "abc" +// "abc/" => "abc" +// "abc" => "" +// "abc///" => "abc//" +SPDLOG_API filename_t dir_name(const filename_t &path); + +// Create a dir from the given path. +// Return true if succeeded or if this dir already exists. +SPDLOG_API bool create_dir(const filename_t &path); + +// non thread safe, cross platform getenv/getenv_s +// return empty string if field not found +SPDLOG_API std::string getenv(const char *field); + +// Do fsync by FILE objectpointer. +// Return true on success. +SPDLOG_API bool fsync(FILE *fp); + +} // namespace os +} // namespace details +} // namespace spdlog + +#ifdef SPDLOG_HEADER_ONLY +# include "os-inl.h" +#endif diff --git a/tpl/spdlog/include/spdlog/details/periodic_worker-inl.h b/tpl/spdlog/include/spdlog/details/periodic_worker-inl.h new file mode 100644 index 0000000..520a2b3 --- /dev/null +++ b/tpl/spdlog/include/spdlog/details/periodic_worker-inl.h @@ -0,0 +1,28 @@ +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) + +#pragma once + +#ifndef SPDLOG_HEADER_ONLY +# include +#endif + +namespace spdlog { +namespace details { + +// stop the worker thread and join it +SPDLOG_INLINE periodic_worker::~periodic_worker() +{ + if (worker_thread_.joinable()) + { + { + std::lock_guard lock(mutex_); + active_ = false; + } + cv_.notify_one(); + worker_thread_.join(); + } +} + +} // namespace details +} // namespace spdlog diff --git a/tpl/spdlog/include/spdlog/details/periodic_worker.h b/tpl/spdlog/include/spdlog/details/periodic_worker.h new file mode 100644 index 0000000..d7d69b2 --- /dev/null +++ b/tpl/spdlog/include/spdlog/details/periodic_worker.h @@ -0,0 +1,60 @@ +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) + +#pragma once + +// periodic worker thread - periodically executes the given callback function. +// +// RAII over the owned thread: +// creates the thread on construction. +// stops and joins the thread on destruction (if the thread is executing a callback, wait for it to finish first). + +#include +#include +#include +#include +#include +namespace spdlog { +namespace details { + +class SPDLOG_API periodic_worker +{ +public: + template + periodic_worker(const std::function &callback_fun, std::chrono::duration interval) + { + active_ = (interval > std::chrono::duration::zero()); + if (!active_) + { + return; + } + + worker_thread_ = std::thread([this, callback_fun, interval]() { + for (;;) + { + std::unique_lock lock(this->mutex_); + if (this->cv_.wait_for(lock, interval, [this] { return !this->active_; })) + { + return; // active_ == false, so exit this thread + } + callback_fun(); + } + }); + } + periodic_worker(const periodic_worker &) = delete; + periodic_worker &operator=(const periodic_worker &) = delete; + // stop the worker thread and join it + ~periodic_worker(); + +private: + bool active_; + std::thread worker_thread_; + std::mutex mutex_; + std::condition_variable cv_; +}; +} // namespace details +} // namespace spdlog + +#ifdef SPDLOG_HEADER_ONLY +# include "periodic_worker-inl.h" +#endif diff --git a/tpl/spdlog/include/spdlog/details/registry-inl.h b/tpl/spdlog/include/spdlog/details/registry-inl.h new file mode 100644 index 0000000..cb1fe84 --- /dev/null +++ b/tpl/spdlog/include/spdlog/details/registry-inl.h @@ -0,0 +1,315 @@ +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) + +#pragma once + +#ifndef SPDLOG_HEADER_ONLY +# include +#endif + +#include +#include +#include +#include + +#ifndef SPDLOG_DISABLE_DEFAULT_LOGGER +// support for the default stdout color logger +# ifdef _WIN32 +# include +# else +# include +# endif +#endif // SPDLOG_DISABLE_DEFAULT_LOGGER + +#include +#include +#include +#include +#include + +namespace spdlog { +namespace details { + +SPDLOG_INLINE registry::registry() + : formatter_(new pattern_formatter()) +{ + +#ifndef SPDLOG_DISABLE_DEFAULT_LOGGER + // create default logger (ansicolor_stdout_sink_mt or wincolor_stdout_sink_mt in windows). +# ifdef _WIN32 + auto color_sink = std::make_shared(); +# else + auto color_sink = std::make_shared(); +# endif + + const char *default_logger_name = ""; + default_logger_ = std::make_shared(default_logger_name, std::move(color_sink)); + loggers_[default_logger_name] = default_logger_; + +#endif // SPDLOG_DISABLE_DEFAULT_LOGGER +} + +SPDLOG_INLINE registry::~registry() = default; + +SPDLOG_INLINE void registry::register_logger(std::shared_ptr new_logger) +{ + std::lock_guard lock(logger_map_mutex_); + register_logger_(std::move(new_logger)); +} + +SPDLOG_INLINE void registry::initialize_logger(std::shared_ptr new_logger) +{ + std::lock_guard lock(logger_map_mutex_); + new_logger->set_formatter(formatter_->clone()); + + if (err_handler_) + { + new_logger->set_error_handler(err_handler_); + } + + // set new level according to previously configured level or default level + auto it = log_levels_.find(new_logger->name()); + auto new_level = it != log_levels_.end() ? it->second : global_log_level_; + new_logger->set_level(new_level); + + new_logger->flush_on(flush_level_); + + if (backtrace_n_messages_ > 0) + { + new_logger->enable_backtrace(backtrace_n_messages_); + } + + if (automatic_registration_) + { + register_logger_(std::move(new_logger)); + } +} + +SPDLOG_INLINE std::shared_ptr registry::get(const std::string &logger_name) +{ + std::lock_guard lock(logger_map_mutex_); + auto found = loggers_.find(logger_name); + return found == loggers_.end() ? nullptr : found->second; +} + +SPDLOG_INLINE std::shared_ptr registry::default_logger() +{ + std::lock_guard lock(logger_map_mutex_); + return default_logger_; +} + +// Return raw ptr to the default logger. +// To be used directly by the spdlog default api (e.g. spdlog::info) +// This make the default API faster, but cannot be used concurrently with set_default_logger(). +// e.g do not call set_default_logger() from one thread while calling spdlog::info() from another. +SPDLOG_INLINE logger *registry::get_default_raw() +{ + return default_logger_.get(); +} + +// set default logger. +// default logger is stored in default_logger_ (for faster retrieval) and in the loggers_ map. +SPDLOG_INLINE void registry::set_default_logger(std::shared_ptr new_default_logger) +{ + std::lock_guard lock(logger_map_mutex_); + // remove previous default logger from the map + if (default_logger_ != nullptr) + { + loggers_.erase(default_logger_->name()); + } + if (new_default_logger != nullptr) + { + loggers_[new_default_logger->name()] = new_default_logger; + } + default_logger_ = std::move(new_default_logger); +} + +SPDLOG_INLINE void registry::set_tp(std::shared_ptr tp) +{ + std::lock_guard lock(tp_mutex_); + tp_ = std::move(tp); +} + +SPDLOG_INLINE std::shared_ptr registry::get_tp() +{ + std::lock_guard lock(tp_mutex_); + return tp_; +} + +// Set global formatter. Each sink in each logger will get a clone of this object +SPDLOG_INLINE void registry::set_formatter(std::unique_ptr formatter) +{ + std::lock_guard lock(logger_map_mutex_); + formatter_ = std::move(formatter); + for (auto &l : loggers_) + { + l.second->set_formatter(formatter_->clone()); + } +} + +SPDLOG_INLINE void registry::enable_backtrace(size_t n_messages) +{ + std::lock_guard lock(logger_map_mutex_); + backtrace_n_messages_ = n_messages; + + for (auto &l : loggers_) + { + l.second->enable_backtrace(n_messages); + } +} + +SPDLOG_INLINE void registry::disable_backtrace() +{ + std::lock_guard lock(logger_map_mutex_); + backtrace_n_messages_ = 0; + for (auto &l : loggers_) + { + l.second->disable_backtrace(); + } +} + +SPDLOG_INLINE void registry::set_level(level::level_enum log_level) +{ + std::lock_guard lock(logger_map_mutex_); + for (auto &l : loggers_) + { + l.second->set_level(log_level); + } + global_log_level_ = log_level; +} + +SPDLOG_INLINE void registry::flush_on(level::level_enum log_level) +{ + std::lock_guard lock(logger_map_mutex_); + for (auto &l : loggers_) + { + l.second->flush_on(log_level); + } + flush_level_ = log_level; +} + +SPDLOG_INLINE void registry::set_error_handler(err_handler handler) +{ + std::lock_guard lock(logger_map_mutex_); + for (auto &l : loggers_) + { + l.second->set_error_handler(handler); + } + err_handler_ = std::move(handler); +} + +SPDLOG_INLINE void registry::apply_all(const std::function)> &fun) +{ + std::lock_guard lock(logger_map_mutex_); + for (auto &l : loggers_) + { + fun(l.second); + } +} + +SPDLOG_INLINE void registry::flush_all() +{ + std::lock_guard lock(logger_map_mutex_); + for (auto &l : loggers_) + { + l.second->flush(); + } +} + +SPDLOG_INLINE void registry::drop(const std::string &logger_name) +{ + std::lock_guard lock(logger_map_mutex_); + auto is_default_logger = default_logger_ && default_logger_->name() == logger_name; + loggers_.erase(logger_name); + if (is_default_logger) + { + default_logger_.reset(); + } +} + +SPDLOG_INLINE void registry::drop_all() +{ + std::lock_guard lock(logger_map_mutex_); + loggers_.clear(); + default_logger_.reset(); +} + +// clean all resources and threads started by the registry +SPDLOG_INLINE void registry::shutdown() +{ + { + std::lock_guard lock(flusher_mutex_); + periodic_flusher_.reset(); + } + + drop_all(); + + { + std::lock_guard lock(tp_mutex_); + tp_.reset(); + } +} + +SPDLOG_INLINE std::recursive_mutex ®istry::tp_mutex() +{ + return tp_mutex_; +} + +SPDLOG_INLINE void registry::set_automatic_registration(bool automatic_registration) +{ + std::lock_guard lock(logger_map_mutex_); + automatic_registration_ = automatic_registration; +} + +SPDLOG_INLINE void registry::set_levels(log_levels levels, level::level_enum *global_level) +{ + std::lock_guard lock(logger_map_mutex_); + log_levels_ = std::move(levels); + auto global_level_requested = global_level != nullptr; + global_log_level_ = global_level_requested ? *global_level : global_log_level_; + + for (auto &logger : loggers_) + { + auto logger_entry = log_levels_.find(logger.first); + if (logger_entry != log_levels_.end()) + { + logger.second->set_level(logger_entry->second); + } + else if (global_level_requested) + { + logger.second->set_level(*global_level); + } + } +} + +SPDLOG_INLINE registry ®istry::instance() +{ + static registry s_instance; + return s_instance; +} + +SPDLOG_INLINE void registry::apply_logger_env_levels(std::shared_ptr new_logger) +{ + std::lock_guard lock(logger_map_mutex_); + auto it = log_levels_.find(new_logger->name()); + auto new_level = it != log_levels_.end() ? it->second : global_log_level_; + new_logger->set_level(new_level); +} + +SPDLOG_INLINE void registry::throw_if_exists_(const std::string &logger_name) +{ + if (loggers_.find(logger_name) != loggers_.end()) + { + throw_spdlog_ex("logger with name '" + logger_name + "' already exists"); + } +} + +SPDLOG_INLINE void registry::register_logger_(std::shared_ptr new_logger) +{ + auto logger_name = new_logger->name(); + throw_if_exists_(logger_name); + loggers_[logger_name] = std::move(new_logger); +} + +} // namespace details +} // namespace spdlog diff --git a/tpl/spdlog/include/spdlog/details/registry.h b/tpl/spdlog/include/spdlog/details/registry.h new file mode 100644 index 0000000..4666fa2 --- /dev/null +++ b/tpl/spdlog/include/spdlog/details/registry.h @@ -0,0 +1,123 @@ +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) + +#pragma once + +// Loggers registry of unique name->logger pointer +// An attempt to create a logger with an already existing name will result with spdlog_ex exception. +// If user requests a non existing logger, nullptr will be returned +// This class is thread safe + +#include +#include + +#include +#include +#include +#include +#include +#include + +namespace spdlog { +class logger; + +namespace details { +class thread_pool; + +class SPDLOG_API registry +{ +public: + using log_levels = std::unordered_map; + registry(const registry &) = delete; + registry &operator=(const registry &) = delete; + + void register_logger(std::shared_ptr new_logger); + void initialize_logger(std::shared_ptr new_logger); + std::shared_ptr get(const std::string &logger_name); + std::shared_ptr default_logger(); + + // Return raw ptr to the default logger. + // To be used directly by the spdlog default api (e.g. spdlog::info) + // This make the default API faster, but cannot be used concurrently with set_default_logger(). + // e.g do not call set_default_logger() from one thread while calling spdlog::info() from another. + logger *get_default_raw(); + + // set default logger. + // default logger is stored in default_logger_ (for faster retrieval) and in the loggers_ map. + void set_default_logger(std::shared_ptr new_default_logger); + + void set_tp(std::shared_ptr tp); + + std::shared_ptr get_tp(); + + // Set global formatter. Each sink in each logger will get a clone of this object + void set_formatter(std::unique_ptr formatter); + + void enable_backtrace(size_t n_messages); + + void disable_backtrace(); + + void set_level(level::level_enum log_level); + + void flush_on(level::level_enum log_level); + + template + void flush_every(std::chrono::duration interval) + { + std::lock_guard lock(flusher_mutex_); + auto clbk = [this]() { this->flush_all(); }; + periodic_flusher_ = details::make_unique(clbk, interval); + } + + void set_error_handler(err_handler handler); + + void apply_all(const std::function)> &fun); + + void flush_all(); + + void drop(const std::string &logger_name); + + void drop_all(); + + // clean all resources and threads started by the registry + void shutdown(); + + std::recursive_mutex &tp_mutex(); + + void set_automatic_registration(bool automatic_registration); + + // set levels for all existing/future loggers. global_level can be null if should not set. + void set_levels(log_levels levels, level::level_enum *global_level); + + static registry &instance(); + + void apply_logger_env_levels(std::shared_ptr new_logger); + +private: + registry(); + ~registry(); + + void throw_if_exists_(const std::string &logger_name); + void register_logger_(std::shared_ptr new_logger); + bool set_level_from_cfg_(logger *logger); + std::mutex logger_map_mutex_, flusher_mutex_; + std::recursive_mutex tp_mutex_; + std::unordered_map> loggers_; + log_levels log_levels_; + std::unique_ptr formatter_; + spdlog::level::level_enum global_log_level_ = level::info; + level::level_enum flush_level_ = level::off; + err_handler err_handler_; + std::shared_ptr tp_; + std::unique_ptr periodic_flusher_; + std::shared_ptr default_logger_; + bool automatic_registration_ = true; + size_t backtrace_n_messages_ = 0; +}; + +} // namespace details +} // namespace spdlog + +#ifdef SPDLOG_HEADER_ONLY +# include "registry-inl.h" +#endif diff --git a/tpl/spdlog/include/spdlog/details/synchronous_factory.h b/tpl/spdlog/include/spdlog/details/synchronous_factory.h new file mode 100644 index 0000000..e1e4226 --- /dev/null +++ b/tpl/spdlog/include/spdlog/details/synchronous_factory.h @@ -0,0 +1,24 @@ +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) + +#pragma once + +#include "registry.h" + +namespace spdlog { + +// Default logger factory- creates synchronous loggers +class logger; + +struct synchronous_factory +{ + template + static std::shared_ptr create(std::string logger_name, SinkArgs &&...args) + { + auto sink = std::make_shared(std::forward(args)...); + auto new_logger = std::make_shared(std::move(logger_name), std::move(sink)); + details::registry::instance().initialize_logger(new_logger); + return new_logger; + } +}; +} // namespace spdlog diff --git a/tpl/spdlog/include/spdlog/details/tcp_client-windows.h b/tpl/spdlog/include/spdlog/details/tcp_client-windows.h new file mode 100644 index 0000000..968b257 --- /dev/null +++ b/tpl/spdlog/include/spdlog/details/tcp_client-windows.h @@ -0,0 +1,160 @@ +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) + +#pragma once + +#define WIN32_LEAN_AND_MEAN +// tcp client helper +#include +#include + +#include +#include +#include +#include +#include +#include + +#pragma comment(lib, "Ws2_32.lib") +#pragma comment(lib, "Mswsock.lib") +#pragma comment(lib, "AdvApi32.lib") + +namespace spdlog { +namespace details { +class tcp_client +{ + SOCKET socket_ = INVALID_SOCKET; + + static void init_winsock_() + { + WSADATA wsaData; + auto rv = WSAStartup(MAKEWORD(2, 2), &wsaData); + if (rv != 0) + { + throw_winsock_error_("WSAStartup failed", ::WSAGetLastError()); + } + } + + static void throw_winsock_error_(const std::string &msg, int last_error) + { + char buf[512]; + ::FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, last_error, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), buf, (sizeof(buf) / sizeof(char)), NULL); + + throw_spdlog_ex(fmt_lib::format("tcp_sink - {}: {}", msg, buf)); + } + +public: + tcp_client() + { + init_winsock_(); + } + + ~tcp_client() + { + close(); + ::WSACleanup(); + } + + bool is_connected() const + { + return socket_ != INVALID_SOCKET; + } + + void close() + { + ::closesocket(socket_); + socket_ = INVALID_SOCKET; + } + + SOCKET fd() const + { + return socket_; + } + + // try to connect or throw on failure + void connect(const std::string &host, int port) + { + if (is_connected()) + { + close(); + } + struct addrinfo hints + {}; + ZeroMemory(&hints, sizeof(hints)); + + hints.ai_family = AF_UNSPEC; // To work with IPv4, IPv6, and so on + hints.ai_socktype = SOCK_STREAM; // TCP + hints.ai_flags = AI_NUMERICSERV; // port passed as as numeric value + hints.ai_protocol = 0; + + auto port_str = std::to_string(port); + struct addrinfo *addrinfo_result; + auto rv = ::getaddrinfo(host.c_str(), port_str.c_str(), &hints, &addrinfo_result); + int last_error = 0; + if (rv != 0) + { + last_error = ::WSAGetLastError(); + WSACleanup(); + throw_winsock_error_("getaddrinfo failed", last_error); + } + + // Try each address until we successfully connect(2). + + for (auto *rp = addrinfo_result; rp != nullptr; rp = rp->ai_next) + { + socket_ = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); + if (socket_ == INVALID_SOCKET) + { + last_error = ::WSAGetLastError(); + WSACleanup(); + continue; + } + if (::connect(socket_, rp->ai_addr, (int)rp->ai_addrlen) == 0) + { + break; + } + else + { + last_error = ::WSAGetLastError(); + close(); + } + } + ::freeaddrinfo(addrinfo_result); + if (socket_ == INVALID_SOCKET) + { + WSACleanup(); + throw_winsock_error_("connect failed", last_error); + } + + // set TCP_NODELAY + int enable_flag = 1; + ::setsockopt(socket_, IPPROTO_TCP, TCP_NODELAY, reinterpret_cast(&enable_flag), sizeof(enable_flag)); + } + + // Send exactly n_bytes of the given data. + // On error close the connection and throw. + void send(const char *data, size_t n_bytes) + { + size_t bytes_sent = 0; + while (bytes_sent < n_bytes) + { + const int send_flags = 0; + auto write_result = ::send(socket_, data + bytes_sent, (int)(n_bytes - bytes_sent), send_flags); + if (write_result == SOCKET_ERROR) + { + int last_error = ::WSAGetLastError(); + close(); + throw_winsock_error_("send failed", last_error); + } + + if (write_result == 0) // (probably should not happen but in any case..) + { + break; + } + bytes_sent += static_cast(write_result); + } + } +}; +} // namespace details +} // namespace spdlog diff --git a/tpl/spdlog/include/spdlog/details/tcp_client.h b/tpl/spdlog/include/spdlog/details/tcp_client.h new file mode 100644 index 0000000..8b11dfd --- /dev/null +++ b/tpl/spdlog/include/spdlog/details/tcp_client.h @@ -0,0 +1,146 @@ +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) + +#pragma once + +#ifdef _WIN32 +# error include tcp_client-windows.h instead +#endif + +// tcp client helper +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +namespace spdlog { +namespace details { +class tcp_client +{ + int socket_ = -1; + +public: + bool is_connected() const + { + return socket_ != -1; + } + + void close() + { + if (is_connected()) + { + ::close(socket_); + socket_ = -1; + } + } + + int fd() const + { + return socket_; + } + + ~tcp_client() + { + close(); + } + + // try to connect or throw on failure + void connect(const std::string &host, int port) + { + close(); + struct addrinfo hints + {}; + memset(&hints, 0, sizeof(struct addrinfo)); + hints.ai_family = AF_UNSPEC; // To work with IPv4, IPv6, and so on + hints.ai_socktype = SOCK_STREAM; // TCP + hints.ai_flags = AI_NUMERICSERV; // port passed as as numeric value + hints.ai_protocol = 0; + + auto port_str = std::to_string(port); + struct addrinfo *addrinfo_result; + auto rv = ::getaddrinfo(host.c_str(), port_str.c_str(), &hints, &addrinfo_result); + if (rv != 0) + { + throw_spdlog_ex(fmt_lib::format("::getaddrinfo failed: {}", gai_strerror(rv))); + } + + // Try each address until we successfully connect(2). + int last_errno = 0; + for (auto *rp = addrinfo_result; rp != nullptr; rp = rp->ai_next) + { +#if defined(SOCK_CLOEXEC) + const int flags = SOCK_CLOEXEC; +#else + const int flags = 0; +#endif + socket_ = ::socket(rp->ai_family, rp->ai_socktype | flags, rp->ai_protocol); + if (socket_ == -1) + { + last_errno = errno; + continue; + } + rv = ::connect(socket_, rp->ai_addr, rp->ai_addrlen); + if (rv == 0) + { + break; + } + last_errno = errno; + ::close(socket_); + socket_ = -1; + } + ::freeaddrinfo(addrinfo_result); + if (socket_ == -1) + { + throw_spdlog_ex("::connect failed", last_errno); + } + + // set TCP_NODELAY + int enable_flag = 1; + ::setsockopt(socket_, IPPROTO_TCP, TCP_NODELAY, reinterpret_cast(&enable_flag), sizeof(enable_flag)); + + // prevent sigpipe on systems where MSG_NOSIGNAL is not available +#if defined(SO_NOSIGPIPE) && !defined(MSG_NOSIGNAL) + ::setsockopt(socket_, SOL_SOCKET, SO_NOSIGPIPE, reinterpret_cast(&enable_flag), sizeof(enable_flag)); +#endif + +#if !defined(SO_NOSIGPIPE) && !defined(MSG_NOSIGNAL) +# error "tcp_sink would raise SIGPIPE since neither SO_NOSIGPIPE nor MSG_NOSIGNAL are available" +#endif + } + + // Send exactly n_bytes of the given data. + // On error close the connection and throw. + void send(const char *data, size_t n_bytes) + { + size_t bytes_sent = 0; + while (bytes_sent < n_bytes) + { +#if defined(MSG_NOSIGNAL) + const int send_flags = MSG_NOSIGNAL; +#else + const int send_flags = 0; +#endif + auto write_result = ::send(socket_, data + bytes_sent, n_bytes - bytes_sent, send_flags); + if (write_result < 0) + { + close(); + throw_spdlog_ex("write(2) failed", errno); + } + + if (write_result == 0) // (probably should not happen but in any case..) + { + break; + } + bytes_sent += static_cast(write_result); + } + } +}; +} // namespace details +} // namespace spdlog diff --git a/tpl/spdlog/include/spdlog/details/thread_pool-inl.h b/tpl/spdlog/include/spdlog/details/thread_pool-inl.h new file mode 100644 index 0000000..dbd424f --- /dev/null +++ b/tpl/spdlog/include/spdlog/details/thread_pool-inl.h @@ -0,0 +1,137 @@ +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) + +#pragma once + +#ifndef SPDLOG_HEADER_ONLY +# include +#endif + +#include +#include + +namespace spdlog { +namespace details { + +SPDLOG_INLINE thread_pool::thread_pool( + size_t q_max_items, size_t threads_n, std::function on_thread_start, std::function on_thread_stop) + : q_(q_max_items) +{ + if (threads_n == 0 || threads_n > 1000) + { + throw_spdlog_ex("spdlog::thread_pool(): invalid threads_n param (valid " + "range is 1-1000)"); + } + for (size_t i = 0; i < threads_n; i++) + { + threads_.emplace_back([this, on_thread_start, on_thread_stop] { + on_thread_start(); + this->thread_pool::worker_loop_(); + on_thread_stop(); + }); + } +} + +SPDLOG_INLINE thread_pool::thread_pool(size_t q_max_items, size_t threads_n, std::function on_thread_start) + : thread_pool(q_max_items, threads_n, on_thread_start, [] {}) +{} + +SPDLOG_INLINE thread_pool::thread_pool(size_t q_max_items, size_t threads_n) + : thread_pool( + q_max_items, threads_n, [] {}, [] {}) +{} + +// message all threads to terminate gracefully join them +SPDLOG_INLINE thread_pool::~thread_pool() +{ + SPDLOG_TRY + { + for (size_t i = 0; i < threads_.size(); i++) + { + post_async_msg_(async_msg(async_msg_type::terminate), async_overflow_policy::block); + } + + for (auto &t : threads_) + { + t.join(); + } + } + SPDLOG_CATCH_STD +} + +void SPDLOG_INLINE thread_pool::post_log(async_logger_ptr &&worker_ptr, const details::log_msg &msg, async_overflow_policy overflow_policy) +{ + async_msg async_m(std::move(worker_ptr), async_msg_type::log, msg); + post_async_msg_(std::move(async_m), overflow_policy); +} + +void SPDLOG_INLINE thread_pool::post_flush(async_logger_ptr &&worker_ptr, async_overflow_policy overflow_policy) +{ + post_async_msg_(async_msg(std::move(worker_ptr), async_msg_type::flush), overflow_policy); +} + +size_t SPDLOG_INLINE thread_pool::overrun_counter() +{ + return q_.overrun_counter(); +} + +void SPDLOG_INLINE thread_pool::reset_overrun_counter() +{ + q_.reset_overrun_counter(); +} + +size_t SPDLOG_INLINE thread_pool::queue_size() +{ + return q_.size(); +} + +void SPDLOG_INLINE thread_pool::post_async_msg_(async_msg &&new_msg, async_overflow_policy overflow_policy) +{ + if (overflow_policy == async_overflow_policy::block) + { + q_.enqueue(std::move(new_msg)); + } + else + { + q_.enqueue_nowait(std::move(new_msg)); + } +} + +void SPDLOG_INLINE thread_pool::worker_loop_() +{ + while (process_next_msg_()) {} +} + +// process next message in the queue +// return true if this thread should still be active (while no terminate msg +// was received) +bool SPDLOG_INLINE thread_pool::process_next_msg_() +{ + async_msg incoming_async_msg; + q_.dequeue(incoming_async_msg); + + switch (incoming_async_msg.msg_type) + { + case async_msg_type::log: { + incoming_async_msg.worker_ptr->backend_sink_it_(incoming_async_msg); + return true; + } + case async_msg_type::flush: { + incoming_async_msg.worker_ptr->backend_flush_(); + return true; + } + + case async_msg_type::terminate: { + return false; + } + + default: { + assert(false); + } + } + + return true; +} + +} // namespace details +} // namespace spdlog diff --git a/tpl/spdlog/include/spdlog/details/thread_pool.h b/tpl/spdlog/include/spdlog/details/thread_pool.h new file mode 100644 index 0000000..52c569b --- /dev/null +++ b/tpl/spdlog/include/spdlog/details/thread_pool.h @@ -0,0 +1,122 @@ +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) + +#pragma once + +#include +#include +#include + +#include +#include +#include +#include +#include + +namespace spdlog { +class async_logger; + +namespace details { + +using async_logger_ptr = std::shared_ptr; + +enum class async_msg_type +{ + log, + flush, + terminate +}; + +// Async msg to move to/from the queue +// Movable only. should never be copied +struct async_msg : log_msg_buffer +{ + async_msg_type msg_type{async_msg_type::log}; + async_logger_ptr worker_ptr; + + async_msg() = default; + ~async_msg() = default; + + // should only be moved in or out of the queue.. + async_msg(const async_msg &) = delete; + +// support for vs2013 move +#if defined(_MSC_VER) && _MSC_VER <= 1800 + async_msg(async_msg &&other) + : log_msg_buffer(std::move(other)) + , msg_type(other.msg_type) + , worker_ptr(std::move(other.worker_ptr)) + {} + + async_msg &operator=(async_msg &&other) + { + *static_cast(this) = std::move(other); + msg_type = other.msg_type; + worker_ptr = std::move(other.worker_ptr); + return *this; + } +#else // (_MSC_VER) && _MSC_VER <= 1800 + async_msg(async_msg &&) = default; + async_msg &operator=(async_msg &&) = default; +#endif + + // construct from log_msg with given type + async_msg(async_logger_ptr &&worker, async_msg_type the_type, const details::log_msg &m) + : log_msg_buffer{m} + , msg_type{the_type} + , worker_ptr{std::move(worker)} + {} + + async_msg(async_logger_ptr &&worker, async_msg_type the_type) + : log_msg_buffer{} + , msg_type{the_type} + , worker_ptr{std::move(worker)} + {} + + explicit async_msg(async_msg_type the_type) + : async_msg{nullptr, the_type} + {} +}; + +class SPDLOG_API thread_pool +{ +public: + using item_type = async_msg; + using q_type = details::mpmc_blocking_queue; + + thread_pool(size_t q_max_items, size_t threads_n, std::function on_thread_start, std::function on_thread_stop); + thread_pool(size_t q_max_items, size_t threads_n, std::function on_thread_start); + thread_pool(size_t q_max_items, size_t threads_n); + + // message all threads to terminate gracefully and join them + ~thread_pool(); + + thread_pool(const thread_pool &) = delete; + thread_pool &operator=(thread_pool &&) = delete; + + void post_log(async_logger_ptr &&worker_ptr, const details::log_msg &msg, async_overflow_policy overflow_policy); + void post_flush(async_logger_ptr &&worker_ptr, async_overflow_policy overflow_policy); + size_t overrun_counter(); + void reset_overrun_counter(); + size_t queue_size(); + +private: + q_type q_; + + std::vector threads_; + + void post_async_msg_(async_msg &&new_msg, async_overflow_policy overflow_policy); + void worker_loop_(); + + // process next message in the queue + // return true if this thread should still be active (while no terminate msg + // was received) + bool process_next_msg_(); +}; + +} // namespace details +} // namespace spdlog + +#ifdef SPDLOG_HEADER_ONLY +# include "thread_pool-inl.h" +#endif diff --git a/tpl/spdlog/include/spdlog/details/udp_client-windows.h b/tpl/spdlog/include/spdlog/details/udp_client-windows.h new file mode 100644 index 0000000..10894ee --- /dev/null +++ b/tpl/spdlog/include/spdlog/details/udp_client-windows.h @@ -0,0 +1,113 @@ +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) + +#pragma once + +// Helper RAII over winsock udp client socket. +// Will throw on construction if socket creation failed. + +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(_MSC_VER) +# pragma comment(lib, "Ws2_32.lib") +# pragma comment(lib, "Mswsock.lib") +# pragma comment(lib, "AdvApi32.lib") +#endif + +namespace spdlog { +namespace details { +class udp_client +{ + static constexpr int TX_BUFFER_SIZE = 1024 * 10; + SOCKET socket_ = INVALID_SOCKET; + sockaddr_in addr_ = {}; + + static void init_winsock_() + { + WSADATA wsaData; + auto rv = ::WSAStartup(MAKEWORD(2, 2), &wsaData); + if (rv != 0) + { + throw_winsock_error_("WSAStartup failed", ::WSAGetLastError()); + } + } + + static void throw_winsock_error_(const std::string &msg, int last_error) + { + char buf[512]; + ::FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, last_error, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), buf, (sizeof(buf) / sizeof(char)), NULL); + + throw_spdlog_ex(fmt_lib::format("udp_sink - {}: {}", msg, buf)); + } + + void cleanup_() + { + if (socket_ != INVALID_SOCKET) + { + ::closesocket(socket_); + } + socket_ = INVALID_SOCKET; + ::WSACleanup(); + } + +public: + udp_client(const std::string &host, uint16_t port) + { + init_winsock_(); + + addr_.sin_family = PF_INET; + addr_.sin_port = htons(port); + addr_.sin_addr.s_addr = INADDR_ANY; + if (InetPtonA(PF_INET, host.c_str(), &addr_.sin_addr.s_addr) != 1) + { + int last_error = ::WSAGetLastError(); + ::WSACleanup(); + throw_winsock_error_("error: Invalid address!", last_error); + } + + socket_ = ::socket(PF_INET, SOCK_DGRAM, 0); + if (socket_ == INVALID_SOCKET) + { + int last_error = ::WSAGetLastError(); + ::WSACleanup(); + throw_winsock_error_("error: Create Socket failed", last_error); + } + + int option_value = TX_BUFFER_SIZE; + if (::setsockopt(socket_, SOL_SOCKET, SO_SNDBUF, reinterpret_cast(&option_value), sizeof(option_value)) < 0) + { + int last_error = ::WSAGetLastError(); + cleanup_(); + throw_winsock_error_("error: setsockopt(SO_SNDBUF) Failed!", last_error); + } + } + + ~udp_client() + { + cleanup_(); + } + + SOCKET fd() const + { + return socket_; + } + + void send(const char *data, size_t n_bytes) + { + socklen_t tolen = sizeof(struct sockaddr); + if (::sendto(socket_, data, static_cast(n_bytes), 0, (struct sockaddr *)&addr_, tolen) == -1) + { + throw_spdlog_ex("sendto(2) failed", errno); + } + } +}; +} // namespace details +} // namespace spdlog diff --git a/tpl/spdlog/include/spdlog/details/udp_client.h b/tpl/spdlog/include/spdlog/details/udp_client.h new file mode 100644 index 0000000..e8c2ccc --- /dev/null +++ b/tpl/spdlog/include/spdlog/details/udp_client.h @@ -0,0 +1,94 @@ +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) + +#pragma once + +// Helper RAII over unix udp client socket. +// Will throw on construction if the socket creation failed. + +#ifdef _WIN32 +# error "include udp_client-windows.h instead" +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace spdlog { +namespace details { + +class udp_client +{ + static constexpr int TX_BUFFER_SIZE = 1024 * 10; + int socket_ = -1; + struct sockaddr_in sockAddr_; + + void cleanup_() + { + if (socket_ != -1) + { + ::close(socket_); + socket_ = -1; + } + } + +public: + udp_client(const std::string &host, uint16_t port) + { + socket_ = ::socket(PF_INET, SOCK_DGRAM, 0); + if (socket_ < 0) + { + throw_spdlog_ex("error: Create Socket Failed!"); + } + + int option_value = TX_BUFFER_SIZE; + if (::setsockopt(socket_, SOL_SOCKET, SO_SNDBUF, reinterpret_cast(&option_value), sizeof(option_value)) < 0) + { + cleanup_(); + throw_spdlog_ex("error: setsockopt(SO_SNDBUF) Failed!"); + } + + sockAddr_.sin_family = AF_INET; + sockAddr_.sin_port = htons(port); + + if (::inet_aton(host.c_str(), &sockAddr_.sin_addr) == 0) + { + cleanup_(); + throw_spdlog_ex("error: Invalid address!"); + } + + ::memset(sockAddr_.sin_zero, 0x00, sizeof(sockAddr_.sin_zero)); + } + + ~udp_client() + { + cleanup_(); + } + + int fd() const + { + return socket_; + } + + // Send exactly n_bytes of the given data. + // On error close the connection and throw. + void send(const char *data, size_t n_bytes) + { + ssize_t toslen = 0; + socklen_t tolen = sizeof(struct sockaddr); + if ((toslen = ::sendto(socket_, data, n_bytes, 0, (struct sockaddr *)&sockAddr_, tolen)) == -1) + { + throw_spdlog_ex("sendto(2) failed", errno); + } + } +}; +} // namespace details +} // namespace spdlog diff --git a/tpl/spdlog/include/spdlog/details/windows_include.h b/tpl/spdlog/include/spdlog/details/windows_include.h new file mode 100644 index 0000000..a92390b --- /dev/null +++ b/tpl/spdlog/include/spdlog/details/windows_include.h @@ -0,0 +1,11 @@ +#pragma once + +#ifndef NOMINMAX +# define NOMINMAX // prevent windows redefining min/max +#endif + +#ifndef WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +#endif + +#include diff --git a/tpl/spdlog/include/spdlog/fmt/bin_to_hex.h b/tpl/spdlog/include/spdlog/fmt/bin_to_hex.h new file mode 100644 index 0000000..3bf003d --- /dev/null +++ b/tpl/spdlog/include/spdlog/fmt/bin_to_hex.h @@ -0,0 +1,248 @@ +// +// Copyright(c) 2015 Gabi Melman. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) +// + +#pragma once + +#include +#include + +#if defined(__has_include) +# if __has_include() +# include +# endif +#endif + +#if __cpp_lib_span >= 202002L +# include +#endif + +// +// Support for logging binary data as hex +// format flags, any combination of the following: +// {:X} - print in uppercase. +// {:s} - don't separate each byte with space. +// {:p} - don't print the position on each line start. +// {:n} - don't split the output to lines. +// {:a} - show ASCII if :n is not set + +// +// Examples: +// +// std::vector v(200, 0x0b); +// logger->info("Some buffer {}", spdlog::to_hex(v)); +// char buf[128]; +// logger->info("Some buffer {:X}", spdlog::to_hex(std::begin(buf), std::end(buf))); +// logger->info("Some buffer {:X}", spdlog::to_hex(std::begin(buf), std::end(buf), 16)); + +namespace spdlog { +namespace details { + +template +class dump_info +{ +public: + dump_info(It range_begin, It range_end, size_t size_per_line) + : begin_(range_begin) + , end_(range_end) + , size_per_line_(size_per_line) + {} + + // do not use begin() and end() to avoid collision with fmt/ranges + It get_begin() const + { + return begin_; + } + It get_end() const + { + return end_; + } + size_t size_per_line() const + { + return size_per_line_; + } + +private: + It begin_, end_; + size_t size_per_line_; +}; +} // namespace details + +// create a dump_info that wraps the given container +template +inline details::dump_info to_hex(const Container &container, size_t size_per_line = 32) +{ + static_assert(sizeof(typename Container::value_type) == 1, "sizeof(Container::value_type) != 1"); + using Iter = typename Container::const_iterator; + return details::dump_info(std::begin(container), std::end(container), size_per_line); +} + +#if __cpp_lib_span >= 202002L + +template +inline details::dump_info::iterator> to_hex( + const std::span &container, size_t size_per_line = 32) +{ + using Container = std::span; + static_assert(sizeof(typename Container::value_type) == 1, "sizeof(Container::value_type) != 1"); + using Iter = typename Container::iterator; + return details::dump_info(std::begin(container), std::end(container), size_per_line); +} + +#endif + +// create dump_info from ranges +template +inline details::dump_info to_hex(const It range_begin, const It range_end, size_t size_per_line = 32) +{ + return details::dump_info(range_begin, range_end, size_per_line); +} + +} // namespace spdlog + +namespace +#ifdef SPDLOG_USE_STD_FORMAT + std +#else + fmt +#endif +{ + +template +struct formatter, char> +{ + const char delimiter = ' '; + bool put_newlines = true; + bool put_delimiters = true; + bool use_uppercase = false; + bool put_positions = true; // position on start of each line + bool show_ascii = false; + + // parse the format string flags + template + SPDLOG_CONSTEXPR_FUNC auto parse(ParseContext &ctx) -> decltype(ctx.begin()) + { + auto it = ctx.begin(); + while (it != ctx.end() && *it != '}') + { + switch (*it) + { + case 'X': + use_uppercase = true; + break; + case 's': + put_delimiters = false; + break; + case 'p': + put_positions = false; + break; + case 'n': + put_newlines = false; + show_ascii = false; + break; + case 'a': + if (put_newlines) + { + show_ascii = true; + } + break; + } + + ++it; + } + return it; + } + + // format the given bytes range as hex + template + auto format(const spdlog::details::dump_info &the_range, FormatContext &ctx) const -> decltype(ctx.out()) + { + SPDLOG_CONSTEXPR const char *hex_upper = "0123456789ABCDEF"; + SPDLOG_CONSTEXPR const char *hex_lower = "0123456789abcdef"; + const char *hex_chars = use_uppercase ? hex_upper : hex_lower; + +#if !defined(SPDLOG_USE_STD_FORMAT) && FMT_VERSION < 60000 + auto inserter = ctx.begin(); +#else + auto inserter = ctx.out(); +#endif + + int size_per_line = static_cast(the_range.size_per_line()); + auto start_of_line = the_range.get_begin(); + for (auto i = the_range.get_begin(); i != the_range.get_end(); i++) + { + auto ch = static_cast(*i); + + if (put_newlines && (i == the_range.get_begin() || i - start_of_line >= size_per_line)) + { + if (show_ascii && i != the_range.get_begin()) + { + *inserter++ = delimiter; + *inserter++ = delimiter; + for (auto j = start_of_line; j < i; j++) + { + auto pc = static_cast(*j); + *inserter++ = std::isprint(pc) ? static_cast(*j) : '.'; + } + } + + put_newline(inserter, static_cast(i - the_range.get_begin())); + + // put first byte without delimiter in front of it + *inserter++ = hex_chars[(ch >> 4) & 0x0f]; + *inserter++ = hex_chars[ch & 0x0f]; + start_of_line = i; + continue; + } + + if (put_delimiters && i != the_range.get_begin()) + { + *inserter++ = delimiter; + } + + *inserter++ = hex_chars[(ch >> 4) & 0x0f]; + *inserter++ = hex_chars[ch & 0x0f]; + } + if (show_ascii) // add ascii to last line + { + if (the_range.get_end() - the_range.get_begin() > size_per_line) + { + auto blank_num = size_per_line - (the_range.get_end() - start_of_line); + while (blank_num-- > 0) + { + *inserter++ = delimiter; + *inserter++ = delimiter; + if (put_delimiters) + { + *inserter++ = delimiter; + } + } + } + *inserter++ = delimiter; + *inserter++ = delimiter; + for (auto j = start_of_line; j != the_range.get_end(); j++) + { + auto pc = static_cast(*j); + *inserter++ = std::isprint(pc) ? static_cast(*j) : '.'; + } + } + return inserter; + } + + // put newline(and position header) + template + void put_newline(It inserter, std::size_t pos) const + { +#ifdef _WIN32 + *inserter++ = '\r'; +#endif + *inserter++ = '\n'; + + if (put_positions) + { + spdlog::fmt_lib::format_to(inserter, SPDLOG_FMT_STRING("{:04X}: "), pos); + } + } +}; +} // namespace std diff --git a/tpl/spdlog/include/spdlog/fmt/chrono.h b/tpl/spdlog/include/spdlog/fmt/chrono.h new file mode 100644 index 0000000..83fad2f --- /dev/null +++ b/tpl/spdlog/include/spdlog/fmt/chrono.h @@ -0,0 +1,22 @@ +// +// Copyright(c) 2016 Gabi Melman. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) +// + +#pragma once +// +// include bundled or external copy of fmtlib's chrono support +// + +#if !defined(SPDLOG_USE_STD_FORMAT) +# if !defined(SPDLOG_FMT_EXTERNAL) +# ifdef SPDLOG_HEADER_ONLY +# ifndef FMT_HEADER_ONLY +# define FMT_HEADER_ONLY +# endif +# endif +# include +# else +# include +# endif +#endif diff --git a/tpl/spdlog/include/spdlog/fmt/compile.h b/tpl/spdlog/include/spdlog/fmt/compile.h new file mode 100644 index 0000000..906e9f5 --- /dev/null +++ b/tpl/spdlog/include/spdlog/fmt/compile.h @@ -0,0 +1,22 @@ +// +// Copyright(c) 2016 Gabi Melman. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) +// + +#pragma once +// +// include bundled or external copy of fmtlib's compile-time support +// + +#if !defined(SPDLOG_USE_STD_FORMAT) +# if !defined(SPDLOG_FMT_EXTERNAL) +# ifdef SPDLOG_HEADER_ONLY +# ifndef FMT_HEADER_ONLY +# define FMT_HEADER_ONLY +# endif +# endif +# include +# else +# include +# endif +#endif diff --git a/tpl/spdlog/include/spdlog/fmt/fmt.h b/tpl/spdlog/include/spdlog/fmt/fmt.h new file mode 100644 index 0000000..a1a8f1c --- /dev/null +++ b/tpl/spdlog/include/spdlog/fmt/fmt.h @@ -0,0 +1,33 @@ +// +// Copyright(c) 2016-2018 Gabi Melman. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) +// + +#pragma once + +// +// Include a bundled header-only copy of fmtlib or an external one. +// By default spdlog include its own copy. +// + +#if defined(SPDLOG_USE_STD_FORMAT) // SPDLOG_USE_STD_FORMAT is defined - use std::format +# include +#elif !defined(SPDLOG_FMT_EXTERNAL) +# if !defined(SPDLOG_COMPILED_LIB) && !defined(FMT_HEADER_ONLY) +# define FMT_HEADER_ONLY +# endif +# ifndef FMT_USE_WINDOWS_H +# define FMT_USE_WINDOWS_H 0 +# endif +// enable the 'n' flag in for backward compatibility with fmt 6.x +# define FMT_DEPRECATED_N_SPECIFIER +// enable ostream formatting for backward compatibility with fmt 8.x +# define FMT_DEPRECATED_OSTREAM + +# include +# include + +#else // SPDLOG_FMT_EXTERNAL is defined - use external fmtlib +# include +# include +#endif diff --git a/tpl/spdlog/include/spdlog/fmt/ostr.h b/tpl/spdlog/include/spdlog/fmt/ostr.h new file mode 100644 index 0000000..7588034 --- /dev/null +++ b/tpl/spdlog/include/spdlog/fmt/ostr.h @@ -0,0 +1,22 @@ +// +// Copyright(c) 2016 Gabi Melman. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) +// + +#pragma once +// +// include bundled or external copy of fmtlib's ostream support +// + +#if !defined(SPDLOG_USE_STD_FORMAT) +# if !defined(SPDLOG_FMT_EXTERNAL) +# ifdef SPDLOG_HEADER_ONLY +# ifndef FMT_HEADER_ONLY +# define FMT_HEADER_ONLY +# endif +# endif +# include +# else +# include +# endif +#endif diff --git a/tpl/spdlog/include/spdlog/fmt/ranges.h b/tpl/spdlog/include/spdlog/fmt/ranges.h new file mode 100644 index 0000000..9103a5f --- /dev/null +++ b/tpl/spdlog/include/spdlog/fmt/ranges.h @@ -0,0 +1,22 @@ +// +// Copyright(c) 2016 Gabi Melman. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) +// + +#pragma once +// +// include bundled or external copy of fmtlib's ranges support +// + +#if !defined(SPDLOG_USE_STD_FORMAT) +# if !defined(SPDLOG_FMT_EXTERNAL) +# ifdef SPDLOG_HEADER_ONLY +# ifndef FMT_HEADER_ONLY +# define FMT_HEADER_ONLY +# endif +# endif +# include +# else +# include +# endif +#endif diff --git a/tpl/spdlog/include/spdlog/fmt/std.h b/tpl/spdlog/include/spdlog/fmt/std.h new file mode 100644 index 0000000..0490cab --- /dev/null +++ b/tpl/spdlog/include/spdlog/fmt/std.h @@ -0,0 +1,23 @@ +// +// Copyright(c) 2016 Gabi Melman. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) +// + +#pragma once +// +// include bundled or external copy of fmtlib's std support (for formatting e.g. std::filesystem::path, std::thread::id, std::monostate, +// std::variant, ...) +// + +#if !defined(SPDLOG_USE_STD_FORMAT) +# if !defined(SPDLOG_FMT_EXTERNAL) +# ifdef SPDLOG_HEADER_ONLY +# ifndef FMT_HEADER_ONLY +# define FMT_HEADER_ONLY +# endif +# endif +# include +# else +# include +# endif +#endif diff --git a/tpl/spdlog/include/spdlog/fmt/xchar.h b/tpl/spdlog/include/spdlog/fmt/xchar.h new file mode 100644 index 0000000..9a766e5 --- /dev/null +++ b/tpl/spdlog/include/spdlog/fmt/xchar.h @@ -0,0 +1,22 @@ +// +// Copyright(c) 2016 Gabi Melman. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) +// + +#pragma once +// +// include bundled or external copy of fmtlib's xchar support +// + +#if !defined(SPDLOG_USE_STD_FORMAT) +# if !defined(SPDLOG_FMT_EXTERNAL) +# ifdef SPDLOG_HEADER_ONLY +# ifndef FMT_HEADER_ONLY +# define FMT_HEADER_ONLY +# endif +# endif +# include +# else +# include +# endif +#endif diff --git a/tpl/spdlog/include/spdlog/formatter.h b/tpl/spdlog/include/spdlog/formatter.h new file mode 100644 index 0000000..5086fb2 --- /dev/null +++ b/tpl/spdlog/include/spdlog/formatter.h @@ -0,0 +1,18 @@ +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) + +#pragma once + +#include +#include + +namespace spdlog { + +class formatter +{ +public: + virtual ~formatter() = default; + virtual void format(const details::log_msg &msg, memory_buf_t &dest) = 0; + virtual std::unique_ptr clone() const = 0; +}; +} // namespace spdlog diff --git a/tpl/spdlog/include/spdlog/fwd.h b/tpl/spdlog/include/spdlog/fwd.h new file mode 100644 index 0000000..d258825 --- /dev/null +++ b/tpl/spdlog/include/spdlog/fwd.h @@ -0,0 +1,18 @@ +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) + +#pragma once + +namespace spdlog { +class logger; +class formatter; + +namespace sinks { +class sink; +} + +namespace level { +enum level_enum : int; +} + +} // namespace spdlog diff --git a/tpl/spdlog/include/spdlog/logger-inl.h b/tpl/spdlog/include/spdlog/logger-inl.h new file mode 100644 index 0000000..227cec4 --- /dev/null +++ b/tpl/spdlog/include/spdlog/logger-inl.h @@ -0,0 +1,257 @@ +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) + +#pragma once + +#ifndef SPDLOG_HEADER_ONLY +# include +#endif + +#include +#include +#include + +#include + +namespace spdlog { + +// public methods +SPDLOG_INLINE logger::logger(const logger &other) + : name_(other.name_) + , sinks_(other.sinks_) + , level_(other.level_.load(std::memory_order_relaxed)) + , flush_level_(other.flush_level_.load(std::memory_order_relaxed)) + , custom_err_handler_(other.custom_err_handler_) + , tracer_(other.tracer_) +{} + +SPDLOG_INLINE logger::logger(logger &&other) SPDLOG_NOEXCEPT : name_(std::move(other.name_)), + sinks_(std::move(other.sinks_)), + level_(other.level_.load(std::memory_order_relaxed)), + flush_level_(other.flush_level_.load(std::memory_order_relaxed)), + custom_err_handler_(std::move(other.custom_err_handler_)), + tracer_(std::move(other.tracer_)) + +{} + +SPDLOG_INLINE logger &logger::operator=(logger other) SPDLOG_NOEXCEPT +{ + this->swap(other); + return *this; +} + +SPDLOG_INLINE void logger::swap(spdlog::logger &other) SPDLOG_NOEXCEPT +{ + name_.swap(other.name_); + sinks_.swap(other.sinks_); + + // swap level_ + auto other_level = other.level_.load(); + auto my_level = level_.exchange(other_level); + other.level_.store(my_level); + + // swap flush level_ + other_level = other.flush_level_.load(); + my_level = flush_level_.exchange(other_level); + other.flush_level_.store(my_level); + + custom_err_handler_.swap(other.custom_err_handler_); + std::swap(tracer_, other.tracer_); +} + +SPDLOG_INLINE void swap(logger &a, logger &b) +{ + a.swap(b); +} + +SPDLOG_INLINE void logger::set_level(level::level_enum log_level) +{ + level_.store(log_level); +} + +SPDLOG_INLINE level::level_enum logger::level() const +{ + return static_cast(level_.load(std::memory_order_relaxed)); +} + +SPDLOG_INLINE const std::string &logger::name() const +{ + return name_; +} + +// set formatting for the sinks in this logger. +// each sink will get a separate instance of the formatter object. +SPDLOG_INLINE void logger::set_formatter(std::unique_ptr f) +{ + for (auto it = sinks_.begin(); it != sinks_.end(); ++it) + { + if (std::next(it) == sinks_.end()) + { + // last element - we can be move it. + (*it)->set_formatter(std::move(f)); + break; // to prevent clang-tidy warning + } + else + { + (*it)->set_formatter(f->clone()); + } + } +} + +SPDLOG_INLINE void logger::set_pattern(std::string pattern, pattern_time_type time_type) +{ + auto new_formatter = details::make_unique(std::move(pattern), time_type); + set_formatter(std::move(new_formatter)); +} + +// create new backtrace sink and move to it all our child sinks +SPDLOG_INLINE void logger::enable_backtrace(size_t n_messages) +{ + tracer_.enable(n_messages); +} + +// restore orig sinks and level and delete the backtrace sink +SPDLOG_INLINE void logger::disable_backtrace() +{ + tracer_.disable(); +} + +SPDLOG_INLINE void logger::dump_backtrace() +{ + dump_backtrace_(); +} + +// flush functions +SPDLOG_INLINE void logger::flush() +{ + flush_(); +} + +SPDLOG_INLINE void logger::flush_on(level::level_enum log_level) +{ + flush_level_.store(log_level); +} + +SPDLOG_INLINE level::level_enum logger::flush_level() const +{ + return static_cast(flush_level_.load(std::memory_order_relaxed)); +} + +// sinks +SPDLOG_INLINE const std::vector &logger::sinks() const +{ + return sinks_; +} + +SPDLOG_INLINE std::vector &logger::sinks() +{ + return sinks_; +} + +// error handler +SPDLOG_INLINE void logger::set_error_handler(err_handler handler) +{ + custom_err_handler_ = std::move(handler); +} + +// create new logger with same sinks and configuration. +SPDLOG_INLINE std::shared_ptr logger::clone(std::string logger_name) +{ + auto cloned = std::make_shared(*this); + cloned->name_ = std::move(logger_name); + return cloned; +} + +// protected methods +SPDLOG_INLINE void logger::log_it_(const spdlog::details::log_msg &log_msg, bool log_enabled, bool traceback_enabled) +{ + if (log_enabled) + { + sink_it_(log_msg); + } + if (traceback_enabled) + { + tracer_.push_back(log_msg); + } +} + +SPDLOG_INLINE void logger::sink_it_(const details::log_msg &msg) +{ + for (auto &sink : sinks_) + { + if (sink->should_log(msg.level)) + { + SPDLOG_TRY + { + sink->log(msg); + } + SPDLOG_LOGGER_CATCH(msg.source) + } + } + + if (should_flush_(msg)) + { + flush_(); + } +} + +SPDLOG_INLINE void logger::flush_() +{ + for (auto &sink : sinks_) + { + SPDLOG_TRY + { + sink->flush(); + } + SPDLOG_LOGGER_CATCH(source_loc()) + } +} + +SPDLOG_INLINE void logger::dump_backtrace_() +{ + using details::log_msg; + if (tracer_.enabled() && !tracer_.empty()) + { + sink_it_(log_msg{name(), level::info, "****************** Backtrace Start ******************"}); + tracer_.foreach_pop([this](const log_msg &msg) { this->sink_it_(msg); }); + sink_it_(log_msg{name(), level::info, "****************** Backtrace End ********************"}); + } +} + +SPDLOG_INLINE bool logger::should_flush_(const details::log_msg &msg) +{ + auto flush_level = flush_level_.load(std::memory_order_relaxed); + return (msg.level >= flush_level) && (msg.level != level::off); +} + +SPDLOG_INLINE void logger::err_handler_(const std::string &msg) +{ + if (custom_err_handler_) + { + custom_err_handler_(msg); + } + else + { + using std::chrono::system_clock; + static std::mutex mutex; + static std::chrono::system_clock::time_point last_report_time; + static size_t err_counter = 0; + std::lock_guard lk{mutex}; + auto now = system_clock::now(); + err_counter++; + if (now - last_report_time < std::chrono::seconds(1)) + { + return; + } + last_report_time = now; + auto tm_time = details::os::localtime(system_clock::to_time_t(now)); + char date_buf[64]; + std::strftime(date_buf, sizeof(date_buf), "%Y-%m-%d %H:%M:%S", &tm_time); +#if defined(USING_R) && defined(R_R_H) // if in R environment + REprintf("[*** LOG ERROR #%04zu ***] [%s] [%s] %s\n", err_counter, date_buf, name().c_str(), msg.c_str()); +#else + std::fprintf(stderr, "[*** LOG ERROR #%04zu ***] [%s] [%s] %s\n", err_counter, date_buf, name().c_str(), msg.c_str()); +#endif + } +} +} // namespace spdlog diff --git a/tpl/spdlog/include/spdlog/logger.h b/tpl/spdlog/include/spdlog/logger.h new file mode 100644 index 0000000..d37af17 --- /dev/null +++ b/tpl/spdlog/include/spdlog/logger.h @@ -0,0 +1,427 @@ +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) + +#pragma once + +// Thread safe logger (except for set_error_handler()) +// 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 and if yes: +// 2. Call the underlying sinks to do the job. +// 3. Each sink use its own private copy of a formatter to format the message +// and send to its destination. +// +// The use of private formatter per sink provides the opportunity to cache some +// formatted data, and support for different format per sink. + +#include +#include +#include + +#ifdef SPDLOG_WCHAR_TO_UTF8_SUPPORT +# ifndef _WIN32 +# error SPDLOG_WCHAR_TO_UTF8_SUPPORT only supported on windows +# endif +# include +#endif + +#include + +#ifndef SPDLOG_NO_EXCEPTIONS +# define SPDLOG_LOGGER_CATCH(location) \ + catch (const std::exception &ex) \ + { \ + if (location.filename) \ + { \ + err_handler_(fmt_lib::format(SPDLOG_FMT_STRING("{} [{}({})]"), ex.what(), location.filename, location.line)); \ + } \ + else \ + { \ + err_handler_(ex.what()); \ + } \ + } \ + catch (...) \ + { \ + err_handler_("Rethrowing unknown exception in logger"); \ + throw; \ + } +#else +# define SPDLOG_LOGGER_CATCH(location) +#endif + +namespace spdlog { + +class SPDLOG_API logger +{ +public: + // Empty logger + explicit logger(std::string name) + : name_(std::move(name)) + , sinks_() + {} + + // Logger with range on sinks + template + logger(std::string name, It begin, It end) + : name_(std::move(name)) + , sinks_(begin, end) + {} + + // Logger with single sink + logger(std::string name, sink_ptr single_sink) + : logger(std::move(name), {std::move(single_sink)}) + {} + + // Logger with sinks init list + logger(std::string name, sinks_init_list sinks) + : logger(std::move(name), sinks.begin(), sinks.end()) + {} + + virtual ~logger() = default; + + logger(const logger &other); + logger(logger &&other) SPDLOG_NOEXCEPT; + logger &operator=(logger other) SPDLOG_NOEXCEPT; + void swap(spdlog::logger &other) SPDLOG_NOEXCEPT; + + template + void log(source_loc loc, level::level_enum lvl, format_string_t fmt, Args &&...args) + { + log_(loc, lvl, details::to_string_view(fmt), std::forward(args)...); + } + + template + void log(level::level_enum lvl, format_string_t fmt, Args &&...args) + { + log(source_loc{}, lvl, fmt, std::forward(args)...); + } + + template + void log(level::level_enum lvl, const T &msg) + { + log(source_loc{}, lvl, msg); + } + + // T cannot be statically converted to format string (including string_view/wstring_view) + template::value, int>::type = 0> + void log(source_loc loc, level::level_enum lvl, const T &msg) + { + log(loc, lvl, "{}", msg); + } + + void log(log_clock::time_point log_time, source_loc loc, level::level_enum lvl, string_view_t msg) + { + bool log_enabled = should_log(lvl); + bool traceback_enabled = tracer_.enabled(); + if (!log_enabled && !traceback_enabled) + { + return; + } + + details::log_msg log_msg(log_time, loc, name_, lvl, msg); + log_it_(log_msg, log_enabled, traceback_enabled); + } + + void log(source_loc loc, level::level_enum lvl, string_view_t msg) + { + bool log_enabled = should_log(lvl); + bool traceback_enabled = tracer_.enabled(); + if (!log_enabled && !traceback_enabled) + { + return; + } + + details::log_msg log_msg(loc, name_, lvl, msg); + log_it_(log_msg, log_enabled, traceback_enabled); + } + + void log(level::level_enum lvl, string_view_t msg) + { + log(source_loc{}, lvl, msg); + } + + template + void trace(format_string_t fmt, Args &&...args) + { + log(level::trace, fmt, std::forward(args)...); + } + + template + void debug(format_string_t fmt, Args &&...args) + { + log(level::debug, fmt, std::forward(args)...); + } + + template + void info(format_string_t fmt, Args &&...args) + { + log(level::info, fmt, std::forward(args)...); + } + + template + void warn(format_string_t fmt, Args &&...args) + { + log(level::warn, fmt, std::forward(args)...); + } + + template + void error(format_string_t fmt, Args &&...args) + { + log(level::err, fmt, std::forward(args)...); + } + + template + void critical(format_string_t fmt, Args &&...args) + { + log(level::critical, fmt, std::forward(args)...); + } + +#ifdef SPDLOG_WCHAR_TO_UTF8_SUPPORT + template + void log(source_loc loc, level::level_enum lvl, wformat_string_t fmt, Args &&...args) + { + log_(loc, lvl, details::to_string_view(fmt), std::forward(args)...); + } + + template + void log(level::level_enum lvl, wformat_string_t fmt, Args &&...args) + { + log(source_loc{}, lvl, fmt, std::forward(args)...); + } + + void log(log_clock::time_point log_time, source_loc loc, level::level_enum lvl, wstring_view_t msg) + { + bool log_enabled = should_log(lvl); + bool traceback_enabled = tracer_.enabled(); + if (!log_enabled && !traceback_enabled) + { + return; + } + + memory_buf_t buf; + details::os::wstr_to_utf8buf(wstring_view_t(msg.data(), msg.size()), buf); + details::log_msg log_msg(log_time, loc, name_, lvl, string_view_t(buf.data(), buf.size())); + log_it_(log_msg, log_enabled, traceback_enabled); + } + + void log(source_loc loc, level::level_enum lvl, wstring_view_t msg) + { + bool log_enabled = should_log(lvl); + bool traceback_enabled = tracer_.enabled(); + if (!log_enabled && !traceback_enabled) + { + return; + } + + memory_buf_t buf; + details::os::wstr_to_utf8buf(wstring_view_t(msg.data(), msg.size()), buf); + details::log_msg log_msg(loc, name_, lvl, string_view_t(buf.data(), buf.size())); + log_it_(log_msg, log_enabled, traceback_enabled); + } + + void log(level::level_enum lvl, wstring_view_t msg) + { + log(source_loc{}, lvl, msg); + } + + template + void trace(wformat_string_t fmt, Args &&...args) + { + log(level::trace, fmt, std::forward(args)...); + } + + template + void debug(wformat_string_t fmt, Args &&...args) + { + log(level::debug, fmt, std::forward(args)...); + } + + template + void info(wformat_string_t fmt, Args &&...args) + { + log(level::info, fmt, std::forward(args)...); + } + + template + void warn(wformat_string_t fmt, Args &&...args) + { + log(level::warn, fmt, std::forward(args)...); + } + + template + void error(wformat_string_t fmt, Args &&...args) + { + log(level::err, fmt, std::forward(args)...); + } + + template + void critical(wformat_string_t fmt, Args &&...args) + { + log(level::critical, fmt, std::forward(args)...); + } +#endif + + template + void trace(const T &msg) + { + log(level::trace, msg); + } + + template + void debug(const T &msg) + { + log(level::debug, msg); + } + + template + void info(const T &msg) + { + log(level::info, msg); + } + + template + void warn(const T &msg) + { + log(level::warn, msg); + } + + template + void error(const T &msg) + { + log(level::err, msg); + } + + template + void critical(const T &msg) + { + log(level::critical, msg); + } + + // return true logging is enabled for the given level. + bool should_log(level::level_enum msg_level) const + { + return msg_level >= level_.load(std::memory_order_relaxed); + } + + // return true if backtrace logging is enabled. + bool should_backtrace() const + { + return tracer_.enabled(); + } + + void set_level(level::level_enum log_level); + + level::level_enum level() const; + + const std::string &name() const; + + // set formatting for the sinks in this logger. + // each sink will get a separate instance of the formatter object. + void set_formatter(std::unique_ptr f); + + // set formatting for the sinks in this logger. + // equivalent to + // set_formatter(make_unique(pattern, time_type)) + // Note: each sink will get a new instance of a formatter object, replacing the old one. + void set_pattern(std::string pattern, pattern_time_type time_type = pattern_time_type::local); + + // backtrace support. + // efficiently store all debug/trace messages in a circular buffer until needed for debugging. + void enable_backtrace(size_t n_messages); + void disable_backtrace(); + void dump_backtrace(); + + // flush functions + void flush(); + void flush_on(level::level_enum log_level); + level::level_enum flush_level() const; + + // sinks + const std::vector &sinks() const; + + std::vector &sinks(); + + // error handler + void set_error_handler(err_handler); + + // create new logger with same sinks and configuration. + virtual std::shared_ptr clone(std::string logger_name); + +protected: + std::string name_; + std::vector sinks_; + spdlog::level_t level_{level::info}; + spdlog::level_t flush_level_{level::off}; + err_handler custom_err_handler_{nullptr}; + details::backtracer tracer_; + + // common implementation for after templated public api has been resolved + template + void log_(source_loc loc, level::level_enum lvl, string_view_t fmt, Args &&...args) + { + bool log_enabled = should_log(lvl); + bool traceback_enabled = tracer_.enabled(); + if (!log_enabled && !traceback_enabled) + { + return; + } + SPDLOG_TRY + { + memory_buf_t buf; +#ifdef SPDLOG_USE_STD_FORMAT + fmt_lib::vformat_to(std::back_inserter(buf), fmt, fmt_lib::make_format_args(args...)); +#else + fmt::vformat_to(std::back_inserter(buf), fmt, fmt::make_format_args(args...)); +#endif + + details::log_msg log_msg(loc, name_, lvl, string_view_t(buf.data(), buf.size())); + log_it_(log_msg, log_enabled, traceback_enabled); + } + SPDLOG_LOGGER_CATCH(loc) + } + +#ifdef SPDLOG_WCHAR_TO_UTF8_SUPPORT + template + void log_(source_loc loc, level::level_enum lvl, wstring_view_t fmt, Args &&...args) + { + bool log_enabled = should_log(lvl); + bool traceback_enabled = tracer_.enabled(); + if (!log_enabled && !traceback_enabled) + { + return; + } + SPDLOG_TRY + { + // format to wmemory_buffer and convert to utf8 + wmemory_buf_t wbuf; + fmt_lib::vformat_to(std::back_inserter(wbuf), fmt, fmt_lib::make_format_args(args...)); + + memory_buf_t buf; + details::os::wstr_to_utf8buf(wstring_view_t(wbuf.data(), wbuf.size()), buf); + details::log_msg log_msg(loc, name_, lvl, string_view_t(buf.data(), buf.size())); + log_it_(log_msg, log_enabled, traceback_enabled); + } + SPDLOG_LOGGER_CATCH(loc) + } +#endif // SPDLOG_WCHAR_TO_UTF8_SUPPORT + + // log the given message (if the given log level is high enough), + // and save backtrace (if backtrace is enabled). + void log_it_(const details::log_msg &log_msg, bool log_enabled, bool traceback_enabled); + virtual void sink_it_(const details::log_msg &msg); + virtual void flush_(); + void dump_backtrace_(); + bool should_flush_(const details::log_msg &msg); + + // handle errors during logging. + // default handler prints the error to stderr at max rate of 1 message/sec. + void err_handler_(const std::string &msg); +}; + +void swap(logger &a, logger &b); + +} // namespace spdlog + +#ifdef SPDLOG_HEADER_ONLY +# include "logger-inl.h" +#endif diff --git a/tpl/spdlog/include/spdlog/pattern_formatter-inl.h b/tpl/spdlog/include/spdlog/pattern_formatter-inl.h new file mode 100644 index 0000000..01afbe6 --- /dev/null +++ b/tpl/spdlog/include/spdlog/pattern_formatter-inl.h @@ -0,0 +1,1436 @@ +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) + +#pragma once + +#ifndef SPDLOG_HEADER_ONLY +# include +#endif + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace spdlog { +namespace details { + +/////////////////////////////////////////////////////////////////////// +// name & level pattern appender +/////////////////////////////////////////////////////////////////////// + +class scoped_padder +{ +public: + scoped_padder(size_t wrapped_size, const padding_info &padinfo, memory_buf_t &dest) + : padinfo_(padinfo) + , dest_(dest) + { + remaining_pad_ = static_cast(padinfo.width_) - static_cast(wrapped_size); + if (remaining_pad_ <= 0) + { + return; + } + + if (padinfo_.side_ == padding_info::pad_side::left) + { + pad_it(remaining_pad_); + remaining_pad_ = 0; + } + else if (padinfo_.side_ == padding_info::pad_side::center) + { + auto half_pad = remaining_pad_ / 2; + auto reminder = remaining_pad_ & 1; + pad_it(half_pad); + remaining_pad_ = half_pad + reminder; // for the right side + } + } + + template + static unsigned int count_digits(T n) + { + return fmt_helper::count_digits(n); + } + + ~scoped_padder() + { + if (remaining_pad_ >= 0) + { + pad_it(remaining_pad_); + } + else if (padinfo_.truncate_) + { + long new_size = static_cast(dest_.size()) + remaining_pad_; + dest_.resize(static_cast(new_size)); + } + } + +private: + void pad_it(long count) + { + fmt_helper::append_string_view(string_view_t(spaces_.data(), static_cast(count)), dest_); + } + + const padding_info &padinfo_; + memory_buf_t &dest_; + long remaining_pad_; + string_view_t spaces_{" ", 64}; +}; + +struct null_scoped_padder +{ + null_scoped_padder(size_t /*wrapped_size*/, const padding_info & /*padinfo*/, memory_buf_t & /*dest*/) {} + + template + static unsigned int count_digits(T /* number */) + { + return 0; + } +}; + +template +class name_formatter final : public flag_formatter +{ +public: + explicit name_formatter(padding_info padinfo) + : flag_formatter(padinfo) + {} + + void format(const details::log_msg &msg, const std::tm &, memory_buf_t &dest) override + { + ScopedPadder p(msg.logger_name.size(), padinfo_, dest); + fmt_helper::append_string_view(msg.logger_name, dest); + } +}; + +// log level appender +template +class level_formatter final : public flag_formatter +{ +public: + explicit level_formatter(padding_info padinfo) + : flag_formatter(padinfo) + {} + + void format(const details::log_msg &msg, const std::tm &, memory_buf_t &dest) override + { + const string_view_t &level_name = level::to_string_view(msg.level); + ScopedPadder p(level_name.size(), padinfo_, dest); + fmt_helper::append_string_view(level_name, dest); + } +}; + +// short log level appender +template +class short_level_formatter final : public flag_formatter +{ +public: + explicit short_level_formatter(padding_info padinfo) + : flag_formatter(padinfo) + {} + + void format(const details::log_msg &msg, const std::tm &, memory_buf_t &dest) override + { + string_view_t level_name{level::to_short_c_str(msg.level)}; + ScopedPadder p(level_name.size(), padinfo_, dest); + fmt_helper::append_string_view(level_name, dest); + } +}; + +/////////////////////////////////////////////////////////////////////// +// 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 std::array days{{"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"}}; + +template +class a_formatter final : public flag_formatter +{ +public: + explicit a_formatter(padding_info padinfo) + : flag_formatter(padinfo) + {} + + void format(const details::log_msg &, const std::tm &tm_time, memory_buf_t &dest) override + { + string_view_t field_value{days[static_cast(tm_time.tm_wday)]}; + ScopedPadder p(field_value.size(), padinfo_, dest); + fmt_helper::append_string_view(field_value, dest); + } +}; + +// Full weekday name +static std::array full_days{{"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"}}; + +template +class A_formatter : public flag_formatter +{ +public: + explicit A_formatter(padding_info padinfo) + : flag_formatter(padinfo) + {} + + void format(const details::log_msg &, const std::tm &tm_time, memory_buf_t &dest) override + { + string_view_t field_value{full_days[static_cast(tm_time.tm_wday)]}; + ScopedPadder p(field_value.size(), padinfo_, dest); + fmt_helper::append_string_view(field_value, dest); + } +}; + +// Abbreviated month +static const std::array months{{"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sept", "Oct", "Nov", "Dec"}}; + +template +class b_formatter final : public flag_formatter +{ +public: + explicit b_formatter(padding_info padinfo) + : flag_formatter(padinfo) + {} + + void format(const details::log_msg &, const std::tm &tm_time, memory_buf_t &dest) override + { + string_view_t field_value{months[static_cast(tm_time.tm_mon)]}; + ScopedPadder p(field_value.size(), padinfo_, dest); + fmt_helper::append_string_view(field_value, dest); + } +}; + +// Full month name +static const std::array full_months{ + {"January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"}}; + +template +class B_formatter final : public flag_formatter +{ +public: + explicit B_formatter(padding_info padinfo) + : flag_formatter(padinfo) + {} + + void format(const details::log_msg &, const std::tm &tm_time, memory_buf_t &dest) override + { + string_view_t field_value{full_months[static_cast(tm_time.tm_mon)]}; + ScopedPadder p(field_value.size(), padinfo_, dest); + fmt_helper::append_string_view(field_value, dest); + } +}; + +// Date and time representation (Thu Aug 23 15:35:46 2014) +template +class c_formatter final : public flag_formatter +{ +public: + explicit c_formatter(padding_info padinfo) + : flag_formatter(padinfo) + {} + + void format(const details::log_msg &, const std::tm &tm_time, memory_buf_t &dest) override + { + const size_t field_size = 24; + ScopedPadder p(field_size, padinfo_, dest); + + fmt_helper::append_string_view(days[static_cast(tm_time.tm_wday)], dest); + dest.push_back(' '); + fmt_helper::append_string_view(months[static_cast(tm_time.tm_mon)], dest); + dest.push_back(' '); + fmt_helper::append_int(tm_time.tm_mday, dest); + dest.push_back(' '); + // time + + fmt_helper::pad2(tm_time.tm_hour, dest); + dest.push_back(':'); + fmt_helper::pad2(tm_time.tm_min, dest); + dest.push_back(':'); + fmt_helper::pad2(tm_time.tm_sec, dest); + dest.push_back(' '); + fmt_helper::append_int(tm_time.tm_year + 1900, dest); + } +}; + +// year - 2 digit +template +class C_formatter final : public flag_formatter +{ +public: + explicit C_formatter(padding_info padinfo) + : flag_formatter(padinfo) + {} + + void format(const details::log_msg &, const std::tm &tm_time, memory_buf_t &dest) override + { + const size_t field_size = 2; + ScopedPadder p(field_size, padinfo_, dest); + fmt_helper::pad2(tm_time.tm_year % 100, dest); + } +}; + +// Short MM/DD/YY date, equivalent to %m/%d/%y 08/23/01 +template +class D_formatter final : public flag_formatter +{ +public: + explicit D_formatter(padding_info padinfo) + : flag_formatter(padinfo) + {} + + void format(const details::log_msg &, const std::tm &tm_time, memory_buf_t &dest) override + { + const size_t field_size = 10; + ScopedPadder p(field_size, padinfo_, dest); + + fmt_helper::pad2(tm_time.tm_mon + 1, dest); + dest.push_back('/'); + fmt_helper::pad2(tm_time.tm_mday, dest); + dest.push_back('/'); + fmt_helper::pad2(tm_time.tm_year % 100, dest); + } +}; + +// year - 4 digit +template +class Y_formatter final : public flag_formatter +{ +public: + explicit Y_formatter(padding_info padinfo) + : flag_formatter(padinfo) + {} + + void format(const details::log_msg &, const std::tm &tm_time, memory_buf_t &dest) override + { + const size_t field_size = 4; + ScopedPadder p(field_size, padinfo_, dest); + fmt_helper::append_int(tm_time.tm_year + 1900, dest); + } +}; + +// month 1-12 +template +class m_formatter final : public flag_formatter +{ +public: + explicit m_formatter(padding_info padinfo) + : flag_formatter(padinfo) + {} + + void format(const details::log_msg &, const std::tm &tm_time, memory_buf_t &dest) override + { + const size_t field_size = 2; + ScopedPadder p(field_size, padinfo_, dest); + fmt_helper::pad2(tm_time.tm_mon + 1, dest); + } +}; + +// day of month 1-31 +template +class d_formatter final : public flag_formatter +{ +public: + explicit d_formatter(padding_info padinfo) + : flag_formatter(padinfo) + {} + + void format(const details::log_msg &, const std::tm &tm_time, memory_buf_t &dest) override + { + const size_t field_size = 2; + ScopedPadder p(field_size, padinfo_, dest); + fmt_helper::pad2(tm_time.tm_mday, dest); + } +}; + +// hours in 24 format 0-23 +template +class H_formatter final : public flag_formatter +{ +public: + explicit H_formatter(padding_info padinfo) + : flag_formatter(padinfo) + {} + + void format(const details::log_msg &, const std::tm &tm_time, memory_buf_t &dest) override + { + const size_t field_size = 2; + ScopedPadder p(field_size, padinfo_, dest); + fmt_helper::pad2(tm_time.tm_hour, dest); + } +}; + +// hours in 12 format 1-12 +template +class I_formatter final : public flag_formatter +{ +public: + explicit I_formatter(padding_info padinfo) + : flag_formatter(padinfo) + {} + + void format(const details::log_msg &, const std::tm &tm_time, memory_buf_t &dest) override + { + const size_t field_size = 2; + ScopedPadder p(field_size, padinfo_, dest); + fmt_helper::pad2(to12h(tm_time), dest); + } +}; + +// minutes 0-59 +template +class M_formatter final : public flag_formatter +{ +public: + explicit M_formatter(padding_info padinfo) + : flag_formatter(padinfo) + {} + + void format(const details::log_msg &, const std::tm &tm_time, memory_buf_t &dest) override + { + const size_t field_size = 2; + ScopedPadder p(field_size, padinfo_, dest); + fmt_helper::pad2(tm_time.tm_min, dest); + } +}; + +// seconds 0-59 +template +class S_formatter final : public flag_formatter +{ +public: + explicit S_formatter(padding_info padinfo) + : flag_formatter(padinfo) + {} + + void format(const details::log_msg &, const std::tm &tm_time, memory_buf_t &dest) override + { + const size_t field_size = 2; + ScopedPadder p(field_size, padinfo_, dest); + fmt_helper::pad2(tm_time.tm_sec, dest); + } +}; + +// milliseconds +template +class e_formatter final : public flag_formatter +{ +public: + explicit e_formatter(padding_info padinfo) + : flag_formatter(padinfo) + {} + + void format(const details::log_msg &msg, const std::tm &, memory_buf_t &dest) override + { + auto millis = fmt_helper::time_fraction(msg.time); + const size_t field_size = 3; + ScopedPadder p(field_size, padinfo_, dest); + fmt_helper::pad3(static_cast(millis.count()), dest); + } +}; + +// microseconds +template +class f_formatter final : public flag_formatter +{ +public: + explicit f_formatter(padding_info padinfo) + : flag_formatter(padinfo) + {} + + void format(const details::log_msg &msg, const std::tm &, memory_buf_t &dest) override + { + auto micros = fmt_helper::time_fraction(msg.time); + + const size_t field_size = 6; + ScopedPadder p(field_size, padinfo_, dest); + fmt_helper::pad6(static_cast(micros.count()), dest); + } +}; + +// nanoseconds +template +class F_formatter final : public flag_formatter +{ +public: + explicit F_formatter(padding_info padinfo) + : flag_formatter(padinfo) + {} + + void format(const details::log_msg &msg, const std::tm &, memory_buf_t &dest) override + { + auto ns = fmt_helper::time_fraction(msg.time); + const size_t field_size = 9; + ScopedPadder p(field_size, padinfo_, dest); + fmt_helper::pad9(static_cast(ns.count()), dest); + } +}; + +// seconds since epoch +template +class E_formatter final : public flag_formatter +{ +public: + explicit E_formatter(padding_info padinfo) + : flag_formatter(padinfo) + {} + + void format(const details::log_msg &msg, const std::tm &, memory_buf_t &dest) override + { + const size_t field_size = 10; + ScopedPadder p(field_size, padinfo_, dest); + auto duration = msg.time.time_since_epoch(); + auto seconds = std::chrono::duration_cast(duration).count(); + fmt_helper::append_int(seconds, dest); + } +}; + +// AM/PM +template +class p_formatter final : public flag_formatter +{ +public: + explicit p_formatter(padding_info padinfo) + : flag_formatter(padinfo) + {} + + void format(const details::log_msg &, const std::tm &tm_time, memory_buf_t &dest) override + { + const size_t field_size = 2; + ScopedPadder p(field_size, padinfo_, dest); + fmt_helper::append_string_view(ampm(tm_time), dest); + } +}; + +// 12 hour clock 02:55:02 pm +template +class r_formatter final : public flag_formatter +{ +public: + explicit r_formatter(padding_info padinfo) + : flag_formatter(padinfo) + {} + + void format(const details::log_msg &, const std::tm &tm_time, memory_buf_t &dest) override + { + const size_t field_size = 11; + ScopedPadder p(field_size, padinfo_, dest); + + fmt_helper::pad2(to12h(tm_time), dest); + dest.push_back(':'); + fmt_helper::pad2(tm_time.tm_min, dest); + dest.push_back(':'); + fmt_helper::pad2(tm_time.tm_sec, dest); + dest.push_back(' '); + fmt_helper::append_string_view(ampm(tm_time), dest); + } +}; + +// 24-hour HH:MM time, equivalent to %H:%M +template +class R_formatter final : public flag_formatter +{ +public: + explicit R_formatter(padding_info padinfo) + : flag_formatter(padinfo) + {} + + void format(const details::log_msg &, const std::tm &tm_time, memory_buf_t &dest) override + { + const size_t field_size = 5; + ScopedPadder p(field_size, padinfo_, dest); + + fmt_helper::pad2(tm_time.tm_hour, dest); + dest.push_back(':'); + fmt_helper::pad2(tm_time.tm_min, dest); + } +}; + +// ISO 8601 time format (HH:MM:SS), equivalent to %H:%M:%S +template +class T_formatter final : public flag_formatter +{ +public: + explicit T_formatter(padding_info padinfo) + : flag_formatter(padinfo) + {} + + void format(const details::log_msg &, const std::tm &tm_time, memory_buf_t &dest) override + { + const size_t field_size = 8; + ScopedPadder p(field_size, padinfo_, dest); + + fmt_helper::pad2(tm_time.tm_hour, dest); + dest.push_back(':'); + fmt_helper::pad2(tm_time.tm_min, dest); + dest.push_back(':'); + fmt_helper::pad2(tm_time.tm_sec, dest); + } +}; + +// ISO 8601 offset from UTC in timezone (+-HH:MM) +template +class z_formatter final : public flag_formatter +{ +public: + explicit z_formatter(padding_info padinfo) + : flag_formatter(padinfo) + {} + + z_formatter() = default; + z_formatter(const z_formatter &) = delete; + z_formatter &operator=(const z_formatter &) = delete; + + void format(const details::log_msg &msg, const std::tm &tm_time, memory_buf_t &dest) override + { + const size_t field_size = 6; + ScopedPadder p(field_size, padinfo_, dest); + + auto total_minutes = get_cached_offset(msg, tm_time); + bool is_negative = total_minutes < 0; + if (is_negative) + { + total_minutes = -total_minutes; + dest.push_back('-'); + } + else + { + dest.push_back('+'); + } + + fmt_helper::pad2(total_minutes / 60, dest); // hours + dest.push_back(':'); + fmt_helper::pad2(total_minutes % 60, dest); // minutes + } + +private: + log_clock::time_point last_update_{std::chrono::seconds(0)}; + int offset_minutes_{0}; + + int get_cached_offset(const log_msg &msg, const std::tm &tm_time) + { + // refresh every 10 seconds + if (msg.time - last_update_ >= std::chrono::seconds(10)) + { + offset_minutes_ = os::utc_minutes_offset(tm_time); + last_update_ = msg.time; + } + return offset_minutes_; + } +}; + +// Thread id +template +class t_formatter final : public flag_formatter +{ +public: + explicit t_formatter(padding_info padinfo) + : flag_formatter(padinfo) + {} + + void format(const details::log_msg &msg, const std::tm &, memory_buf_t &dest) override + { + const auto field_size = ScopedPadder::count_digits(msg.thread_id); + ScopedPadder p(field_size, padinfo_, dest); + fmt_helper::append_int(msg.thread_id, dest); + } +}; + +// Current pid +template +class pid_formatter final : public flag_formatter +{ +public: + explicit pid_formatter(padding_info padinfo) + : flag_formatter(padinfo) + {} + + void format(const details::log_msg &, const std::tm &, memory_buf_t &dest) override + { + const auto pid = static_cast(details::os::pid()); + auto field_size = ScopedPadder::count_digits(pid); + ScopedPadder p(field_size, padinfo_, dest); + fmt_helper::append_int(pid, dest); + } +}; + +template +class v_formatter final : public flag_formatter +{ +public: + explicit v_formatter(padding_info padinfo) + : flag_formatter(padinfo) + {} + + void format(const details::log_msg &msg, const std::tm &, memory_buf_t &dest) override + { + ScopedPadder p(msg.payload.size(), padinfo_, dest); + fmt_helper::append_string_view(msg.payload, dest); + } +}; + +class ch_formatter final : public flag_formatter +{ +public: + explicit ch_formatter(char ch) + : ch_(ch) + {} + + void format(const details::log_msg &, const std::tm &, memory_buf_t &dest) override + { + dest.push_back(ch_); + } + +private: + char ch_; +}; + +// aggregate user chars to display as is +class aggregate_formatter final : public flag_formatter +{ +public: + aggregate_formatter() = default; + + void add_ch(char ch) + { + str_ += ch; + } + void format(const details::log_msg &, const std::tm &, memory_buf_t &dest) override + { + fmt_helper::append_string_view(str_, dest); + } + +private: + std::string str_; +}; + +// mark the color range. expect it to be in the form of "%^colored text%$" +class color_start_formatter final : public flag_formatter +{ +public: + explicit color_start_formatter(padding_info padinfo) + : flag_formatter(padinfo) + {} + + void format(const details::log_msg &msg, const std::tm &, memory_buf_t &dest) override + { + msg.color_range_start = dest.size(); + } +}; + +class color_stop_formatter final : public flag_formatter +{ +public: + explicit color_stop_formatter(padding_info padinfo) + : flag_formatter(padinfo) + {} + + void format(const details::log_msg &msg, const std::tm &, memory_buf_t &dest) override + { + msg.color_range_end = dest.size(); + } +}; + +// print source location +template +class source_location_formatter final : public flag_formatter +{ +public: + explicit source_location_formatter(padding_info padinfo) + : flag_formatter(padinfo) + {} + + void format(const details::log_msg &msg, const std::tm &, memory_buf_t &dest) override + { + if (msg.source.empty()) + { + ScopedPadder p(0, padinfo_, dest); + return; + } + + size_t text_size; + if (padinfo_.enabled()) + { + // calc text size for padding based on "filename:line" + text_size = std::char_traits::length(msg.source.filename) + ScopedPadder::count_digits(msg.source.line) + 1; + } + else + { + text_size = 0; + } + + ScopedPadder p(text_size, padinfo_, dest); + fmt_helper::append_string_view(msg.source.filename, dest); + dest.push_back(':'); + fmt_helper::append_int(msg.source.line, dest); + } +}; + +// print source filename +template +class source_filename_formatter final : public flag_formatter +{ +public: + explicit source_filename_formatter(padding_info padinfo) + : flag_formatter(padinfo) + {} + + void format(const details::log_msg &msg, const std::tm &, memory_buf_t &dest) override + { + if (msg.source.empty()) + { + ScopedPadder p(0, padinfo_, dest); + return; + } + size_t text_size = padinfo_.enabled() ? std::char_traits::length(msg.source.filename) : 0; + ScopedPadder p(text_size, padinfo_, dest); + fmt_helper::append_string_view(msg.source.filename, dest); + } +}; + +template +class short_filename_formatter final : public flag_formatter +{ +public: + explicit short_filename_formatter(padding_info padinfo) + : flag_formatter(padinfo) + {} + +#ifdef _MSC_VER +# pragma warning(push) +# pragma warning(disable : 4127) // consider using 'if constexpr' instead +#endif // _MSC_VER + static const char *basename(const char *filename) + { + // if the size is 2 (1 character + null terminator) we can use the more efficient strrchr + // the branch will be elided by optimizations + if (sizeof(os::folder_seps) == 2) + { + const char *rv = std::strrchr(filename, os::folder_seps[0]); + return rv != nullptr ? rv + 1 : filename; + } + else + { + const std::reverse_iterator begin(filename + std::strlen(filename)); + const std::reverse_iterator end(filename); + + const auto it = std::find_first_of(begin, end, std::begin(os::folder_seps), std::end(os::folder_seps) - 1); + return it != end ? it.base() : filename; + } + } +#ifdef _MSC_VER +# pragma warning(pop) +#endif // _MSC_VER + + void format(const details::log_msg &msg, const std::tm &, memory_buf_t &dest) override + { + if (msg.source.empty()) + { + ScopedPadder p(0, padinfo_, dest); + return; + } + auto filename = basename(msg.source.filename); + size_t text_size = padinfo_.enabled() ? std::char_traits::length(filename) : 0; + ScopedPadder p(text_size, padinfo_, dest); + fmt_helper::append_string_view(filename, dest); + } +}; + +template +class source_linenum_formatter final : public flag_formatter +{ +public: + explicit source_linenum_formatter(padding_info padinfo) + : flag_formatter(padinfo) + {} + + void format(const details::log_msg &msg, const std::tm &, memory_buf_t &dest) override + { + if (msg.source.empty()) + { + ScopedPadder p(0, padinfo_, dest); + return; + } + + auto field_size = ScopedPadder::count_digits(msg.source.line); + ScopedPadder p(field_size, padinfo_, dest); + fmt_helper::append_int(msg.source.line, dest); + } +}; + +// print source funcname +template +class source_funcname_formatter final : public flag_formatter +{ +public: + explicit source_funcname_formatter(padding_info padinfo) + : flag_formatter(padinfo) + {} + + void format(const details::log_msg &msg, const std::tm &, memory_buf_t &dest) override + { + if (msg.source.empty()) + { + ScopedPadder p(0, padinfo_, dest); + return; + } + size_t text_size = padinfo_.enabled() ? std::char_traits::length(msg.source.funcname) : 0; + ScopedPadder p(text_size, padinfo_, dest); + fmt_helper::append_string_view(msg.source.funcname, dest); + } +}; + +// print elapsed time since last message +template +class elapsed_formatter final : public flag_formatter +{ +public: + using DurationUnits = Units; + + explicit elapsed_formatter(padding_info padinfo) + : flag_formatter(padinfo) + , last_message_time_(log_clock::now()) + {} + + void format(const details::log_msg &msg, const std::tm &, memory_buf_t &dest) override + { + auto delta = (std::max)(msg.time - last_message_time_, log_clock::duration::zero()); + auto delta_units = std::chrono::duration_cast(delta); + last_message_time_ = msg.time; + auto delta_count = static_cast(delta_units.count()); + auto n_digits = static_cast(ScopedPadder::count_digits(delta_count)); + ScopedPadder p(n_digits, padinfo_, dest); + fmt_helper::append_int(delta_count, dest); + } + +private: + log_clock::time_point last_message_time_; +}; + +// Full info formatter +// pattern: [%Y-%m-%d %H:%M:%S.%e] [%n] [%l] [%s:%#] %v +class full_formatter final : public flag_formatter +{ +public: + explicit full_formatter(padding_info padinfo) + : flag_formatter(padinfo) + {} + + void format(const details::log_msg &msg, const std::tm &tm_time, memory_buf_t &dest) override + { + using std::chrono::duration_cast; + using std::chrono::milliseconds; + using std::chrono::seconds; + + // cache the date/time part for the next second. + auto duration = msg.time.time_since_epoch(); + auto secs = duration_cast(duration); + + if (cache_timestamp_ != secs || cached_datetime_.size() == 0) + { + cached_datetime_.clear(); + cached_datetime_.push_back('['); + fmt_helper::append_int(tm_time.tm_year + 1900, cached_datetime_); + cached_datetime_.push_back('-'); + + fmt_helper::pad2(tm_time.tm_mon + 1, cached_datetime_); + cached_datetime_.push_back('-'); + + fmt_helper::pad2(tm_time.tm_mday, cached_datetime_); + cached_datetime_.push_back(' '); + + fmt_helper::pad2(tm_time.tm_hour, cached_datetime_); + cached_datetime_.push_back(':'); + + fmt_helper::pad2(tm_time.tm_min, cached_datetime_); + cached_datetime_.push_back(':'); + + fmt_helper::pad2(tm_time.tm_sec, cached_datetime_); + cached_datetime_.push_back('.'); + + cache_timestamp_ = secs; + } + dest.append(cached_datetime_.begin(), cached_datetime_.end()); + + auto millis = fmt_helper::time_fraction(msg.time); + fmt_helper::pad3(static_cast(millis.count()), dest); + dest.push_back(']'); + dest.push_back(' '); + + // append logger name if exists + if (msg.logger_name.size() > 0) + { + dest.push_back('['); + fmt_helper::append_string_view(msg.logger_name, dest); + dest.push_back(']'); + dest.push_back(' '); + } + + dest.push_back('['); + // wrap the level name with color + msg.color_range_start = dest.size(); + // fmt_helper::append_string_view(level::to_c_str(msg.level), dest); + fmt_helper::append_string_view(level::to_string_view(msg.level), dest); + msg.color_range_end = dest.size(); + dest.push_back(']'); + dest.push_back(' '); + + // add source location if present + if (!msg.source.empty()) + { + dest.push_back('['); + const char *filename = details::short_filename_formatter::basename(msg.source.filename); + fmt_helper::append_string_view(filename, dest); + dest.push_back(':'); + fmt_helper::append_int(msg.source.line, dest); + dest.push_back(']'); + dest.push_back(' '); + } + // fmt_helper::append_string_view(msg.msg(), dest); + fmt_helper::append_string_view(msg.payload, dest); + } + +private: + std::chrono::seconds cache_timestamp_{0}; + memory_buf_t cached_datetime_; +}; + +} // namespace details + +SPDLOG_INLINE pattern_formatter::pattern_formatter( + std::string pattern, pattern_time_type time_type, std::string eol, custom_flags custom_user_flags) + : pattern_(std::move(pattern)) + , eol_(std::move(eol)) + , pattern_time_type_(time_type) + , need_localtime_(false) + , last_log_secs_(0) + , custom_handlers_(std::move(custom_user_flags)) +{ + std::memset(&cached_tm_, 0, sizeof(cached_tm_)); + compile_pattern_(pattern_); +} + +// use by default full formatter for if pattern is not given +SPDLOG_INLINE pattern_formatter::pattern_formatter(pattern_time_type time_type, std::string eol) + : pattern_("%+") + , eol_(std::move(eol)) + , pattern_time_type_(time_type) + , need_localtime_(true) + , last_log_secs_(0) +{ + std::memset(&cached_tm_, 0, sizeof(cached_tm_)); + formatters_.push_back(details::make_unique(details::padding_info{})); +} + +SPDLOG_INLINE std::unique_ptr pattern_formatter::clone() const +{ + custom_flags cloned_custom_formatters; + for (auto &it : custom_handlers_) + { + cloned_custom_formatters[it.first] = it.second->clone(); + } + auto cloned = details::make_unique(pattern_, pattern_time_type_, eol_, std::move(cloned_custom_formatters)); + cloned->need_localtime(need_localtime_); +#if defined(__GNUC__) && __GNUC__ < 5 + return std::move(cloned); +#else + return cloned; +#endif +} + +SPDLOG_INLINE void pattern_formatter::format(const details::log_msg &msg, memory_buf_t &dest) +{ + if (need_localtime_) + { + const auto secs = std::chrono::duration_cast(msg.time.time_since_epoch()); + if (secs != last_log_secs_) + { + cached_tm_ = get_time_(msg); + last_log_secs_ = secs; + } + } + + for (auto &f : formatters_) + { + f->format(msg, cached_tm_, dest); + } + // write eol + details::fmt_helper::append_string_view(eol_, dest); +} + +SPDLOG_INLINE void pattern_formatter::set_pattern(std::string pattern) +{ + pattern_ = std::move(pattern); + need_localtime_ = false; + compile_pattern_(pattern_); +} + +SPDLOG_INLINE void pattern_formatter::need_localtime(bool need) +{ + need_localtime_ = need; +} + +SPDLOG_INLINE std::tm pattern_formatter::get_time_(const details::log_msg &msg) +{ + if (pattern_time_type_ == pattern_time_type::local) + { + return details::os::localtime(log_clock::to_time_t(msg.time)); + } + return details::os::gmtime(log_clock::to_time_t(msg.time)); +} + +template +SPDLOG_INLINE void pattern_formatter::handle_flag_(char flag, details::padding_info padding) +{ + // process custom flags + auto it = custom_handlers_.find(flag); + if (it != custom_handlers_.end()) + { + auto custom_handler = it->second->clone(); + custom_handler->set_padding_info(padding); + formatters_.push_back(std::move(custom_handler)); + return; + } + + // process built-in flags + switch (flag) + { + case ('+'): // default formatter + formatters_.push_back(details::make_unique(padding)); + need_localtime_ = true; + break; + + case 'n': // logger name + formatters_.push_back(details::make_unique>(padding)); + break; + + case 'l': // level + formatters_.push_back(details::make_unique>(padding)); + break; + + case 'L': // short level + formatters_.push_back(details::make_unique>(padding)); + break; + + case ('t'): // thread id + formatters_.push_back(details::make_unique>(padding)); + break; + + case ('v'): // the message text + formatters_.push_back(details::make_unique>(padding)); + break; + + case ('a'): // weekday + formatters_.push_back(details::make_unique>(padding)); + need_localtime_ = true; + break; + + case ('A'): // short weekday + formatters_.push_back(details::make_unique>(padding)); + need_localtime_ = true; + break; + + case ('b'): + case ('h'): // month + formatters_.push_back(details::make_unique>(padding)); + need_localtime_ = true; + break; + + case ('B'): // short month + formatters_.push_back(details::make_unique>(padding)); + need_localtime_ = true; + break; + + case ('c'): // datetime + formatters_.push_back(details::make_unique>(padding)); + need_localtime_ = true; + break; + + case ('C'): // year 2 digits + formatters_.push_back(details::make_unique>(padding)); + need_localtime_ = true; + break; + + case ('Y'): // year 4 digits + formatters_.push_back(details::make_unique>(padding)); + need_localtime_ = true; + break; + + case ('D'): + case ('x'): // datetime MM/DD/YY + formatters_.push_back(details::make_unique>(padding)); + need_localtime_ = true; + break; + + case ('m'): // month 1-12 + formatters_.push_back(details::make_unique>(padding)); + need_localtime_ = true; + break; + + case ('d'): // day of month 1-31 + formatters_.push_back(details::make_unique>(padding)); + need_localtime_ = true; + break; + + case ('H'): // hours 24 + formatters_.push_back(details::make_unique>(padding)); + need_localtime_ = true; + break; + + case ('I'): // hours 12 + formatters_.push_back(details::make_unique>(padding)); + need_localtime_ = true; + break; + + case ('M'): // minutes + formatters_.push_back(details::make_unique>(padding)); + need_localtime_ = true; + break; + + case ('S'): // seconds + formatters_.push_back(details::make_unique>(padding)); + need_localtime_ = true; + break; + + case ('e'): // milliseconds + formatters_.push_back(details::make_unique>(padding)); + break; + + case ('f'): // microseconds + formatters_.push_back(details::make_unique>(padding)); + break; + + case ('F'): // nanoseconds + formatters_.push_back(details::make_unique>(padding)); + break; + + case ('E'): // seconds since epoch + formatters_.push_back(details::make_unique>(padding)); + break; + + case ('p'): // am/pm + formatters_.push_back(details::make_unique>(padding)); + need_localtime_ = true; + break; + + case ('r'): // 12 hour clock 02:55:02 pm + formatters_.push_back(details::make_unique>(padding)); + need_localtime_ = true; + break; + + case ('R'): // 24-hour HH:MM time + formatters_.push_back(details::make_unique>(padding)); + need_localtime_ = true; + break; + + case ('T'): + case ('X'): // ISO 8601 time format (HH:MM:SS) + formatters_.push_back(details::make_unique>(padding)); + need_localtime_ = true; + break; + + case ('z'): // timezone + formatters_.push_back(details::make_unique>(padding)); + need_localtime_ = true; + break; + + case ('P'): // pid + formatters_.push_back(details::make_unique>(padding)); + break; + + case ('^'): // color range start + formatters_.push_back(details::make_unique(padding)); + break; + + case ('$'): // color range end + formatters_.push_back(details::make_unique(padding)); + break; + + case ('@'): // source location (filename:filenumber) + formatters_.push_back(details::make_unique>(padding)); + break; + + case ('s'): // short source filename - without directory name + formatters_.push_back(details::make_unique>(padding)); + break; + + case ('g'): // full source filename + formatters_.push_back(details::make_unique>(padding)); + break; + + case ('#'): // source line number + formatters_.push_back(details::make_unique>(padding)); + break; + + case ('!'): // source funcname + formatters_.push_back(details::make_unique>(padding)); + break; + + case ('%'): // % char + formatters_.push_back(details::make_unique('%')); + break; + + case ('u'): // elapsed time since last log message in nanos + formatters_.push_back(details::make_unique>(padding)); + break; + + case ('i'): // elapsed time since last log message in micros + formatters_.push_back(details::make_unique>(padding)); + break; + + case ('o'): // elapsed time since last log message in millis + formatters_.push_back(details::make_unique>(padding)); + break; + + case ('O'): // elapsed time since last log message in seconds + formatters_.push_back(details::make_unique>(padding)); + break; + + default: // Unknown flag appears as is + auto unknown_flag = details::make_unique(); + + if (!padding.truncate_) + { + unknown_flag->add_ch('%'); + unknown_flag->add_ch(flag); + formatters_.push_back((std::move(unknown_flag))); + } + // fix issue #1617 (prev char was '!' and should have been treated as funcname flag instead of truncating flag) + // spdlog::set_pattern("[%10!] %v") => "[ main] some message" + // spdlog::set_pattern("[%3!!] %v") => "[mai] some message" + else + { + padding.truncate_ = false; + formatters_.push_back(details::make_unique>(padding)); + unknown_flag->add_ch(flag); + formatters_.push_back((std::move(unknown_flag))); + } + + break; + } +} + +// Extract given pad spec (e.g. %8X, %=8X, %-8!X, %8!X, %=8!X, %-8!X, %+8!X) +// Advance the given it pass the end of the padding spec found (if any) +// Return padding. +SPDLOG_INLINE details::padding_info pattern_formatter::handle_padspec_(std::string::const_iterator &it, std::string::const_iterator end) +{ + using details::padding_info; + using details::scoped_padder; + const size_t max_width = 64; + if (it == end) + { + return padding_info{}; + } + + padding_info::pad_side side; + switch (*it) + { + case '-': + side = padding_info::pad_side::right; + ++it; + break; + case '=': + side = padding_info::pad_side::center; + ++it; + break; + default: + side = details::padding_info::pad_side::left; + break; + } + + if (it == end || !std::isdigit(static_cast(*it))) + { + return padding_info{}; // no padding if no digit found here + } + + auto width = static_cast(*it) - '0'; + for (++it; it != end && std::isdigit(static_cast(*it)); ++it) + { + auto digit = static_cast(*it) - '0'; + width = width * 10 + digit; + } + + // search for the optional truncate marker '!' + bool truncate; + if (it != end && *it == '!') + { + truncate = true; + ++it; + } + else + { + truncate = false; + } + return details::padding_info{std::min(width, max_width), side, truncate}; +} + +SPDLOG_INLINE void pattern_formatter::compile_pattern_(const std::string &pattern) +{ + auto end = pattern.end(); + std::unique_ptr user_chars; + formatters_.clear(); + 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)); + } + + auto padding = handle_padspec_(++it, end); + + if (it != end) + { + if (padding.enabled()) + { + handle_flag_(*it, padding); + } + else + { + handle_flag_(*it, padding); + } + } + else + { + break; + } + } + else // chars not following the % sign should be displayed as is + { + if (!user_chars) + { + user_chars = details::make_unique(); + } + user_chars->add_ch(*it); + } + } + if (user_chars) // append raw chars found so far + { + formatters_.push_back(std::move(user_chars)); + } +} +} // namespace spdlog diff --git a/tpl/spdlog/include/spdlog/pattern_formatter.h b/tpl/spdlog/include/spdlog/pattern_formatter.h new file mode 100644 index 0000000..4c87b21 --- /dev/null +++ b/tpl/spdlog/include/spdlog/pattern_formatter.h @@ -0,0 +1,128 @@ +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) + +#pragma once + +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +namespace spdlog { +namespace details { + +// padding information. +struct padding_info +{ + enum class pad_side + { + left, + right, + center + }; + + padding_info() = default; + padding_info(size_t width, padding_info::pad_side side, bool truncate) + : width_(width) + , side_(side) + , truncate_(truncate) + , enabled_(true) + {} + + bool enabled() const + { + return enabled_; + } + size_t width_ = 0; + pad_side side_ = pad_side::left; + bool truncate_ = false; + bool enabled_ = false; +}; + +class SPDLOG_API flag_formatter +{ +public: + explicit flag_formatter(padding_info padinfo) + : padinfo_(padinfo) + {} + flag_formatter() = default; + virtual ~flag_formatter() = default; + virtual void format(const details::log_msg &msg, const std::tm &tm_time, memory_buf_t &dest) = 0; + +protected: + padding_info padinfo_; +}; + +} // namespace details + +class SPDLOG_API custom_flag_formatter : public details::flag_formatter +{ +public: + virtual std::unique_ptr clone() const = 0; + + void set_padding_info(const details::padding_info &padding) + { + flag_formatter::padinfo_ = padding; + } +}; + +class SPDLOG_API pattern_formatter final : public formatter +{ +public: + using custom_flags = std::unordered_map>; + + explicit pattern_formatter(std::string pattern, pattern_time_type time_type = pattern_time_type::local, + std::string eol = spdlog::details::os::default_eol, custom_flags custom_user_flags = custom_flags()); + + // use default pattern is not given + explicit pattern_formatter(pattern_time_type time_type = pattern_time_type::local, std::string eol = spdlog::details::os::default_eol); + + pattern_formatter(const pattern_formatter &other) = delete; + pattern_formatter &operator=(const pattern_formatter &other) = delete; + + std::unique_ptr clone() const override; + void format(const details::log_msg &msg, memory_buf_t &dest) override; + + template + pattern_formatter &add_flag(char flag, Args &&...args) + { + custom_handlers_[flag] = details::make_unique(std::forward(args)...); + return *this; + } + void set_pattern(std::string pattern); + void need_localtime(bool need = true); + +private: + std::string pattern_; + std::string eol_; + pattern_time_type pattern_time_type_; + bool need_localtime_; + std::tm cached_tm_; + std::chrono::seconds last_log_secs_; + std::vector> formatters_; + custom_flags custom_handlers_; + + std::tm get_time_(const details::log_msg &msg); + template + void handle_flag_(char flag, details::padding_info padding); + + // Extract given pad spec (e.g. %8X) + // Advance the given it pass the end of the padding spec found (if any) + // Return padding. + static details::padding_info handle_padspec_(std::string::const_iterator &it, std::string::const_iterator end); + + void compile_pattern_(const std::string &pattern); +}; +} // namespace spdlog + +#ifdef SPDLOG_HEADER_ONLY +# include "pattern_formatter-inl.h" +#endif diff --git a/tpl/spdlog/include/spdlog/sinks/android_sink.h b/tpl/spdlog/include/spdlog/sinks/android_sink.h new file mode 100644 index 0000000..0087e95 --- /dev/null +++ b/tpl/spdlog/include/spdlog/sinks/android_sink.h @@ -0,0 +1,146 @@ +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) + +#pragma once + +#ifdef __ANDROID__ + +# include +# include +# include +# include +# include + +# include +# include +# include +# include +# include +# include + +# if !defined(SPDLOG_ANDROID_RETRIES) +# define SPDLOG_ANDROID_RETRIES 2 +# endif + +namespace spdlog { +namespace sinks { + +/* + * Android sink + * (logging using __android_log_write or __android_log_buf_write depending on the specified BufferID) + */ +template +class android_sink final : public base_sink +{ +public: + explicit android_sink(std::string tag = "spdlog", bool use_raw_msg = false) + : tag_(std::move(tag)) + , use_raw_msg_(use_raw_msg) + {} + +protected: + void sink_it_(const details::log_msg &msg) override + { + const android_LogPriority priority = convert_to_android_(msg.level); + memory_buf_t formatted; + if (use_raw_msg_) + { + details::fmt_helper::append_string_view(msg.payload, formatted); + } + else + { + base_sink::formatter_->format(msg, formatted); + } + formatted.push_back('\0'); + const char *msg_output = formatted.data(); + + // See system/core/liblog/logger_write.c for explanation of return value + int ret = android_log(priority, tag_.c_str(), msg_output); + if (ret == -EPERM) + { + return; // !__android_log_is_loggable + } + int retry_count = 0; + while ((ret == -11 /*EAGAIN*/) && (retry_count < SPDLOG_ANDROID_RETRIES)) + { + details::os::sleep_for_millis(5); + ret = android_log(priority, tag_.c_str(), msg_output); + retry_count++; + } + + if (ret < 0) + { + throw_spdlog_ex("logging to Android failed", ret); + } + } + + void flush_() override {} + +private: + // There might be liblog versions used, that do not support __android_log_buf_write. So we only compile and link against + // __android_log_buf_write, if user explicitly provides a non-default log buffer. Otherwise, when using the default log buffer, always + // log via __android_log_write. + template + typename std::enable_if(log_id::LOG_ID_MAIN), int>::type android_log(int prio, const char *tag, const char *text) + { + return __android_log_write(prio, tag, text); + } + + template + typename std::enable_if(log_id::LOG_ID_MAIN), int>::type android_log(int prio, const char *tag, const char *text) + { + return __android_log_buf_write(ID, prio, tag, text); + } + + static android_LogPriority convert_to_android_(spdlog::level::level_enum level) + { + switch (level) + { + case spdlog::level::trace: + return ANDROID_LOG_VERBOSE; + case spdlog::level::debug: + return ANDROID_LOG_DEBUG; + case spdlog::level::info: + return ANDROID_LOG_INFO; + case spdlog::level::warn: + return ANDROID_LOG_WARN; + case spdlog::level::err: + return ANDROID_LOG_ERROR; + case spdlog::level::critical: + return ANDROID_LOG_FATAL; + default: + return ANDROID_LOG_DEFAULT; + } + } + + std::string tag_; + bool use_raw_msg_; +}; + +using android_sink_mt = android_sink; +using android_sink_st = android_sink; + +template +using android_sink_buf_mt = android_sink; +template +using android_sink_buf_st = android_sink; + +} // namespace sinks + +// Create and register android syslog logger + +template +inline std::shared_ptr android_logger_mt(const std::string &logger_name, const std::string &tag = "spdlog") +{ + return Factory::template create(logger_name, tag); +} + +template +inline std::shared_ptr android_logger_st(const std::string &logger_name, const std::string &tag = "spdlog") +{ + return Factory::template create(logger_name, tag); +} + +} // namespace spdlog + +#endif // __ANDROID__ diff --git a/tpl/spdlog/include/spdlog/sinks/ansicolor_sink-inl.h b/tpl/spdlog/include/spdlog/sinks/ansicolor_sink-inl.h new file mode 100644 index 0000000..c924fc5 --- /dev/null +++ b/tpl/spdlog/include/spdlog/sinks/ansicolor_sink-inl.h @@ -0,0 +1,145 @@ +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) + +#pragma once + +#ifndef SPDLOG_HEADER_ONLY +# include +#endif + +#include +#include + +namespace spdlog { +namespace sinks { + +template +SPDLOG_INLINE ansicolor_sink::ansicolor_sink(FILE *target_file, color_mode mode) + : target_file_(target_file) + , mutex_(ConsoleMutex::mutex()) + , formatter_(details::make_unique()) + +{ + set_color_mode(mode); + colors_.at(level::trace) = to_string_(white); + colors_.at(level::debug) = to_string_(cyan); + colors_.at(level::info) = to_string_(green); + colors_.at(level::warn) = to_string_(yellow_bold); + colors_.at(level::err) = to_string_(red_bold); + colors_.at(level::critical) = to_string_(bold_on_red); + colors_.at(level::off) = to_string_(reset); +} + +template +SPDLOG_INLINE void ansicolor_sink::set_color(level::level_enum color_level, string_view_t color) +{ + std::lock_guard lock(mutex_); + colors_.at(static_cast(color_level)) = to_string_(color); +} + +template +SPDLOG_INLINE void ansicolor_sink::log(const details::log_msg &msg) +{ + // Wrap the originally formatted message in color codes. + // If color is not supported in the terminal, log as is instead. + std::lock_guard lock(mutex_); + msg.color_range_start = 0; + msg.color_range_end = 0; + memory_buf_t formatted; + formatter_->format(msg, formatted); + if (should_do_colors_ && msg.color_range_end > msg.color_range_start) + { + // before color range + print_range_(formatted, 0, msg.color_range_start); + // in color range + print_ccode_(colors_.at(static_cast(msg.level))); + print_range_(formatted, msg.color_range_start, msg.color_range_end); + print_ccode_(reset); + // after color range + print_range_(formatted, msg.color_range_end, formatted.size()); + } + else // no color + { + print_range_(formatted, 0, formatted.size()); + } + fflush(target_file_); +} + +template +SPDLOG_INLINE void ansicolor_sink::flush() +{ + std::lock_guard lock(mutex_); + fflush(target_file_); +} + +template +SPDLOG_INLINE void ansicolor_sink::set_pattern(const std::string &pattern) +{ + std::lock_guard lock(mutex_); + formatter_ = std::unique_ptr(new pattern_formatter(pattern)); +} + +template +SPDLOG_INLINE void ansicolor_sink::set_formatter(std::unique_ptr sink_formatter) +{ + std::lock_guard lock(mutex_); + formatter_ = std::move(sink_formatter); +} + +template +SPDLOG_INLINE bool ansicolor_sink::should_color() +{ + return should_do_colors_; +} + +template +SPDLOG_INLINE void ansicolor_sink::set_color_mode(color_mode mode) +{ + switch (mode) + { + case color_mode::always: + should_do_colors_ = true; + return; + case color_mode::automatic: + should_do_colors_ = details::os::in_terminal(target_file_) && details::os::is_color_terminal(); + return; + case color_mode::never: + should_do_colors_ = false; + return; + default: + should_do_colors_ = false; + } +} + +template +SPDLOG_INLINE void ansicolor_sink::print_ccode_(const string_view_t &color_code) +{ + fwrite(color_code.data(), sizeof(char), color_code.size(), target_file_); +} + +template +SPDLOG_INLINE void ansicolor_sink::print_range_(const memory_buf_t &formatted, size_t start, size_t end) +{ + fwrite(formatted.data() + start, sizeof(char), end - start, target_file_); +} + +template +SPDLOG_INLINE std::string ansicolor_sink::to_string_(const string_view_t &sv) +{ + return std::string(sv.data(), sv.size()); +} + +// ansicolor_stdout_sink +template +SPDLOG_INLINE ansicolor_stdout_sink::ansicolor_stdout_sink(color_mode mode) + : ansicolor_sink(stdout, mode) +{} + +// ansicolor_stderr_sink +template +SPDLOG_INLINE ansicolor_stderr_sink::ansicolor_stderr_sink(color_mode mode) + : ansicolor_sink(stderr, mode) +{} + +} // namespace sinks +} // namespace spdlog diff --git a/tpl/spdlog/include/spdlog/sinks/ansicolor_sink.h b/tpl/spdlog/include/spdlog/sinks/ansicolor_sink.h new file mode 100644 index 0000000..39d966b --- /dev/null +++ b/tpl/spdlog/include/spdlog/sinks/ansicolor_sink.h @@ -0,0 +1,118 @@ +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) + +#pragma once + +#include +#include +#include +#include +#include +#include +#include + +namespace spdlog { +namespace sinks { + +/** + * This sink prefixes the output with an ANSI escape sequence color code + * depending on the severity + * of the message. + * If no color terminal detected, omit the escape codes. + */ + +template +class ansicolor_sink : public sink +{ +public: + using mutex_t = typename ConsoleMutex::mutex_t; + ansicolor_sink(FILE *target_file, color_mode mode); + ~ansicolor_sink() override = default; + + ansicolor_sink(const ansicolor_sink &other) = delete; + ansicolor_sink(ansicolor_sink &&other) = delete; + + ansicolor_sink &operator=(const ansicolor_sink &other) = delete; + ansicolor_sink &operator=(ansicolor_sink &&other) = delete; + + void set_color(level::level_enum color_level, string_view_t color); + void set_color_mode(color_mode mode); + bool should_color(); + + void log(const details::log_msg &msg) override; + void flush() override; + void set_pattern(const std::string &pattern) final; + void set_formatter(std::unique_ptr sink_formatter) override; + + // Formatting codes + const string_view_t reset = "\033[m"; + const string_view_t bold = "\033[1m"; + const string_view_t dark = "\033[2m"; + const string_view_t underline = "\033[4m"; + const string_view_t blink = "\033[5m"; + const string_view_t reverse = "\033[7m"; + const string_view_t concealed = "\033[8m"; + const string_view_t clear_line = "\033[K"; + + // Foreground colors + const string_view_t black = "\033[30m"; + const string_view_t red = "\033[31m"; + const string_view_t green = "\033[32m"; + const string_view_t yellow = "\033[33m"; + const string_view_t blue = "\033[34m"; + const string_view_t magenta = "\033[35m"; + const string_view_t cyan = "\033[36m"; + const string_view_t white = "\033[37m"; + + /// Background colors + const string_view_t on_black = "\033[40m"; + const string_view_t on_red = "\033[41m"; + const string_view_t on_green = "\033[42m"; + const string_view_t on_yellow = "\033[43m"; + const string_view_t on_blue = "\033[44m"; + const string_view_t on_magenta = "\033[45m"; + const string_view_t on_cyan = "\033[46m"; + const string_view_t on_white = "\033[47m"; + + /// Bold colors + const string_view_t yellow_bold = "\033[33m\033[1m"; + const string_view_t red_bold = "\033[31m\033[1m"; + const string_view_t bold_on_red = "\033[1m\033[41m"; + +private: + FILE *target_file_; + mutex_t &mutex_; + bool should_do_colors_; + std::unique_ptr formatter_; + std::array colors_; + void print_ccode_(const string_view_t &color_code); + void print_range_(const memory_buf_t &formatted, size_t start, size_t end); + static std::string to_string_(const string_view_t &sv); +}; + +template +class ansicolor_stdout_sink : public ansicolor_sink +{ +public: + explicit ansicolor_stdout_sink(color_mode mode = color_mode::automatic); +}; + +template +class ansicolor_stderr_sink : public ansicolor_sink +{ +public: + explicit ansicolor_stderr_sink(color_mode mode = color_mode::automatic); +}; + +using ansicolor_stdout_sink_mt = ansicolor_stdout_sink; +using ansicolor_stdout_sink_st = ansicolor_stdout_sink; + +using ansicolor_stderr_sink_mt = ansicolor_stderr_sink; +using ansicolor_stderr_sink_st = ansicolor_stderr_sink; + +} // namespace sinks +} // namespace spdlog + +#ifdef SPDLOG_HEADER_ONLY +# include "ansicolor_sink-inl.h" +#endif diff --git a/tpl/spdlog/include/spdlog/sinks/base_sink-inl.h b/tpl/spdlog/include/spdlog/sinks/base_sink-inl.h new file mode 100644 index 0000000..421fdf9 --- /dev/null +++ b/tpl/spdlog/include/spdlog/sinks/base_sink-inl.h @@ -0,0 +1,63 @@ +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) + +#pragma once + +#ifndef SPDLOG_HEADER_ONLY +# include +#endif + +#include +#include + +#include + +template +SPDLOG_INLINE spdlog::sinks::base_sink::base_sink() + : formatter_{details::make_unique()} +{} + +template +SPDLOG_INLINE spdlog::sinks::base_sink::base_sink(std::unique_ptr formatter) + : formatter_{std::move(formatter)} +{} + +template +void SPDLOG_INLINE spdlog::sinks::base_sink::log(const details::log_msg &msg) +{ + std::lock_guard lock(mutex_); + sink_it_(msg); +} + +template +void SPDLOG_INLINE spdlog::sinks::base_sink::flush() +{ + std::lock_guard lock(mutex_); + flush_(); +} + +template +void SPDLOG_INLINE spdlog::sinks::base_sink::set_pattern(const std::string &pattern) +{ + std::lock_guard lock(mutex_); + set_pattern_(pattern); +} + +template +void SPDLOG_INLINE spdlog::sinks::base_sink::set_formatter(std::unique_ptr sink_formatter) +{ + std::lock_guard lock(mutex_); + set_formatter_(std::move(sink_formatter)); +} + +template +void SPDLOG_INLINE spdlog::sinks::base_sink::set_pattern_(const std::string &pattern) +{ + set_formatter_(details::make_unique(pattern)); +} + +template +void SPDLOG_INLINE spdlog::sinks::base_sink::set_formatter_(std::unique_ptr sink_formatter) +{ + formatter_ = std::move(sink_formatter); +} diff --git a/tpl/spdlog/include/spdlog/sinks/base_sink.h b/tpl/spdlog/include/spdlog/sinks/base_sink.h new file mode 100644 index 0000000..2e795f5 --- /dev/null +++ b/tpl/spdlog/include/spdlog/sinks/base_sink.h @@ -0,0 +1,52 @@ +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) + +#pragma once +// +// base sink templated over a mutex (either dummy or real) +// concrete implementation should override the sink_it_() and flush_() methods. +// locking is taken care of in this class - no locking needed by the +// implementers.. +// + +#include +#include +#include + +namespace spdlog { +namespace sinks { +template +class SPDLOG_API base_sink : public sink +{ +public: + base_sink(); + explicit base_sink(std::unique_ptr formatter); + ~base_sink() override = default; + + base_sink(const base_sink &) = delete; + base_sink(base_sink &&) = delete; + + base_sink &operator=(const base_sink &) = delete; + base_sink &operator=(base_sink &&) = delete; + + void log(const details::log_msg &msg) final; + void flush() final; + void set_pattern(const std::string &pattern) final; + void set_formatter(std::unique_ptr sink_formatter) final; + +protected: + // sink formatter + std::unique_ptr formatter_; + Mutex mutex_; + + virtual void sink_it_(const details::log_msg &msg) = 0; + virtual void flush_() = 0; + virtual void set_pattern_(const std::string &pattern); + virtual void set_formatter_(std::unique_ptr sink_formatter); +}; +} // namespace sinks +} // namespace spdlog + +#ifdef SPDLOG_HEADER_ONLY +# include "base_sink-inl.h" +#endif diff --git a/tpl/spdlog/include/spdlog/sinks/basic_file_sink-inl.h b/tpl/spdlog/include/spdlog/sinks/basic_file_sink-inl.h new file mode 100644 index 0000000..8d23f96 --- /dev/null +++ b/tpl/spdlog/include/spdlog/sinks/basic_file_sink-inl.h @@ -0,0 +1,44 @@ +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) + +#pragma once + +#ifndef SPDLOG_HEADER_ONLY +# include +#endif + +#include +#include + +namespace spdlog { +namespace sinks { + +template +SPDLOG_INLINE basic_file_sink::basic_file_sink(const filename_t &filename, bool truncate, const file_event_handlers &event_handlers) + : file_helper_{event_handlers} +{ + file_helper_.open(filename, truncate); +} + +template +SPDLOG_INLINE const filename_t &basic_file_sink::filename() const +{ + return file_helper_.filename(); +} + +template +SPDLOG_INLINE void basic_file_sink::sink_it_(const details::log_msg &msg) +{ + memory_buf_t formatted; + base_sink::formatter_->format(msg, formatted); + file_helper_.write(formatted); +} + +template +SPDLOG_INLINE void basic_file_sink::flush_() +{ + file_helper_.flush(); +} + +} // namespace sinks +} // namespace spdlog diff --git a/tpl/spdlog/include/spdlog/sinks/basic_file_sink.h b/tpl/spdlog/include/spdlog/sinks/basic_file_sink.h new file mode 100644 index 0000000..aacc993 --- /dev/null +++ b/tpl/spdlog/include/spdlog/sinks/basic_file_sink.h @@ -0,0 +1,60 @@ +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) + +#pragma once + +#include +#include +#include +#include + +#include +#include + +namespace spdlog { +namespace sinks { +/* + * Trivial file sink with single file as target + */ +template +class basic_file_sink final : public base_sink +{ +public: + explicit basic_file_sink(const filename_t &filename, bool truncate = false, const file_event_handlers &event_handlers = {}); + const filename_t &filename() const; + +protected: + void sink_it_(const details::log_msg &msg) override; + void flush_() override; + +private: + details::file_helper file_helper_; +}; + +using basic_file_sink_mt = basic_file_sink; +using basic_file_sink_st = basic_file_sink; + +} // namespace sinks + +// +// factory functions +// +template +inline std::shared_ptr basic_logger_mt( + const std::string &logger_name, const filename_t &filename, bool truncate = false, const file_event_handlers &event_handlers = {}) +{ + return Factory::template create(logger_name, filename, truncate, event_handlers); +} + +template +inline std::shared_ptr basic_logger_st( + const std::string &logger_name, const filename_t &filename, bool truncate = false, const file_event_handlers &event_handlers = {}) +{ + return Factory::template create(logger_name, filename, truncate, event_handlers); +} + +} // namespace spdlog + +#ifdef SPDLOG_HEADER_ONLY +# include "basic_file_sink-inl.h" +#endif diff --git a/tpl/spdlog/include/spdlog/sinks/callback_sink.h b/tpl/spdlog/include/spdlog/sinks/callback_sink.h new file mode 100644 index 0000000..bcd3138 --- /dev/null +++ b/tpl/spdlog/include/spdlog/sinks/callback_sink.h @@ -0,0 +1,61 @@ +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) + +#pragma once + +#include +#include +#include + +#include +#include + +namespace spdlog { + +// callbacks type +typedef std::function custom_log_callback; + +namespace sinks { +/* + * Trivial callback sink, gets a callback function and calls it on each log + */ +template +class callback_sink final : public base_sink +{ +public: + explicit callback_sink(const custom_log_callback &callback) + : callback_{callback} + {} + +protected: + void sink_it_(const details::log_msg &msg) override + { + callback_(msg); + } + void flush_() override{}; + +private: + custom_log_callback callback_; +}; + +using callback_sink_mt = callback_sink; +using callback_sink_st = callback_sink; + +} // namespace sinks + +// +// factory functions +// +template +inline std::shared_ptr callback_logger_mt(const std::string &logger_name, const custom_log_callback &callback) +{ + return Factory::template create(logger_name, callback); +} + +template +inline std::shared_ptr callback_logger_st(const std::string &logger_name, const custom_log_callback &callback) +{ + return Factory::template create(logger_name, callback); +} + +} // namespace spdlog diff --git a/tpl/spdlog/include/spdlog/sinks/daily_file_sink.h b/tpl/spdlog/include/spdlog/sinks/daily_file_sink.h new file mode 100644 index 0000000..0770380 --- /dev/null +++ b/tpl/spdlog/include/spdlog/sinks/daily_file_sink.h @@ -0,0 +1,247 @@ +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +namespace spdlog { +namespace sinks { + +/* + * Generator of daily log file names in format basename.YYYY-MM-DD.ext + */ +struct daily_filename_calculator +{ + // Create filename for the form basename.YYYY-MM-DD + static filename_t calc_filename(const filename_t &filename, const tm &now_tm) + { + filename_t basename, ext; + std::tie(basename, ext) = details::file_helper::split_by_extension(filename); + return fmt_lib::format(SPDLOG_FMT_STRING(SPDLOG_FILENAME_T("{}_{:04d}-{:02d}-{:02d}{}")), basename, now_tm.tm_year + 1900, + now_tm.tm_mon + 1, now_tm.tm_mday, ext); + } +}; + +/* + * Generator of daily log file names with strftime format. + * Usages: + * auto sink = std::make_shared("myapp-%Y-%m-%d:%H:%M:%S.log", hour, minute);" + * auto logger = spdlog::daily_logger_format_mt("loggername, "myapp-%Y-%m-%d:%X.log", hour, minute)" + * + */ +struct daily_filename_format_calculator +{ + static filename_t calc_filename(const filename_t &file_path, const tm &now_tm) + { +#if defined(_WIN32) && defined(SPDLOG_WCHAR_FILENAMES) + std::wstringstream stream; +#else + std::stringstream stream; +#endif + stream << std::put_time(&now_tm, file_path.c_str()); + return stream.str(); + } +}; + +/* + * Rotating file sink based on date. + * If truncate != false , the created file will be truncated. + * If max_files > 0, retain only the last max_files and delete previous. + */ +template +class daily_file_sink final : public base_sink +{ +public: + // create daily file sink which rotates on given time + daily_file_sink(filename_t base_filename, int rotation_hour, int rotation_minute, bool truncate = false, uint16_t max_files = 0, + const file_event_handlers &event_handlers = {}) + : base_filename_(std::move(base_filename)) + , rotation_h_(rotation_hour) + , rotation_m_(rotation_minute) + , file_helper_{event_handlers} + , truncate_(truncate) + , max_files_(max_files) + , filenames_q_() + { + if (rotation_hour < 0 || rotation_hour > 23 || rotation_minute < 0 || rotation_minute > 59) + { + throw_spdlog_ex("daily_file_sink: Invalid rotation time in ctor"); + } + + auto now = log_clock::now(); + auto filename = FileNameCalc::calc_filename(base_filename_, now_tm(now)); + file_helper_.open(filename, truncate_); + rotation_tp_ = next_rotation_tp_(); + + if (max_files_ > 0) + { + init_filenames_q_(); + } + } + + filename_t filename() + { + std::lock_guard lock(base_sink::mutex_); + return file_helper_.filename(); + } + +protected: + void sink_it_(const details::log_msg &msg) override + { + auto time = msg.time; + bool should_rotate = time >= rotation_tp_; + if (should_rotate) + { + auto filename = FileNameCalc::calc_filename(base_filename_, now_tm(time)); + file_helper_.open(filename, truncate_); + rotation_tp_ = next_rotation_tp_(); + } + memory_buf_t formatted; + base_sink::formatter_->format(msg, formatted); + file_helper_.write(formatted); + + // Do the cleaning only at the end because it might throw on failure. + if (should_rotate && max_files_ > 0) + { + delete_old_(); + } + } + + void flush_() override + { + file_helper_.flush(); + } + +private: + void init_filenames_q_() + { + using details::os::path_exists; + + filenames_q_ = details::circular_q(static_cast(max_files_)); + std::vector filenames; + auto now = log_clock::now(); + while (filenames.size() < max_files_) + { + auto filename = FileNameCalc::calc_filename(base_filename_, now_tm(now)); + if (!path_exists(filename)) + { + break; + } + filenames.emplace_back(filename); + now -= std::chrono::hours(24); + } + for (auto iter = filenames.rbegin(); iter != filenames.rend(); ++iter) + { + filenames_q_.push_back(std::move(*iter)); + } + } + + tm now_tm(log_clock::time_point tp) + { + time_t tnow = log_clock::to_time_t(tp); + return spdlog::details::os::localtime(tnow); + } + + log_clock::time_point next_rotation_tp_() + { + auto now = log_clock::now(); + tm date = now_tm(now); + date.tm_hour = rotation_h_; + date.tm_min = rotation_m_; + date.tm_sec = 0; + auto rotation_time = log_clock::from_time_t(std::mktime(&date)); + if (rotation_time > now) + { + return rotation_time; + } + return {rotation_time + std::chrono::hours(24)}; + } + + // Delete the file N rotations ago. + // Throw spdlog_ex on failure to delete the old file. + void delete_old_() + { + using details::os::filename_to_str; + using details::os::remove_if_exists; + + filename_t current_file = file_helper_.filename(); + if (filenames_q_.full()) + { + auto old_filename = std::move(filenames_q_.front()); + filenames_q_.pop_front(); + bool ok = remove_if_exists(old_filename) == 0; + if (!ok) + { + filenames_q_.push_back(std::move(current_file)); + throw_spdlog_ex("Failed removing daily file " + filename_to_str(old_filename), errno); + } + } + filenames_q_.push_back(std::move(current_file)); + } + + filename_t base_filename_; + int rotation_h_; + int rotation_m_; + log_clock::time_point rotation_tp_; + details::file_helper file_helper_; + bool truncate_; + uint16_t max_files_; + details::circular_q filenames_q_; +}; + +using daily_file_sink_mt = daily_file_sink; +using daily_file_sink_st = daily_file_sink; +using daily_file_format_sink_mt = daily_file_sink; +using daily_file_format_sink_st = daily_file_sink; + +} // namespace sinks + +// +// factory functions +// +template +inline std::shared_ptr daily_logger_mt(const std::string &logger_name, const filename_t &filename, int hour = 0, int minute = 0, + bool truncate = false, uint16_t max_files = 0, const file_event_handlers &event_handlers = {}) +{ + return Factory::template create(logger_name, filename, hour, minute, truncate, max_files, event_handlers); +} + +template +inline std::shared_ptr daily_logger_format_mt(const std::string &logger_name, const filename_t &filename, int hour = 0, + int minute = 0, bool truncate = false, uint16_t max_files = 0, const file_event_handlers &event_handlers = {}) +{ + return Factory::template create( + logger_name, filename, hour, minute, truncate, max_files, event_handlers); +} + +template +inline std::shared_ptr daily_logger_st(const std::string &logger_name, const filename_t &filename, int hour = 0, int minute = 0, + bool truncate = false, uint16_t max_files = 0, const file_event_handlers &event_handlers = {}) +{ + return Factory::template create(logger_name, filename, hour, minute, truncate, max_files, event_handlers); +} + +template +inline std::shared_ptr daily_logger_format_st(const std::string &logger_name, const filename_t &filename, int hour = 0, + int minute = 0, bool truncate = false, uint16_t max_files = 0, const file_event_handlers &event_handlers = {}) +{ + return Factory::template create( + logger_name, filename, hour, minute, truncate, max_files, event_handlers); +} +} // namespace spdlog diff --git a/tpl/spdlog/include/spdlog/sinks/dist_sink.h b/tpl/spdlog/include/spdlog/sinks/dist_sink.h new file mode 100644 index 0000000..7ec3a2e --- /dev/null +++ b/tpl/spdlog/include/spdlog/sinks/dist_sink.h @@ -0,0 +1,97 @@ +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) + +#pragma once + +#include "base_sink.h" +#include +#include +#include + +#include +#include +#include +#include + +// Distribution sink (mux). Stores a vector of sinks which get called when log +// is called + +namespace spdlog { +namespace sinks { + +template +class dist_sink : public base_sink +{ +public: + dist_sink() = default; + explicit dist_sink(std::vector> sinks) + : sinks_(sinks) + {} + + dist_sink(const dist_sink &) = delete; + dist_sink &operator=(const dist_sink &) = delete; + + void add_sink(std::shared_ptr sub_sink) + { + std::lock_guard lock(base_sink::mutex_); + sinks_.push_back(sub_sink); + } + + void remove_sink(std::shared_ptr sub_sink) + { + std::lock_guard lock(base_sink::mutex_); + sinks_.erase(std::remove(sinks_.begin(), sinks_.end(), sub_sink), sinks_.end()); + } + + void set_sinks(std::vector> sinks) + { + std::lock_guard lock(base_sink::mutex_); + sinks_ = std::move(sinks); + } + + std::vector> &sinks() + { + return sinks_; + } + +protected: + void sink_it_(const details::log_msg &msg) override + { + for (auto &sub_sink : sinks_) + { + if (sub_sink->should_log(msg.level)) + { + sub_sink->log(msg); + } + } + } + + void flush_() override + { + for (auto &sub_sink : sinks_) + { + sub_sink->flush(); + } + } + + void set_pattern_(const std::string &pattern) override + { + set_formatter_(details::make_unique(pattern)); + } + + void set_formatter_(std::unique_ptr sink_formatter) override + { + base_sink::formatter_ = std::move(sink_formatter); + for (auto &sub_sink : sinks_) + { + sub_sink->set_formatter(base_sink::formatter_->clone()); + } + } + std::vector> sinks_; +}; + +using dist_sink_mt = dist_sink; +using dist_sink_st = dist_sink; + +} // namespace sinks +} // namespace spdlog diff --git a/tpl/spdlog/include/spdlog/sinks/dup_filter_sink.h b/tpl/spdlog/include/spdlog/sinks/dup_filter_sink.h new file mode 100644 index 0000000..3c96549 --- /dev/null +++ b/tpl/spdlog/include/spdlog/sinks/dup_filter_sink.h @@ -0,0 +1,96 @@ +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) + +#pragma once + +#include "dist_sink.h" +#include +#include + +#include +#include +#include +#include + +// Duplicate message removal sink. +// Skip the message if previous one is identical and less than "max_skip_duration" have passed +// +// Example: +// +// #include +// +// int main() { +// auto dup_filter = std::make_shared(std::chrono::seconds(5), level::info); +// dup_filter->add_sink(std::make_shared()); +// spdlog::logger l("logger", dup_filter); +// l.info("Hello"); +// l.info("Hello"); +// l.info("Hello"); +// l.info("Different Hello"); +// } +// +// Will produce: +// [2019-06-25 17:50:56.511] [logger] [info] Hello +// [2019-06-25 17:50:56.512] [logger] [info] Skipped 3 duplicate messages.. +// [2019-06-25 17:50:56.512] [logger] [info] Different Hello + +namespace spdlog { +namespace sinks { +template +class dup_filter_sink : public dist_sink +{ +public: + template + explicit dup_filter_sink(std::chrono::duration max_skip_duration, level::level_enum notification_level = level::info) + : max_skip_duration_{max_skip_duration} + , log_level_{notification_level} + {} + +protected: + std::chrono::microseconds max_skip_duration_; + log_clock::time_point last_msg_time_; + std::string last_msg_payload_; + size_t skip_counter_ = 0; + level::level_enum log_level_; + + void sink_it_(const details::log_msg &msg) override + { + bool filtered = filter_(msg); + if (!filtered) + { + skip_counter_ += 1; + return; + } + + // log the "skipped.." message + if (skip_counter_ > 0) + { + char buf[64]; + auto msg_size = ::snprintf(buf, sizeof(buf), "Skipped %u duplicate messages..", static_cast(skip_counter_)); + if (msg_size > 0 && static_cast(msg_size) < sizeof(buf)) + { + details::log_msg skipped_msg{msg.source, msg.logger_name, log_level_, string_view_t{buf, static_cast(msg_size)}}; + dist_sink::sink_it_(skipped_msg); + } + } + + // log current message + dist_sink::sink_it_(msg); + last_msg_time_ = msg.time; + skip_counter_ = 0; + last_msg_payload_.assign(msg.payload.data(), msg.payload.data() + msg.payload.size()); + } + + // return whether the log msg should be displayed (true) or skipped (false) + bool filter_(const details::log_msg &msg) + { + auto filter_duration = msg.time - last_msg_time_; + return (filter_duration > max_skip_duration_) || (msg.payload != last_msg_payload_); + } +}; + +using dup_filter_sink_mt = dup_filter_sink; +using dup_filter_sink_st = dup_filter_sink; + +} // namespace sinks +} // namespace spdlog diff --git a/tpl/spdlog/include/spdlog/sinks/hourly_file_sink.h b/tpl/spdlog/include/spdlog/sinks/hourly_file_sink.h new file mode 100644 index 0000000..33dd894 --- /dev/null +++ b/tpl/spdlog/include/spdlog/sinks/hourly_file_sink.h @@ -0,0 +1,204 @@ +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +namespace spdlog { +namespace sinks { + +/* + * Generator of Hourly log file names in format basename.YYYY-MM-DD-HH.ext + */ +struct hourly_filename_calculator +{ + // Create filename for the form basename.YYYY-MM-DD-H + static filename_t calc_filename(const filename_t &filename, const tm &now_tm) + { + filename_t basename, ext; + std::tie(basename, ext) = details::file_helper::split_by_extension(filename); + return fmt_lib::format(SPDLOG_FILENAME_T("{}_{:04d}-{:02d}-{:02d}_{:02d}{}"), basename, now_tm.tm_year + 1900, now_tm.tm_mon + 1, + now_tm.tm_mday, now_tm.tm_hour, ext); + } +}; + +/* + * Rotating file sink based on time. + * If truncate != false , the created file will be truncated. + * If max_files > 0, retain only the last max_files and delete previous. + */ +template +class hourly_file_sink final : public base_sink +{ +public: + // create hourly file sink which rotates on given time + hourly_file_sink( + filename_t base_filename, bool truncate = false, uint16_t max_files = 0, const file_event_handlers &event_handlers = {}) + : base_filename_(std::move(base_filename)) + , file_helper_{event_handlers} + , truncate_(truncate) + , max_files_(max_files) + , filenames_q_() + { + auto now = log_clock::now(); + auto filename = FileNameCalc::calc_filename(base_filename_, now_tm(now)); + file_helper_.open(filename, truncate_); + remove_init_file_ = file_helper_.size() == 0; + rotation_tp_ = next_rotation_tp_(); + + if (max_files_ > 0) + { + init_filenames_q_(); + } + } + + filename_t filename() + { + std::lock_guard lock(base_sink::mutex_); + return file_helper_.filename(); + } + +protected: + void sink_it_(const details::log_msg &msg) override + { + auto time = msg.time; + bool should_rotate = time >= rotation_tp_; + if (should_rotate) + { + if (remove_init_file_) + { + file_helper_.close(); + details::os::remove(file_helper_.filename()); + } + auto filename = FileNameCalc::calc_filename(base_filename_, now_tm(time)); + file_helper_.open(filename, truncate_); + rotation_tp_ = next_rotation_tp_(); + } + remove_init_file_ = false; + memory_buf_t formatted; + base_sink::formatter_->format(msg, formatted); + file_helper_.write(formatted); + + // Do the cleaning only at the end because it might throw on failure. + if (should_rotate && max_files_ > 0) + { + delete_old_(); + } + } + + void flush_() override + { + file_helper_.flush(); + } + +private: + void init_filenames_q_() + { + using details::os::path_exists; + + filenames_q_ = details::circular_q(static_cast(max_files_)); + std::vector filenames; + auto now = log_clock::now(); + while (filenames.size() < max_files_) + { + auto filename = FileNameCalc::calc_filename(base_filename_, now_tm(now)); + if (!path_exists(filename)) + { + break; + } + filenames.emplace_back(filename); + now -= std::chrono::hours(1); + } + for (auto iter = filenames.rbegin(); iter != filenames.rend(); ++iter) + { + filenames_q_.push_back(std::move(*iter)); + } + } + + tm now_tm(log_clock::time_point tp) + { + time_t tnow = log_clock::to_time_t(tp); + return spdlog::details::os::localtime(tnow); + } + + log_clock::time_point next_rotation_tp_() + { + auto now = log_clock::now(); + tm date = now_tm(now); + date.tm_min = 0; + date.tm_sec = 0; + auto rotation_time = log_clock::from_time_t(std::mktime(&date)); + if (rotation_time > now) + { + return rotation_time; + } + return {rotation_time + std::chrono::hours(1)}; + } + + // Delete the file N rotations ago. + // Throw spdlog_ex on failure to delete the old file. + void delete_old_() + { + using details::os::filename_to_str; + using details::os::remove_if_exists; + + filename_t current_file = file_helper_.filename(); + if (filenames_q_.full()) + { + auto old_filename = std::move(filenames_q_.front()); + filenames_q_.pop_front(); + bool ok = remove_if_exists(old_filename) == 0; + if (!ok) + { + filenames_q_.push_back(std::move(current_file)); + SPDLOG_THROW(spdlog_ex("Failed removing hourly file " + filename_to_str(old_filename), errno)); + } + } + filenames_q_.push_back(std::move(current_file)); + } + + filename_t base_filename_; + log_clock::time_point rotation_tp_; + details::file_helper file_helper_; + bool truncate_; + uint16_t max_files_; + details::circular_q filenames_q_; + bool remove_init_file_; +}; + +using hourly_file_sink_mt = hourly_file_sink; +using hourly_file_sink_st = hourly_file_sink; + +} // namespace sinks + +// +// factory functions +// +template +inline std::shared_ptr hourly_logger_mt(const std::string &logger_name, const filename_t &filename, bool truncate = false, + uint16_t max_files = 0, const file_event_handlers &event_handlers = {}) +{ + return Factory::template create(logger_name, filename, truncate, max_files, event_handlers); +} + +template +inline std::shared_ptr hourly_logger_st(const std::string &logger_name, const filename_t &filename, bool truncate = false, + uint16_t max_files = 0, const file_event_handlers &event_handlers = {}) +{ + return Factory::template create(logger_name, filename, truncate, max_files, event_handlers); +} +} // namespace spdlog diff --git a/tpl/spdlog/include/spdlog/sinks/kafka_sink.h b/tpl/spdlog/include/spdlog/sinks/kafka_sink.h new file mode 100644 index 0000000..ce740ef --- /dev/null +++ b/tpl/spdlog/include/spdlog/sinks/kafka_sink.h @@ -0,0 +1,133 @@ +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) + +#pragma once + +// +// Custom sink for kafka +// Building and using requires librdkafka library. +// For building librdkafka library check the url below +// https://github.com/confluentinc/librdkafka +// + +#include +#include "spdlog/details/log_msg.h" +#include "spdlog/sinks/base_sink.h" +#include "spdlog/details/synchronous_factory.h" +#include "spdlog/details/null_mutex.h" +#include "spdlog/async.h" +#include + +// kafka header +#include + +namespace spdlog { +namespace sinks { + +struct kafka_sink_config +{ + std::string server_addr; + std::string produce_topic; + int32_t flush_timeout_ms = 1000; + + kafka_sink_config(std::string addr, std::string topic, int flush_timeout_ms = 1000) + : server_addr{std::move(addr)} + , produce_topic{std::move(topic)} + , flush_timeout_ms(flush_timeout_ms) + {} +}; + +template +class kafka_sink : public base_sink +{ +public: + kafka_sink(kafka_sink_config config) + : config_{std::move(config)} + { + try + { + std::string errstr; + conf_.reset(RdKafka::Conf::create(RdKafka::Conf::CONF_GLOBAL)); + RdKafka::Conf::ConfResult confRes = conf_->set("bootstrap.servers", config_.server_addr, errstr); + if (confRes != RdKafka::Conf::CONF_OK) + { + throw_spdlog_ex(fmt_lib::format("conf set bootstrap.servers failed err:{}", errstr)); + } + + tconf_.reset(RdKafka::Conf::create(RdKafka::Conf::CONF_TOPIC)); + if (tconf_ == nullptr) + { + throw_spdlog_ex(fmt_lib::format("create topic config failed")); + } + + producer_.reset(RdKafka::Producer::create(conf_.get(), errstr)); + if (producer_ == nullptr) + { + throw_spdlog_ex(fmt_lib::format("create producer failed err:{}", errstr)); + } + topic_.reset(RdKafka::Topic::create(producer_.get(), config_.produce_topic, tconf_.get(), errstr)); + if (topic_ == nullptr) + { + throw_spdlog_ex(fmt_lib::format("create topic failed err:{}", errstr)); + } + } + catch (const std::exception &e) + { + throw_spdlog_ex(fmt_lib::format("error create kafka instance: {}", e.what())); + } + } + + ~kafka_sink() + { + producer_->flush(config_.flush_timeout_ms); + } + +protected: + void sink_it_(const details::log_msg &msg) override + { + producer_->produce(topic_.get(), 0, RdKafka::Producer::RK_MSG_COPY, (void *)msg.payload.data(), msg.payload.size(), NULL, NULL); + } + + void flush_() override + { + producer_->flush(config_.flush_timeout_ms); + } + +private: + kafka_sink_config config_; + std::unique_ptr producer_ = nullptr; + std::unique_ptr conf_ = nullptr; + std::unique_ptr tconf_ = nullptr; + std::unique_ptr topic_ = nullptr; +}; + +using kafka_sink_mt = kafka_sink; +using kafka_sink_st = kafka_sink; + +} // namespace sinks + +template +inline std::shared_ptr kafka_logger_mt(const std::string &logger_name, spdlog::sinks::kafka_sink_config config) +{ + return Factory::template create(logger_name, config); +} + +template +inline std::shared_ptr kafka_logger_st(const std::string &logger_name, spdlog::sinks::kafka_sink_config config) +{ + return Factory::template create(logger_name, config); +} + +template +inline std::shared_ptr kafka_logger_async_mt(std::string logger_name, spdlog::sinks::kafka_sink_config config) +{ + return Factory::template create(logger_name, config); +} + +template +inline std::shared_ptr kafka_logger_async_st(std::string logger_name, spdlog::sinks::kafka_sink_config config) +{ + return Factory::template create(logger_name, config); +} + +} // namespace spdlog diff --git a/tpl/spdlog/include/spdlog/sinks/mongo_sink.h b/tpl/spdlog/include/spdlog/sinks/mongo_sink.h new file mode 100644 index 0000000..6a8927f --- /dev/null +++ b/tpl/spdlog/include/spdlog/sinks/mongo_sink.h @@ -0,0 +1,107 @@ +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) + +#pragma once + +// +// Custom sink for mongodb +// Building and using requires mongocxx library. +// For building mongocxx library check the url below +// http://mongocxx.org/mongocxx-v3/installation/ +// + +#include "spdlog/common.h" +#include "spdlog/details/log_msg.h" +#include "spdlog/sinks/base_sink.h" +#include + +#include +#include +#include + +#include +#include +#include + +namespace spdlog { +namespace sinks { +template +class mongo_sink : public base_sink +{ +public: + mongo_sink(const std::string &db_name, const std::string &collection_name, const std::string &uri = "mongodb://localhost:27017") + try : mongo_sink(std::make_shared(), db_name, collection_name, uri) + {} + catch (const std::exception &e) + { + throw_spdlog_ex(fmt_lib::format("Error opening database: {}", e.what())); + } + + mongo_sink(std::shared_ptr instance, const std::string &db_name, const std::string &collection_name, + const std::string &uri = "mongodb://localhost:27017") + : instance_(std::move(instance)) + , db_name_(db_name) + , coll_name_(collection_name) + { + try + { + client_ = spdlog::details::make_unique(mongocxx::uri{uri}); + } + catch (const std::exception &e) + { + throw_spdlog_ex(fmt_lib::format("Error opening database: {}", e.what())); + } + } + + ~mongo_sink() + { + flush_(); + } + +protected: + void sink_it_(const details::log_msg &msg) override + { + using bsoncxx::builder::stream::document; + using bsoncxx::builder::stream::finalize; + + if (client_ != nullptr) + { + auto doc = document{} << "timestamp" << bsoncxx::types::b_date(msg.time) << "level" << level::to_string_view(msg.level).data() + << "level_num" << msg.level << "message" << std::string(msg.payload.begin(), msg.payload.end()) + << "logger_name" << std::string(msg.logger_name.begin(), msg.logger_name.end()) << "thread_id" + << static_cast(msg.thread_id) << finalize; + client_->database(db_name_).collection(coll_name_).insert_one(doc.view()); + } + } + + void flush_() override {} + +private: + std::shared_ptr instance_; + std::string db_name_; + std::string coll_name_; + std::unique_ptr client_ = nullptr; +}; + +#include "spdlog/details/null_mutex.h" +#include +using mongo_sink_mt = mongo_sink; +using mongo_sink_st = mongo_sink; + +} // namespace sinks + +template +inline std::shared_ptr mongo_logger_mt(const std::string &logger_name, const std::string &db_name, + const std::string &collection_name, const std::string &uri = "mongodb://localhost:27017") +{ + return Factory::template create(logger_name, db_name, collection_name, uri); +} + +template +inline std::shared_ptr mongo_logger_st(const std::string &logger_name, const std::string &db_name, + const std::string &collection_name, const std::string &uri = "mongodb://localhost:27017") +{ + return Factory::template create(logger_name, db_name, collection_name, uri); +} + +} // namespace spdlog diff --git a/tpl/spdlog/include/spdlog/sinks/msvc_sink.h b/tpl/spdlog/include/spdlog/sinks/msvc_sink.h new file mode 100644 index 0000000..bf68ae8 --- /dev/null +++ b/tpl/spdlog/include/spdlog/sinks/msvc_sink.h @@ -0,0 +1,71 @@ +// Copyright(c) 2016 Alexander Dalshov & spdlog contributors. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) + +#pragma once + +#if defined(_WIN32) + +# include +# if defined(SPDLOG_WCHAR_TO_UTF8_SUPPORT) +# include +# endif +# include + +# include +# include + +// Avoid including windows.h (https://stackoverflow.com/a/30741042) +# if defined(SPDLOG_WCHAR_TO_UTF8_SUPPORT) +extern "C" __declspec(dllimport) void __stdcall OutputDebugStringW(const wchar_t *lpOutputString); +# else +extern "C" __declspec(dllimport) void __stdcall OutputDebugStringA(const char *lpOutputString); +# endif +extern "C" __declspec(dllimport) int __stdcall IsDebuggerPresent(); + +namespace spdlog { +namespace sinks { +/* + * MSVC sink (logging using OutputDebugStringA) + */ +template +class msvc_sink : public base_sink +{ +public: + msvc_sink() = default; + msvc_sink(bool check_debugger_present) + : check_debugger_present_{check_debugger_present} {}; + +protected: + void sink_it_(const details::log_msg &msg) override + { + if (check_debugger_present_ && !IsDebuggerPresent()) + { + return; + } + memory_buf_t formatted; + base_sink::formatter_->format(msg, formatted); + formatted.push_back('\0'); // add a null terminator for OutputDebugString +# if defined(SPDLOG_WCHAR_TO_UTF8_SUPPORT) + wmemory_buf_t wformatted; + details::os::utf8_to_wstrbuf(string_view_t(formatted.data(), formatted.size()), wformatted); + OutputDebugStringW(wformatted.data()); +# else + OutputDebugStringA(formatted.data()); +# endif + } + + void flush_() override {} + + bool check_debugger_present_ = true; +}; + +using msvc_sink_mt = msvc_sink; +using msvc_sink_st = msvc_sink; + +using windebug_sink_mt = msvc_sink_mt; +using windebug_sink_st = msvc_sink_st; + +} // namespace sinks +} // namespace spdlog + +#endif diff --git a/tpl/spdlog/include/spdlog/sinks/null_sink.h b/tpl/spdlog/include/spdlog/sinks/null_sink.h new file mode 100644 index 0000000..eb83280 --- /dev/null +++ b/tpl/spdlog/include/spdlog/sinks/null_sink.h @@ -0,0 +1,44 @@ +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) + +#pragma once + +#include +#include +#include + +#include + +namespace spdlog { +namespace sinks { + +template +class null_sink : public base_sink +{ +protected: + void sink_it_(const details::log_msg &) override {} + void flush_() override {} +}; + +using null_sink_mt = null_sink; +using null_sink_st = null_sink; + +} // namespace sinks + +template +inline std::shared_ptr null_logger_mt(const std::string &logger_name) +{ + auto null_logger = Factory::template create(logger_name); + null_logger->set_level(level::off); + return null_logger; +} + +template +inline std::shared_ptr null_logger_st(const std::string &logger_name) +{ + auto null_logger = Factory::template create(logger_name); + null_logger->set_level(level::off); + return null_logger; +} + +} // namespace spdlog diff --git a/tpl/spdlog/include/spdlog/sinks/ostream_sink.h b/tpl/spdlog/include/spdlog/sinks/ostream_sink.h new file mode 100644 index 0000000..95c1e96 --- /dev/null +++ b/tpl/spdlog/include/spdlog/sinks/ostream_sink.h @@ -0,0 +1,50 @@ +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) + +#pragma once + +#include +#include + +#include +#include + +namespace spdlog { +namespace sinks { +template +class ostream_sink final : public base_sink +{ +public: + explicit ostream_sink(std::ostream &os, bool force_flush = false) + : ostream_(os) + , force_flush_(force_flush) + {} + ostream_sink(const ostream_sink &) = delete; + ostream_sink &operator=(const ostream_sink &) = delete; + +protected: + void sink_it_(const details::log_msg &msg) override + { + memory_buf_t formatted; + base_sink::formatter_->format(msg, formatted); + ostream_.write(formatted.data(), static_cast(formatted.size())); + if (force_flush_) + { + ostream_.flush(); + } + } + + void flush_() override + { + ostream_.flush(); + } + + std::ostream &ostream_; + bool force_flush_; +}; + +using ostream_sink_mt = ostream_sink; +using ostream_sink_st = ostream_sink; + +} // namespace sinks +} // namespace spdlog diff --git a/tpl/spdlog/include/spdlog/sinks/qt_sinks.h b/tpl/spdlog/include/spdlog/sinks/qt_sinks.h new file mode 100644 index 0000000..f801ac3 --- /dev/null +++ b/tpl/spdlog/include/spdlog/sinks/qt_sinks.h @@ -0,0 +1,292 @@ +// Copyright(c) 2015-present, Gabi Melman, mguludag and spdlog contributors. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) + +#pragma once + +// +// Custom sink for QPlainTextEdit or QTextEdit and its childs(QTextBrowser... +// etc) Building and using requires Qt library. +// +// Warning: the qt_sink won't be notified if the target widget is destroyed. +// If the widget's lifetime can be shorter than the logger's one, you should provide some permanent QObject, +// and then use a standard signal/slot. +// + +#include "spdlog/common.h" +#include "spdlog/details/log_msg.h" +#include "spdlog/details/synchronous_factory.h" +#include "spdlog/sinks/base_sink.h" +#include + +#include +#include + +// +// qt_sink class +// +namespace spdlog { +namespace sinks { +template +class qt_sink : public base_sink +{ +public: + qt_sink(QObject *qt_object, std::string meta_method) + : qt_object_(qt_object) + , meta_method_(std::move(meta_method)) + { + if (!qt_object_) + { + throw_spdlog_ex("qt_sink: qt_object is null"); + } + } + + ~qt_sink() + { + flush_(); + } + +protected: + void sink_it_(const details::log_msg &msg) override + { + memory_buf_t formatted; + base_sink::formatter_->format(msg, formatted); + const string_view_t str = string_view_t(formatted.data(), formatted.size()); + QMetaObject::invokeMethod(qt_object_, meta_method_.c_str(), Qt::AutoConnection, + Q_ARG(QString, QString::fromUtf8(str.data(), static_cast(str.size())).trimmed())); + } + + void flush_() override {} + +private: + QObject *qt_object_ = nullptr; + std::string meta_method_; +}; + +// QT color sink to QTextEdit. +// Color location is determined by the sink log pattern like in the rest of spdlog sinks. +// Colors can be modified if needed using sink->set_color(level, qtTextCharFormat). +// max_lines is the maximum number of lines that the sink will hold before removing the oldest lines. +// Note: Only ascii (latin1) is supported by this sink. +template +class qt_color_sink : public base_sink +{ +public: + qt_color_sink(QTextEdit *qt_text_edit, int max_lines) + : qt_text_edit_(qt_text_edit) + , max_lines_(max_lines) + { + if (!qt_text_edit_) + { + throw_spdlog_ex("qt_color_text_sink: text_edit is null"); + } + + default_color_ = qt_text_edit_->currentCharFormat(); + // set colors + QTextCharFormat format; + // trace + format.setForeground(Qt::gray); + colors_.at(level::trace) = format; + // debug + format.setForeground(Qt::cyan); + colors_.at(level::debug) = format; + // info + format.setForeground(Qt::green); + colors_.at(level::info) = format; + // warn + format.setForeground(Qt::yellow); + colors_.at(level::warn) = format; + // err + format.setForeground(Qt::red); + colors_.at(level::err) = format; + // critical + format.setForeground(Qt::white); + format.setBackground(Qt::red); + colors_.at(level::critical) = format; + } + + ~qt_color_sink() + { + flush_(); + } + + void set_default_color(QTextCharFormat format) + { + // std::lock_guard lock(base_sink::mutex_); + default_color_ = format; + } + + void set_level_color(level::level_enum color_level, QTextCharFormat format) + { + // std::lock_guard lock(base_sink::mutex_); + colors_.at(static_cast(color_level)) = format; + } + + QTextCharFormat &get_level_color(level::level_enum color_level) + { + std::lock_guard lock(base_sink::mutex_); + return colors_.at(static_cast(color_level)); + } + + QTextCharFormat &get_default_color() + { + std::lock_guard lock(base_sink::mutex_); + return default_color_; + } + +protected: + struct invoke_params + { + invoke_params(int max_lines, QTextEdit *q_text_edit, QString payload, QTextCharFormat default_color, QTextCharFormat level_color, + int color_range_start, int color_range_end) + : max_lines(max_lines) + , q_text_edit(q_text_edit) + , payload(std::move(payload)) + , default_color(default_color) + , level_color(level_color) + , color_range_start(color_range_start) + , color_range_end(color_range_end) + {} + int max_lines; + QTextEdit *q_text_edit; + QString payload; + QTextCharFormat default_color; + QTextCharFormat level_color; + int color_range_start; + int color_range_end; + }; + + void sink_it_(const details::log_msg &msg) override + { + memory_buf_t formatted; + base_sink::formatter_->format(msg, formatted); + + const string_view_t str = string_view_t(formatted.data(), formatted.size()); + // apply the color to the color range in the formatted message. + auto payload = QString::fromLatin1(str.data(), static_cast(str.size())); + + invoke_params params{max_lines_, // max lines + qt_text_edit_, // text edit to append to + std::move(payload), // text to append + default_color_, // default color + colors_.at(msg.level), // color to apply + static_cast(msg.color_range_start), // color range start + static_cast(msg.color_range_end)}; // color range end + + QMetaObject::invokeMethod( + qt_text_edit_, [params]() { invoke_method_(params); }, Qt::AutoConnection); + } + + void flush_() override {} + + // Add colored text to the text edit widget. This method is invoked in the GUI thread. + // It is a static method to ensure that it is handled correctly even if the sink is destroyed prematurely + // before it is invoked. + + static void invoke_method_(invoke_params params) + { + auto *document = params.q_text_edit->document(); + QTextCursor cursor(document); + + // remove first blocks if number of blocks exceeds max_lines + while (document->blockCount() > params.max_lines) + { + cursor.select(QTextCursor::BlockUnderCursor); + cursor.removeSelectedText(); + cursor.deleteChar(); // delete the newline after the block + } + + cursor.movePosition(QTextCursor::End); + cursor.setCharFormat(params.default_color); + + // if color range not specified or not not valid, just append the text with default color + if (params.color_range_end <= params.color_range_start) + { + cursor.insertText(params.payload); + return; + } + + // insert the text before the color range + cursor.insertText(params.payload.left(params.color_range_start)); + + // insert the colorized text + cursor.setCharFormat(params.level_color); + cursor.insertText(params.payload.mid(params.color_range_start, params.color_range_end - params.color_range_start)); + + // insert the text after the color range with default format + cursor.setCharFormat(params.default_color); + cursor.insertText(params.payload.mid(params.color_range_end)); + } + + QTextEdit *qt_text_edit_; + int max_lines_; + QTextCharFormat default_color_; + std::array colors_; +}; + +#include "spdlog/details/null_mutex.h" +#include + +using qt_sink_mt = qt_sink; +using qt_sink_st = qt_sink; +using qt_color_sink_mt = qt_color_sink; +using qt_color_sink_st = qt_color_sink; +} // namespace sinks + +// +// Factory functions +// + +// log to QTextEdit +template +inline std::shared_ptr qt_logger_mt(const std::string &logger_name, QTextEdit *qt_object, const std::string &meta_method = "append") +{ + return Factory::template create(logger_name, qt_object, meta_method); +} + +template +inline std::shared_ptr qt_logger_st(const std::string &logger_name, QTextEdit *qt_object, const std::string &meta_method = "append") +{ + return Factory::template create(logger_name, qt_object, meta_method); +} + +// log to QPlainTextEdit +template +inline std::shared_ptr qt_logger_mt( + const std::string &logger_name, QPlainTextEdit *qt_object, const std::string &meta_method = "appendPlainText") +{ + return Factory::template create(logger_name, qt_object, meta_method); +} + +template +inline std::shared_ptr qt_logger_st( + const std::string &logger_name, QPlainTextEdit *qt_object, const std::string &meta_method = "appendPlainText") +{ + return Factory::template create(logger_name, qt_object, meta_method); +} +// log to QObject +template +inline std::shared_ptr qt_logger_mt(const std::string &logger_name, QObject *qt_object, const std::string &meta_method) +{ + return Factory::template create(logger_name, qt_object, meta_method); +} + +template +inline std::shared_ptr qt_logger_st(const std::string &logger_name, QObject *qt_object, const std::string &meta_method) +{ + return Factory::template create(logger_name, qt_object, meta_method); +} + +// log to QTextEdit with colorize output +template +inline std::shared_ptr qt_color_logger_mt(const std::string &logger_name, QTextEdit *qt_text_edit, int max_lines) +{ + return Factory::template create(logger_name, qt_text_edit, max_lines); +} + +template +inline std::shared_ptr qt_color_logger_st(const std::string &logger_name, QTextEdit *qt_text_edit, int max_lines) +{ + return Factory::template create(logger_name, qt_text_edit, max_lines); +} + +} // namespace spdlog diff --git a/tpl/spdlog/include/spdlog/sinks/ringbuffer_sink.h b/tpl/spdlog/include/spdlog/sinks/ringbuffer_sink.h new file mode 100644 index 0000000..3ca47c6 --- /dev/null +++ b/tpl/spdlog/include/spdlog/sinks/ringbuffer_sink.h @@ -0,0 +1,74 @@ +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) + +#pragma once + +#include "spdlog/sinks/base_sink.h" +#include "spdlog/details/circular_q.h" +#include "spdlog/details/log_msg_buffer.h" +#include "spdlog/details/null_mutex.h" + +#include +#include +#include + +namespace spdlog { +namespace sinks { +/* + * Ring buffer sink + */ +template +class ringbuffer_sink final : public base_sink +{ +public: + explicit ringbuffer_sink(size_t n_items) + : q_{n_items} + {} + + std::vector last_raw(size_t lim = 0) + { + std::lock_guard lock(base_sink::mutex_); + auto items_available = q_.size(); + auto n_items = lim > 0 ? (std::min)(lim, items_available) : items_available; + std::vector ret; + ret.reserve(n_items); + for (size_t i = (items_available - n_items); i < items_available; i++) + { + ret.push_back(q_.at(i)); + } + return ret; + } + + std::vector last_formatted(size_t lim = 0) + { + std::lock_guard lock(base_sink::mutex_); + auto items_available = q_.size(); + auto n_items = lim > 0 ? (std::min)(lim, items_available) : items_available; + std::vector ret; + ret.reserve(n_items); + for (size_t i = (items_available - n_items); i < items_available; i++) + { + memory_buf_t formatted; + base_sink::formatter_->format(q_.at(i), formatted); + ret.push_back(SPDLOG_BUF_TO_STRING(formatted)); + } + return ret; + } + +protected: + void sink_it_(const details::log_msg &msg) override + { + q_.push_back(details::log_msg_buffer{msg}); + } + void flush_() override {} + +private: + details::circular_q q_; +}; + +using ringbuffer_sink_mt = ringbuffer_sink; +using ringbuffer_sink_st = ringbuffer_sink; + +} // namespace sinks + +} // namespace spdlog diff --git a/tpl/spdlog/include/spdlog/sinks/rotating_file_sink-inl.h b/tpl/spdlog/include/spdlog/sinks/rotating_file_sink-inl.h new file mode 100644 index 0000000..cf8b9d5 --- /dev/null +++ b/tpl/spdlog/include/spdlog/sinks/rotating_file_sink-inl.h @@ -0,0 +1,152 @@ +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) + +#pragma once + +#ifndef SPDLOG_HEADER_ONLY +# include +#endif + +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +namespace spdlog { +namespace sinks { + +template +SPDLOG_INLINE rotating_file_sink::rotating_file_sink( + filename_t base_filename, std::size_t max_size, std::size_t max_files, bool rotate_on_open, const file_event_handlers &event_handlers) + : base_filename_(std::move(base_filename)) + , max_size_(max_size) + , max_files_(max_files) + , file_helper_{event_handlers} +{ + if (max_size == 0) + { + throw_spdlog_ex("rotating sink constructor: max_size arg cannot be zero"); + } + + if (max_files > 200000) + { + throw_spdlog_ex("rotating sink constructor: max_files arg cannot exceed 200000"); + } + file_helper_.open(calc_filename(base_filename_, 0)); + current_size_ = file_helper_.size(); // expensive. called only once + if (rotate_on_open && current_size_ > 0) + { + rotate_(); + current_size_ = 0; + } +} + +// calc filename according to index and file extension if exists. +// e.g. calc_filename("logs/mylog.txt, 3) => "logs/mylog.3.txt". +template +SPDLOG_INLINE filename_t rotating_file_sink::calc_filename(const filename_t &filename, std::size_t index) +{ + if (index == 0u) + { + return filename; + } + + filename_t basename, ext; + std::tie(basename, ext) = details::file_helper::split_by_extension(filename); + return fmt_lib::format(SPDLOG_FILENAME_T("{}.{}{}"), basename, index, ext); +} + +template +SPDLOG_INLINE filename_t rotating_file_sink::filename() +{ + std::lock_guard lock(base_sink::mutex_); + return file_helper_.filename(); +} + +template +SPDLOG_INLINE void rotating_file_sink::sink_it_(const details::log_msg &msg) +{ + memory_buf_t formatted; + base_sink::formatter_->format(msg, formatted); + auto new_size = current_size_ + formatted.size(); + + // rotate if the new estimated file size exceeds max size. + // rotate only if the real size > 0 to better deal with full disk (see issue #2261). + // we only check the real size when new_size > max_size_ because it is relatively expensive. + if (new_size > max_size_) + { + file_helper_.flush(); + if (file_helper_.size() > 0) + { + rotate_(); + new_size = formatted.size(); + } + } + file_helper_.write(formatted); + current_size_ = new_size; +} + +template +SPDLOG_INLINE void rotating_file_sink::flush_() +{ + file_helper_.flush(); +} + +// Rotate files: +// log.txt -> log.1.txt +// log.1.txt -> log.2.txt +// log.2.txt -> log.3.txt +// log.3.txt -> delete +template +SPDLOG_INLINE void rotating_file_sink::rotate_() +{ + using details::os::filename_to_str; + using details::os::path_exists; + + file_helper_.close(); + for (auto i = max_files_; i > 0; --i) + { + filename_t src = calc_filename(base_filename_, i - 1); + if (!path_exists(src)) + { + continue; + } + filename_t target = calc_filename(base_filename_, i); + + if (!rename_file_(src, target)) + { + // if failed try again after a small delay. + // this is a workaround to a windows issue, where very high rotation + // rates can cause the rename to fail with permission denied (because of antivirus?). + details::os::sleep_for_millis(100); + if (!rename_file_(src, target)) + { + file_helper_.reopen(true); // truncate the log file anyway to prevent it to grow beyond its limit! + current_size_ = 0; + throw_spdlog_ex("rotating_file_sink: failed renaming " + filename_to_str(src) + " to " + filename_to_str(target), errno); + } + } + } + file_helper_.reopen(true); +} + +// delete the target if exists, and rename the src file to target +// return true on success, false otherwise. +template +SPDLOG_INLINE bool rotating_file_sink::rename_file_(const filename_t &src_filename, const filename_t &target_filename) +{ + // try to delete the target file in case it already exists. + (void)details::os::remove(target_filename); + return details::os::rename(src_filename, target_filename) == 0; +} + +} // namespace sinks +} // namespace spdlog diff --git a/tpl/spdlog/include/spdlog/sinks/rotating_file_sink.h b/tpl/spdlog/include/spdlog/sinks/rotating_file_sink.h new file mode 100644 index 0000000..ce0d7b1 --- /dev/null +++ b/tpl/spdlog/include/spdlog/sinks/rotating_file_sink.h @@ -0,0 +1,81 @@ +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) + +#pragma once + +#include +#include +#include +#include + +#include +#include +#include + +namespace spdlog { +namespace sinks { + +// +// Rotating file sink based on size +// +template +class rotating_file_sink final : public base_sink +{ +public: + rotating_file_sink(filename_t base_filename, std::size_t max_size, std::size_t max_files, bool rotate_on_open = false, + const file_event_handlers &event_handlers = {}); + static filename_t calc_filename(const filename_t &filename, std::size_t index); + filename_t filename(); + +protected: + void sink_it_(const details::log_msg &msg) override; + void flush_() override; + +private: + // Rotate files: + // log.txt -> log.1.txt + // log.1.txt -> log.2.txt + // log.2.txt -> log.3.txt + // log.3.txt -> delete + void rotate_(); + + // delete the target if exists, and rename the src file to target + // return true on success, false otherwise. + bool rename_file_(const filename_t &src_filename, const filename_t &target_filename); + + filename_t base_filename_; + std::size_t max_size_; + std::size_t max_files_; + std::size_t current_size_; + details::file_helper file_helper_; +}; + +using rotating_file_sink_mt = rotating_file_sink; +using rotating_file_sink_st = rotating_file_sink; + +} // namespace sinks + +// +// factory functions +// + +template +inline std::shared_ptr rotating_logger_mt(const std::string &logger_name, const filename_t &filename, size_t max_file_size, + size_t max_files, bool rotate_on_open = false, const file_event_handlers &event_handlers = {}) +{ + return Factory::template create( + logger_name, filename, max_file_size, max_files, rotate_on_open, event_handlers); +} + +template +inline std::shared_ptr rotating_logger_st(const std::string &logger_name, const filename_t &filename, size_t max_file_size, + size_t max_files, bool rotate_on_open = false, const file_event_handlers &event_handlers = {}) +{ + return Factory::template create( + logger_name, filename, max_file_size, max_files, rotate_on_open, event_handlers); +} +} // namespace spdlog + +#ifdef SPDLOG_HEADER_ONLY +# include "rotating_file_sink-inl.h" +#endif diff --git a/tpl/spdlog/include/spdlog/sinks/sink-inl.h b/tpl/spdlog/include/spdlog/sinks/sink-inl.h new file mode 100644 index 0000000..df07add --- /dev/null +++ b/tpl/spdlog/include/spdlog/sinks/sink-inl.h @@ -0,0 +1,25 @@ +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) + +#pragma once + +#ifndef SPDLOG_HEADER_ONLY +# include +#endif + +#include + +SPDLOG_INLINE bool spdlog::sinks::sink::should_log(spdlog::level::level_enum msg_level) const +{ + return msg_level >= level_.load(std::memory_order_relaxed); +} + +SPDLOG_INLINE void spdlog::sinks::sink::set_level(level::level_enum log_level) +{ + level_.store(log_level, std::memory_order_relaxed); +} + +SPDLOG_INLINE spdlog::level::level_enum spdlog::sinks::sink::level() const +{ + return static_cast(level_.load(std::memory_order_relaxed)); +} diff --git a/tpl/spdlog/include/spdlog/sinks/sink.h b/tpl/spdlog/include/spdlog/sinks/sink.h new file mode 100644 index 0000000..0a28ccc --- /dev/null +++ b/tpl/spdlog/include/spdlog/sinks/sink.h @@ -0,0 +1,35 @@ +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) + +#pragma once + +#include +#include + +namespace spdlog { + +namespace sinks { +class SPDLOG_API sink +{ +public: + virtual ~sink() = default; + virtual void log(const details::log_msg &msg) = 0; + virtual void flush() = 0; + virtual void set_pattern(const std::string &pattern) = 0; + virtual void set_formatter(std::unique_ptr sink_formatter) = 0; + + void set_level(level::level_enum log_level); + level::level_enum level() const; + bool should_log(level::level_enum msg_level) const; + +protected: + // sink log level - default is all + level_t level_{level::trace}; +}; + +} // namespace sinks +} // namespace spdlog + +#ifdef SPDLOG_HEADER_ONLY +# include "sink-inl.h" +#endif diff --git a/tpl/spdlog/include/spdlog/sinks/stdout_color_sinks-inl.h b/tpl/spdlog/include/spdlog/sinks/stdout_color_sinks-inl.h new file mode 100644 index 0000000..066df18 --- /dev/null +++ b/tpl/spdlog/include/spdlog/sinks/stdout_color_sinks-inl.h @@ -0,0 +1,38 @@ +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) + +#pragma once + +#ifndef SPDLOG_HEADER_ONLY +# include +#endif + +#include +#include + +namespace spdlog { + +template +SPDLOG_INLINE std::shared_ptr stdout_color_mt(const std::string &logger_name, color_mode mode) +{ + return Factory::template create(logger_name, mode); +} + +template +SPDLOG_INLINE std::shared_ptr stdout_color_st(const std::string &logger_name, color_mode mode) +{ + return Factory::template create(logger_name, mode); +} + +template +SPDLOG_INLINE std::shared_ptr stderr_color_mt(const std::string &logger_name, color_mode mode) +{ + return Factory::template create(logger_name, mode); +} + +template +SPDLOG_INLINE std::shared_ptr stderr_color_st(const std::string &logger_name, color_mode mode) +{ + return Factory::template create(logger_name, mode); +} +} // namespace spdlog diff --git a/tpl/spdlog/include/spdlog/sinks/stdout_color_sinks.h b/tpl/spdlog/include/spdlog/sinks/stdout_color_sinks.h new file mode 100644 index 0000000..420b13a --- /dev/null +++ b/tpl/spdlog/include/spdlog/sinks/stdout_color_sinks.h @@ -0,0 +1,45 @@ +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) + +#pragma once + +#ifdef _WIN32 +# include +#else +# include +#endif + +#include + +namespace spdlog { +namespace sinks { +#ifdef _WIN32 +using stdout_color_sink_mt = wincolor_stdout_sink_mt; +using stdout_color_sink_st = wincolor_stdout_sink_st; +using stderr_color_sink_mt = wincolor_stderr_sink_mt; +using stderr_color_sink_st = wincolor_stderr_sink_st; +#else +using stdout_color_sink_mt = ansicolor_stdout_sink_mt; +using stdout_color_sink_st = ansicolor_stdout_sink_st; +using stderr_color_sink_mt = ansicolor_stderr_sink_mt; +using stderr_color_sink_st = ansicolor_stderr_sink_st; +#endif +} // namespace sinks + +template +std::shared_ptr stdout_color_mt(const std::string &logger_name, color_mode mode = color_mode::automatic); + +template +std::shared_ptr stdout_color_st(const std::string &logger_name, color_mode mode = color_mode::automatic); + +template +std::shared_ptr stderr_color_mt(const std::string &logger_name, color_mode mode = color_mode::automatic); + +template +std::shared_ptr stderr_color_st(const std::string &logger_name, color_mode mode = color_mode::automatic); + +} // namespace spdlog + +#ifdef SPDLOG_HEADER_ONLY +# include "stdout_color_sinks-inl.h" +#endif diff --git a/tpl/spdlog/include/spdlog/sinks/stdout_sinks-inl.h b/tpl/spdlog/include/spdlog/sinks/stdout_sinks-inl.h new file mode 100644 index 0000000..c175437 --- /dev/null +++ b/tpl/spdlog/include/spdlog/sinks/stdout_sinks-inl.h @@ -0,0 +1,138 @@ +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) + +#pragma once + +#ifndef SPDLOG_HEADER_ONLY +# include +#endif + +#include +#include +#include + +#ifdef _WIN32 +// under windows using fwrite to non-binary stream results in \r\r\n (see issue #1675) +// so instead we use ::FileWrite +# include + +# ifndef _USING_V110_SDK71_ // fileapi.h doesn't exist in winxp +# include // WriteFile (..) +# endif + +# include // _get_osfhandle(..) +# include // _fileno(..) +#endif // WIN32 + +namespace spdlog { + +namespace sinks { + +template +SPDLOG_INLINE stdout_sink_base::stdout_sink_base(FILE *file) + : mutex_(ConsoleMutex::mutex()) + , file_(file) + , formatter_(details::make_unique()) +{ +#ifdef _WIN32 + // get windows handle from the FILE* object + + handle_ = reinterpret_cast(::_get_osfhandle(::_fileno(file_))); + + // don't throw to support cases where no console is attached, + // and let the log method to do nothing if (handle_ == INVALID_HANDLE_VALUE). + // throw only if non stdout/stderr target is requested (probably regular file and not console). + if (handle_ == INVALID_HANDLE_VALUE && file != stdout && file != stderr) + { + throw_spdlog_ex("spdlog::stdout_sink_base: _get_osfhandle() failed", errno); + } +#endif // WIN32 +} + +template +SPDLOG_INLINE void stdout_sink_base::log(const details::log_msg &msg) +{ +#ifdef _WIN32 + if (handle_ == INVALID_HANDLE_VALUE) + { + return; + } + std::lock_guard lock(mutex_); + memory_buf_t formatted; + formatter_->format(msg, formatted); + auto size = static_cast(formatted.size()); + DWORD bytes_written = 0; + bool ok = ::WriteFile(handle_, formatted.data(), size, &bytes_written, nullptr) != 0; + if (!ok) + { + throw_spdlog_ex("stdout_sink_base: WriteFile() failed. GetLastError(): " + std::to_string(::GetLastError())); + } +#else + std::lock_guard lock(mutex_); + memory_buf_t formatted; + formatter_->format(msg, formatted); + ::fwrite(formatted.data(), sizeof(char), formatted.size(), file_); +#endif // WIN32 + ::fflush(file_); // flush every line to terminal +} + +template +SPDLOG_INLINE void stdout_sink_base::flush() +{ + std::lock_guard lock(mutex_); + fflush(file_); +} + +template +SPDLOG_INLINE void stdout_sink_base::set_pattern(const std::string &pattern) +{ + std::lock_guard lock(mutex_); + formatter_ = std::unique_ptr(new pattern_formatter(pattern)); +} + +template +SPDLOG_INLINE void stdout_sink_base::set_formatter(std::unique_ptr sink_formatter) +{ + std::lock_guard lock(mutex_); + formatter_ = std::move(sink_formatter); +} + +// stdout sink +template +SPDLOG_INLINE stdout_sink::stdout_sink() + : stdout_sink_base(stdout) +{} + +// stderr sink +template +SPDLOG_INLINE stderr_sink::stderr_sink() + : stdout_sink_base(stderr) +{} + +} // namespace sinks + +// factory methods +template +SPDLOG_INLINE std::shared_ptr stdout_logger_mt(const std::string &logger_name) +{ + return Factory::template create(logger_name); +} + +template +SPDLOG_INLINE std::shared_ptr stdout_logger_st(const std::string &logger_name) +{ + return Factory::template create(logger_name); +} + +template +SPDLOG_INLINE std::shared_ptr stderr_logger_mt(const std::string &logger_name) +{ + return Factory::template create(logger_name); +} + +template +SPDLOG_INLINE std::shared_ptr stderr_logger_st(const std::string &logger_name) +{ + return Factory::template create(logger_name); +} +} // namespace spdlog diff --git a/tpl/spdlog/include/spdlog/sinks/stdout_sinks.h b/tpl/spdlog/include/spdlog/sinks/stdout_sinks.h new file mode 100644 index 0000000..6fdc0de --- /dev/null +++ b/tpl/spdlog/include/spdlog/sinks/stdout_sinks.h @@ -0,0 +1,87 @@ +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) + +#pragma once + +#include +#include +#include +#include + +#ifdef _WIN32 +# include +#endif + +namespace spdlog { + +namespace sinks { + +template +class stdout_sink_base : public sink +{ +public: + using mutex_t = typename ConsoleMutex::mutex_t; + explicit stdout_sink_base(FILE *file); + ~stdout_sink_base() override = default; + + stdout_sink_base(const stdout_sink_base &other) = delete; + stdout_sink_base(stdout_sink_base &&other) = delete; + + stdout_sink_base &operator=(const stdout_sink_base &other) = delete; + stdout_sink_base &operator=(stdout_sink_base &&other) = delete; + + void log(const details::log_msg &msg) override; + void flush() override; + void set_pattern(const std::string &pattern) override; + + void set_formatter(std::unique_ptr sink_formatter) override; + +protected: + mutex_t &mutex_; + FILE *file_; + std::unique_ptr formatter_; +#ifdef _WIN32 + HANDLE handle_; +#endif // WIN32 +}; + +template +class stdout_sink : public stdout_sink_base +{ +public: + stdout_sink(); +}; + +template +class stderr_sink : public stdout_sink_base +{ +public: + stderr_sink(); +}; + +using stdout_sink_mt = stdout_sink; +using stdout_sink_st = stdout_sink; + +using stderr_sink_mt = stderr_sink; +using stderr_sink_st = stderr_sink; + +} // namespace sinks + +// factory methods +template +std::shared_ptr stdout_logger_mt(const std::string &logger_name); + +template +std::shared_ptr stdout_logger_st(const std::string &logger_name); + +template +std::shared_ptr stderr_logger_mt(const std::string &logger_name); + +template +std::shared_ptr stderr_logger_st(const std::string &logger_name); + +} // namespace spdlog + +#ifdef SPDLOG_HEADER_ONLY +# include "stdout_sinks-inl.h" +#endif diff --git a/tpl/spdlog/include/spdlog/sinks/syslog_sink.h b/tpl/spdlog/include/spdlog/sinks/syslog_sink.h new file mode 100644 index 0000000..7c38fcb --- /dev/null +++ b/tpl/spdlog/include/spdlog/sinks/syslog_sink.h @@ -0,0 +1,109 @@ +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) + +#pragma once + +#include +#include +#include + +#include +#include +#include + +namespace spdlog { +namespace sinks { +/** + * Sink that write to syslog using the `syscall()` library call. + */ +template +class syslog_sink : public base_sink +{ + +public: + syslog_sink(std::string ident, int syslog_option, int syslog_facility, bool enable_formatting) + : enable_formatting_{enable_formatting} + , syslog_levels_{{/* spdlog::level::trace */ LOG_DEBUG, + /* spdlog::level::debug */ LOG_DEBUG, + /* spdlog::level::info */ LOG_INFO, + /* spdlog::level::warn */ LOG_WARNING, + /* spdlog::level::err */ LOG_ERR, + /* spdlog::level::critical */ LOG_CRIT, + /* spdlog::level::off */ LOG_INFO}} + , ident_{std::move(ident)} + { + // set ident to be program name if empty + ::openlog(ident_.empty() ? nullptr : ident_.c_str(), syslog_option, syslog_facility); + } + + ~syslog_sink() override + { + ::closelog(); + } + + syslog_sink(const syslog_sink &) = delete; + syslog_sink &operator=(const syslog_sink &) = delete; + +protected: + void sink_it_(const details::log_msg &msg) override + { + string_view_t payload; + memory_buf_t formatted; + if (enable_formatting_) + { + base_sink::formatter_->format(msg, formatted); + payload = string_view_t(formatted.data(), formatted.size()); + } + else + { + payload = msg.payload; + } + + size_t length = payload.size(); + // limit to max int + if (length > static_cast(std::numeric_limits::max())) + { + length = static_cast(std::numeric_limits::max()); + } + + ::syslog(syslog_prio_from_level(msg), "%.*s", static_cast(length), payload.data()); + } + + void flush_() override {} + bool enable_formatting_ = false; + +private: + using levels_array = std::array; + levels_array syslog_levels_; + // must store the ident because the man says openlog might use the pointer as + // is and not a string copy + const std::string ident_; + + // + // Simply maps spdlog's log level to syslog priority level. + // + int syslog_prio_from_level(const details::log_msg &msg) const + { + return syslog_levels_.at(static_cast(msg.level)); + } +}; + +using syslog_sink_mt = syslog_sink; +using syslog_sink_st = syslog_sink; +} // namespace sinks + +// Create and register a syslog logger +template +inline std::shared_ptr syslog_logger_mt(const std::string &logger_name, const std::string &syslog_ident = "", int syslog_option = 0, + int syslog_facility = LOG_USER, bool enable_formatting = false) +{ + return Factory::template create(logger_name, syslog_ident, syslog_option, syslog_facility, enable_formatting); +} + +template +inline std::shared_ptr syslog_logger_st(const std::string &logger_name, const std::string &syslog_ident = "", int syslog_option = 0, + int syslog_facility = LOG_USER, bool enable_formatting = false) +{ + return Factory::template create(logger_name, syslog_ident, syslog_option, syslog_facility, enable_formatting); +} +} // namespace spdlog diff --git a/tpl/spdlog/include/spdlog/sinks/systemd_sink.h b/tpl/spdlog/include/spdlog/sinks/systemd_sink.h new file mode 100644 index 0000000..b00a95f --- /dev/null +++ b/tpl/spdlog/include/spdlog/sinks/systemd_sink.h @@ -0,0 +1,126 @@ +// Copyright(c) 2019 ZVYAGIN.Alexander@gmail.com +// Distributed under the MIT License (http://opensource.org/licenses/MIT) + +#pragma once + +#include +#include +#include +#include + +#include +#ifndef SD_JOURNAL_SUPPRESS_LOCATION +# define SD_JOURNAL_SUPPRESS_LOCATION +#endif +#include + +namespace spdlog { +namespace sinks { + +/** + * Sink that write to systemd journal using the `sd_journal_send()` library call. + */ +template +class systemd_sink : public base_sink +{ +public: + systemd_sink(std::string ident = "", bool enable_formatting = false) + : ident_{std::move(ident)} + , enable_formatting_{enable_formatting} + , syslog_levels_{{/* spdlog::level::trace */ LOG_DEBUG, + /* spdlog::level::debug */ LOG_DEBUG, + /* spdlog::level::info */ LOG_INFO, + /* spdlog::level::warn */ LOG_WARNING, + /* spdlog::level::err */ LOG_ERR, + /* spdlog::level::critical */ LOG_CRIT, + /* spdlog::level::off */ LOG_INFO}} + {} + + ~systemd_sink() override {} + + systemd_sink(const systemd_sink &) = delete; + systemd_sink &operator=(const systemd_sink &) = delete; + +protected: + const std::string ident_; + bool enable_formatting_ = false; + using levels_array = std::array; + levels_array syslog_levels_; + + void sink_it_(const details::log_msg &msg) override + { + int err; + string_view_t payload; + memory_buf_t formatted; + if (enable_formatting_) + { + base_sink::formatter_->format(msg, formatted); + payload = string_view_t(formatted.data(), formatted.size()); + } + else + { + payload = msg.payload; + } + + size_t length = payload.size(); + // limit to max int + if (length > static_cast(std::numeric_limits::max())) + { + length = static_cast(std::numeric_limits::max()); + } + + const string_view_t syslog_identifier = ident_.empty() ? msg.logger_name : ident_; + + // Do not send source location if not available + if (msg.source.empty()) + { + // Note: function call inside '()' to avoid macro expansion + err = (sd_journal_send)("MESSAGE=%.*s", static_cast(length), payload.data(), "PRIORITY=%d", syslog_level(msg.level), +#ifndef SPDLOG_NO_THREAD_ID + "TID=%zu", details::os::thread_id(), +#endif + "SYSLOG_IDENTIFIER=%.*s", static_cast(syslog_identifier.size()), syslog_identifier.data(), nullptr); + } + else + { + err = (sd_journal_send)("MESSAGE=%.*s", static_cast(length), payload.data(), "PRIORITY=%d", syslog_level(msg.level), +#ifndef SPDLOG_NO_THREAD_ID + "TID=%zu", details::os::thread_id(), +#endif + "SYSLOG_IDENTIFIER=%.*s", static_cast(syslog_identifier.size()), syslog_identifier.data(), "CODE_FILE=%s", + msg.source.filename, "CODE_LINE=%d", msg.source.line, "CODE_FUNC=%s", msg.source.funcname, nullptr); + } + + if (err) + { + throw_spdlog_ex("Failed writing to systemd", errno); + } + } + + int syslog_level(level::level_enum l) + { + return syslog_levels_.at(static_cast(l)); + } + + void flush_() override {} +}; + +using systemd_sink_mt = systemd_sink; +using systemd_sink_st = systemd_sink; +} // namespace sinks + +// Create and register a syslog logger +template +inline std::shared_ptr systemd_logger_mt( + const std::string &logger_name, const std::string &ident = "", bool enable_formatting = false) +{ + return Factory::template create(logger_name, ident, enable_formatting); +} + +template +inline std::shared_ptr systemd_logger_st( + const std::string &logger_name, const std::string &ident = "", bool enable_formatting = false) +{ + return Factory::template create(logger_name, ident, enable_formatting); +} +} // namespace spdlog diff --git a/tpl/spdlog/include/spdlog/sinks/tcp_sink.h b/tpl/spdlog/include/spdlog/sinks/tcp_sink.h new file mode 100644 index 0000000..e0efb31 --- /dev/null +++ b/tpl/spdlog/include/spdlog/sinks/tcp_sink.h @@ -0,0 +1,81 @@ +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) + +#pragma once + +#include +#include +#include +#ifdef _WIN32 +# include +#else +# include +#endif + +#include +#include +#include +#include + +#pragma once + +// Simple tcp client sink +// Connects to remote address and send the formatted log. +// Will attempt to reconnect if connection drops. +// If more complicated behaviour is needed (i.e get responses), you can inherit it and override the sink_it_ method. + +namespace spdlog { +namespace sinks { + +struct tcp_sink_config +{ + std::string server_host; + int server_port; + bool lazy_connect = false; // if true connect on first log call instead of on construction + + tcp_sink_config(std::string host, int port) + : server_host{std::move(host)} + , server_port{port} + {} +}; + +template +class tcp_sink : public spdlog::sinks::base_sink +{ +public: + // connect to tcp host/port or throw if failed + // host can be hostname or ip address + + explicit tcp_sink(tcp_sink_config sink_config) + : config_{std::move(sink_config)} + { + if (!config_.lazy_connect) + { + this->client_.connect(config_.server_host, config_.server_port); + } + } + + ~tcp_sink() override = default; + +protected: + void sink_it_(const spdlog::details::log_msg &msg) override + { + spdlog::memory_buf_t formatted; + spdlog::sinks::base_sink::formatter_->format(msg, formatted); + if (!client_.is_connected()) + { + client_.connect(config_.server_host, config_.server_port); + } + client_.send(formatted.data(), formatted.size()); + } + + void flush_() override {} + tcp_sink_config config_; + details::tcp_client client_; +}; + +using tcp_sink_mt = tcp_sink; +using tcp_sink_st = tcp_sink; + +} // namespace sinks +} // namespace spdlog diff --git a/tpl/spdlog/include/spdlog/sinks/udp_sink.h b/tpl/spdlog/include/spdlog/sinks/udp_sink.h new file mode 100644 index 0000000..ccbce2b --- /dev/null +++ b/tpl/spdlog/include/spdlog/sinks/udp_sink.h @@ -0,0 +1,74 @@ +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) + +#pragma once + +#include +#include +#include +#ifdef _WIN32 +# include +#else +# include +#endif + +#include +#include +#include +#include + +// Simple udp client sink +// Sends formatted log via udp + +namespace spdlog { +namespace sinks { + +struct udp_sink_config +{ + std::string server_host; + uint16_t server_port; + + udp_sink_config(std::string host, uint16_t port) + : server_host{std::move(host)} + , server_port{port} + {} +}; + +template +class udp_sink : public spdlog::sinks::base_sink +{ +public: + // host can be hostname or ip address + explicit udp_sink(udp_sink_config sink_config) + : client_{sink_config.server_host, sink_config.server_port} + {} + + ~udp_sink() override = default; + +protected: + void sink_it_(const spdlog::details::log_msg &msg) override + { + spdlog::memory_buf_t formatted; + spdlog::sinks::base_sink::formatter_->format(msg, formatted); + client_.send(formatted.data(), formatted.size()); + } + + void flush_() override {} + details::udp_client client_; +}; + +using udp_sink_mt = udp_sink; +using udp_sink_st = udp_sink; + +} // namespace sinks + +// +// factory functions +// +template +inline std::shared_ptr udp_logger_mt(const std::string &logger_name, sinks::udp_sink_config skin_config) +{ + return Factory::template create(logger_name, skin_config); +} + +} // namespace spdlog diff --git a/tpl/spdlog/include/spdlog/sinks/win_eventlog_sink.h b/tpl/spdlog/include/spdlog/sinks/win_eventlog_sink.h new file mode 100644 index 0000000..d23d00a --- /dev/null +++ b/tpl/spdlog/include/spdlog/sinks/win_eventlog_sink.h @@ -0,0 +1,289 @@ +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) + +// Writing to Windows Event Log requires the registry entries below to be present, with the following modifications: +// 1. should be replaced with your log name (e.g. your application name) +// 2. should be replaced with the specific source name and the key should be duplicated for +// each source used in the application +// +// Since typically modifications of this kind require elevation, it's better to do it as a part of setup procedure. +// The snippet below uses mscoree.dll as the message file as it exists on most of the Windows systems anyway and +// happens to contain the needed resource. +// +// You can also specify a custom message file if needed. +// Please refer to Event Log functions descriptions in MSDN for more details on custom message files. + +/*--------------------------------------------------------------------------------------- + +Windows Registry Editor Version 5.00 + +[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\EventLog\] + +[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\EventLog\\] +"TypesSupported"=dword:00000007 +"EventMessageFile"=hex(2):25,00,73,00,79,00,73,00,74,00,65,00,6d,00,72,00,6f,\ + 00,6f,00,74,00,25,00,5c,00,53,00,79,00,73,00,74,00,65,00,6d,00,33,00,32,00,\ + 5c,00,6d,00,73,00,63,00,6f,00,72,00,65,00,65,00,2e,00,64,00,6c,00,6c,00,00,\ + 00 + +-----------------------------------------------------------------------------------------*/ + +#pragma once + +#include +#include + +#include +#include + +#include +#include +#include + +namespace spdlog { +namespace sinks { + +namespace win_eventlog { + +namespace internal { + +struct local_alloc_t +{ + HLOCAL hlocal_; + + SPDLOG_CONSTEXPR local_alloc_t() SPDLOG_NOEXCEPT : hlocal_(nullptr) {} + + local_alloc_t(local_alloc_t const &) = delete; + local_alloc_t &operator=(local_alloc_t const &) = delete; + + ~local_alloc_t() SPDLOG_NOEXCEPT + { + if (hlocal_) + { + LocalFree(hlocal_); + } + } +}; + +/** Windows error */ +struct win32_error : public spdlog_ex +{ + /** Formats an error report line: "user-message: error-code (system message)" */ + static std::string format(std::string const &user_message, DWORD error_code = GetLastError()) + { + std::string system_message; + + local_alloc_t format_message_result{}; + auto format_message_succeeded = + ::FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, nullptr, + error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&format_message_result.hlocal_, 0, nullptr); + + if (format_message_succeeded && format_message_result.hlocal_) + { + system_message = fmt_lib::format(" ({})", (LPSTR)format_message_result.hlocal_); + } + + return fmt_lib::format("{}: {}{}", user_message, error_code, system_message); + } + + explicit win32_error(std::string const &func_name, DWORD error = GetLastError()) + : spdlog_ex(format(func_name, error)) + {} +}; + +/** Wrapper for security identifiers (SID) on Windows */ +struct sid_t +{ + std::vector buffer_; + +public: + sid_t() {} + + /** creates a wrapped SID copy */ + static sid_t duplicate_sid(PSID psid) + { + if (!::IsValidSid(psid)) + { + throw_spdlog_ex("sid_t::sid_t(): invalid SID received"); + } + + auto const sid_length{::GetLengthSid(psid)}; + + sid_t result; + result.buffer_.resize(sid_length); + if (!::CopySid(sid_length, (PSID)result.as_sid(), psid)) + { + SPDLOG_THROW(win32_error("CopySid")); + } + + return result; + } + + /** Retrieves pointer to the internal buffer contents as SID* */ + SID *as_sid() const + { + return buffer_.empty() ? nullptr : (SID *)buffer_.data(); + } + + /** Get SID for the current user */ + static sid_t get_current_user_sid() + { + /* create and init RAII holder for process token */ + struct process_token_t + { + HANDLE token_handle_ = INVALID_HANDLE_VALUE; + explicit process_token_t(HANDLE process) + { + if (!::OpenProcessToken(process, TOKEN_QUERY, &token_handle_)) + { + SPDLOG_THROW(win32_error("OpenProcessToken")); + } + } + + ~process_token_t() + { + ::CloseHandle(token_handle_); + } + + } current_process_token(::GetCurrentProcess()); // GetCurrentProcess returns pseudohandle, no leak here! + + // Get the required size, this is expected to fail with ERROR_INSUFFICIENT_BUFFER and return the token size + DWORD tusize = 0; + if (::GetTokenInformation(current_process_token.token_handle_, TokenUser, NULL, 0, &tusize)) + { + SPDLOG_THROW(win32_error("GetTokenInformation should fail")); + } + + // get user token + std::vector buffer(static_cast(tusize)); + if (!::GetTokenInformation(current_process_token.token_handle_, TokenUser, (LPVOID)buffer.data(), tusize, &tusize)) + { + SPDLOG_THROW(win32_error("GetTokenInformation")); + } + + // create a wrapper of the SID data as stored in the user token + return sid_t::duplicate_sid(((TOKEN_USER *)buffer.data())->User.Sid); + } +}; + +struct eventlog +{ + static WORD get_event_type(details::log_msg const &msg) + { + switch (msg.level) + { + case level::trace: + case level::debug: + return EVENTLOG_SUCCESS; + + case level::info: + return EVENTLOG_INFORMATION_TYPE; + + case level::warn: + return EVENTLOG_WARNING_TYPE; + + case level::err: + case level::critical: + case level::off: + return EVENTLOG_ERROR_TYPE; + + default: + return EVENTLOG_INFORMATION_TYPE; + } + } + + static WORD get_event_category(details::log_msg const &msg) + { + return (WORD)msg.level; + } +}; + +} // namespace internal + +/* + * Windows Event Log sink + */ +template +class win_eventlog_sink : public base_sink +{ +private: + HANDLE hEventLog_{NULL}; + internal::sid_t current_user_sid_; + std::string source_; + DWORD event_id_; + + HANDLE event_log_handle() + { + if (!hEventLog_) + { + hEventLog_ = ::RegisterEventSourceA(nullptr, source_.c_str()); + if (!hEventLog_ || hEventLog_ == (HANDLE)ERROR_ACCESS_DENIED) + { + SPDLOG_THROW(internal::win32_error("RegisterEventSource")); + } + } + + return hEventLog_; + } + +protected: + void sink_it_(const details::log_msg &msg) override + { + using namespace internal; + + bool succeeded; + memory_buf_t formatted; + base_sink::formatter_->format(msg, formatted); + formatted.push_back('\0'); + +#ifdef SPDLOG_WCHAR_TO_UTF8_SUPPORT + wmemory_buf_t buf; + details::os::utf8_to_wstrbuf(string_view_t(formatted.data(), formatted.size()), buf); + + LPCWSTR lp_wstr = buf.data(); + succeeded = static_cast(::ReportEventW(event_log_handle(), eventlog::get_event_type(msg), eventlog::get_event_category(msg), + event_id_, current_user_sid_.as_sid(), 1, 0, &lp_wstr, nullptr)); +#else + LPCSTR lp_str = formatted.data(); + succeeded = static_cast(::ReportEventA(event_log_handle(), eventlog::get_event_type(msg), eventlog::get_event_category(msg), + event_id_, current_user_sid_.as_sid(), 1, 0, &lp_str, nullptr)); +#endif + + if (!succeeded) + { + SPDLOG_THROW(win32_error("ReportEvent")); + } + } + + void flush_() override {} + +public: + win_eventlog_sink(std::string const &source, DWORD event_id = 1000 /* according to mscoree.dll */) + : source_(source) + , event_id_(event_id) + { + try + { + current_user_sid_ = internal::sid_t::get_current_user_sid(); + } + catch (...) + { + // get_current_user_sid() is unlikely to fail and if it does, we can still proceed without + // current_user_sid but in the event log the record will have no user name + } + } + + ~win_eventlog_sink() + { + if (hEventLog_) + DeregisterEventSource(hEventLog_); + } +}; + +} // namespace win_eventlog + +using win_eventlog_sink_mt = win_eventlog::win_eventlog_sink; +using win_eventlog_sink_st = win_eventlog::win_eventlog_sink; + +} // namespace sinks +} // namespace spdlog diff --git a/tpl/spdlog/include/spdlog/sinks/wincolor_sink-inl.h b/tpl/spdlog/include/spdlog/sinks/wincolor_sink-inl.h new file mode 100644 index 0000000..8311929 --- /dev/null +++ b/tpl/spdlog/include/spdlog/sinks/wincolor_sink-inl.h @@ -0,0 +1,175 @@ +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) + +#pragma once + +#ifndef SPDLOG_HEADER_ONLY +# include +#endif + +#include +#include + +#include +#include + +namespace spdlog { +namespace sinks { +template +SPDLOG_INLINE wincolor_sink::wincolor_sink(void *out_handle, color_mode mode) + : out_handle_(out_handle) + , mutex_(ConsoleMutex::mutex()) + , formatter_(details::make_unique()) +{ + + set_color_mode_impl(mode); + // set level colors + colors_[level::trace] = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE; // white + colors_[level::debug] = FOREGROUND_GREEN | FOREGROUND_BLUE; // cyan + colors_[level::info] = FOREGROUND_GREEN; // green + colors_[level::warn] = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY; // intense yellow + colors_[level::err] = FOREGROUND_RED | FOREGROUND_INTENSITY; // intense red + colors_[level::critical] = + BACKGROUND_RED | FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY; // intense white on red background + colors_[level::off] = 0; +} + +template +SPDLOG_INLINE wincolor_sink::~wincolor_sink() +{ + this->flush(); +} + +// change the color for the given level +template +void SPDLOG_INLINE wincolor_sink::set_color(level::level_enum level, std::uint16_t color) +{ + std::lock_guard lock(mutex_); + colors_[static_cast(level)] = color; +} + +template +void SPDLOG_INLINE wincolor_sink::log(const details::log_msg &msg) +{ + if (out_handle_ == nullptr || out_handle_ == INVALID_HANDLE_VALUE) + { + return; + } + + std::lock_guard lock(mutex_); + msg.color_range_start = 0; + msg.color_range_end = 0; + memory_buf_t formatted; + formatter_->format(msg, formatted); + if (should_do_colors_ && msg.color_range_end > msg.color_range_start) + { + // before color range + print_range_(formatted, 0, msg.color_range_start); + // in color range + auto orig_attribs = static_cast(set_foreground_color_(colors_[static_cast(msg.level)])); + print_range_(formatted, msg.color_range_start, msg.color_range_end); + // reset to orig colors + ::SetConsoleTextAttribute(static_cast(out_handle_), orig_attribs); + print_range_(formatted, msg.color_range_end, formatted.size()); + } + else // print without colors if color range is invalid (or color is disabled) + { + write_to_file_(formatted); + } +} + +template +void SPDLOG_INLINE wincolor_sink::flush() +{ + // windows console always flushed? +} + +template +void SPDLOG_INLINE wincolor_sink::set_pattern(const std::string &pattern) +{ + std::lock_guard lock(mutex_); + formatter_ = std::unique_ptr(new pattern_formatter(pattern)); +} + +template +void SPDLOG_INLINE wincolor_sink::set_formatter(std::unique_ptr sink_formatter) +{ + std::lock_guard lock(mutex_); + formatter_ = std::move(sink_formatter); +} + +template +void SPDLOG_INLINE wincolor_sink::set_color_mode(color_mode mode) +{ + std::lock_guard lock(mutex_); + set_color_mode_impl(mode); +} + +template +void SPDLOG_INLINE wincolor_sink::set_color_mode_impl(color_mode mode) +{ + if (mode == color_mode::automatic) + { + // should do colors only if out_handle_ points to actual console. + DWORD console_mode; + bool in_console = ::GetConsoleMode(static_cast(out_handle_), &console_mode) != 0; + should_do_colors_ = in_console; + } + else + { + should_do_colors_ = mode == color_mode::always ? true : false; + } +} + +// set foreground color and return the orig console attributes (for resetting later) +template +std::uint16_t SPDLOG_INLINE wincolor_sink::set_foreground_color_(std::uint16_t attribs) +{ + CONSOLE_SCREEN_BUFFER_INFO orig_buffer_info; + if (!::GetConsoleScreenBufferInfo(static_cast(out_handle_), &orig_buffer_info)) + { + // just return white if failed getting console info + return FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE; + } + + // change only the foreground bits (lowest 4 bits) + auto new_attribs = static_cast(attribs) | (orig_buffer_info.wAttributes & 0xfff0); + auto ignored = ::SetConsoleTextAttribute(static_cast(out_handle_), static_cast(new_attribs)); + (void)(ignored); + return static_cast(orig_buffer_info.wAttributes); // return orig attribs +} + +// print a range of formatted message to console +template +void SPDLOG_INLINE wincolor_sink::print_range_(const memory_buf_t &formatted, size_t start, size_t end) +{ + if (end > start) + { + auto size = static_cast(end - start); + auto ignored = ::WriteConsoleA(static_cast(out_handle_), formatted.data() + start, size, nullptr, nullptr); + (void)(ignored); + } +} + +template +void SPDLOG_INLINE wincolor_sink::write_to_file_(const memory_buf_t &formatted) +{ + auto size = static_cast(formatted.size()); + DWORD bytes_written = 0; + auto ignored = ::WriteFile(static_cast(out_handle_), formatted.data(), size, &bytes_written, nullptr); + (void)(ignored); +} + +// wincolor_stdout_sink +template +SPDLOG_INLINE wincolor_stdout_sink::wincolor_stdout_sink(color_mode mode) + : wincolor_sink(::GetStdHandle(STD_OUTPUT_HANDLE), mode) +{} + +// wincolor_stderr_sink +template +SPDLOG_INLINE wincolor_stderr_sink::wincolor_stderr_sink(color_mode mode) + : wincolor_sink(::GetStdHandle(STD_ERROR_HANDLE), mode) +{} +} // namespace sinks +} // namespace spdlog diff --git a/tpl/spdlog/include/spdlog/sinks/wincolor_sink.h b/tpl/spdlog/include/spdlog/sinks/wincolor_sink.h new file mode 100644 index 0000000..9b030fc --- /dev/null +++ b/tpl/spdlog/include/spdlog/sinks/wincolor_sink.h @@ -0,0 +1,85 @@ +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) + +#pragma once + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +namespace spdlog { +namespace sinks { +/* + * Windows color console sink. Uses WriteConsoleA to write to the console with + * colors + */ +template +class wincolor_sink : public sink +{ +public: + wincolor_sink(void *out_handle, color_mode mode); + ~wincolor_sink() override; + + wincolor_sink(const wincolor_sink &other) = delete; + wincolor_sink &operator=(const wincolor_sink &other) = delete; + + // change the color for the given level + void set_color(level::level_enum level, std::uint16_t color); + void log(const details::log_msg &msg) final override; + void flush() final override; + void set_pattern(const std::string &pattern) override final; + void set_formatter(std::unique_ptr sink_formatter) override final; + void set_color_mode(color_mode mode); + +protected: + using mutex_t = typename ConsoleMutex::mutex_t; + void *out_handle_; + mutex_t &mutex_; + bool should_do_colors_; + std::unique_ptr formatter_; + std::array colors_; + + // set foreground color and return the orig console attributes (for resetting later) + std::uint16_t set_foreground_color_(std::uint16_t attribs); + + // print a range of formatted message to console + void print_range_(const memory_buf_t &formatted, size_t start, size_t end); + + // in case we are redirected to file (not in console mode) + void write_to_file_(const memory_buf_t &formatted); + + void set_color_mode_impl(color_mode mode); +}; + +template +class wincolor_stdout_sink : public wincolor_sink +{ +public: + explicit wincolor_stdout_sink(color_mode mode = color_mode::automatic); +}; + +template +class wincolor_stderr_sink : public wincolor_sink +{ +public: + explicit wincolor_stderr_sink(color_mode mode = color_mode::automatic); +}; + +using wincolor_stdout_sink_mt = wincolor_stdout_sink; +using wincolor_stdout_sink_st = wincolor_stdout_sink; + +using wincolor_stderr_sink_mt = wincolor_stderr_sink; +using wincolor_stderr_sink_st = wincolor_stderr_sink; +} // namespace sinks +} // namespace spdlog + +#ifdef SPDLOG_HEADER_ONLY +# include "wincolor_sink-inl.h" +#endif diff --git a/tpl/spdlog/include/spdlog/spdlog-inl.h b/tpl/spdlog/include/spdlog/spdlog-inl.h new file mode 100644 index 0000000..22ea22b --- /dev/null +++ b/tpl/spdlog/include/spdlog/spdlog-inl.h @@ -0,0 +1,125 @@ +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) + +#pragma once + +#ifndef SPDLOG_HEADER_ONLY +# include +#endif + +#include +#include + +namespace spdlog { + +SPDLOG_INLINE void initialize_logger(std::shared_ptr logger) +{ + details::registry::instance().initialize_logger(std::move(logger)); +} + +SPDLOG_INLINE std::shared_ptr get(const std::string &name) +{ + return details::registry::instance().get(name); +} + +SPDLOG_INLINE void set_formatter(std::unique_ptr formatter) +{ + details::registry::instance().set_formatter(std::move(formatter)); +} + +SPDLOG_INLINE void set_pattern(std::string pattern, pattern_time_type time_type) +{ + set_formatter(std::unique_ptr(new pattern_formatter(std::move(pattern), time_type))); +} + +SPDLOG_INLINE void enable_backtrace(size_t n_messages) +{ + details::registry::instance().enable_backtrace(n_messages); +} + +SPDLOG_INLINE void disable_backtrace() +{ + details::registry::instance().disable_backtrace(); +} + +SPDLOG_INLINE void dump_backtrace() +{ + default_logger_raw()->dump_backtrace(); +} + +SPDLOG_INLINE level::level_enum get_level() +{ + return default_logger_raw()->level(); +} + +SPDLOG_INLINE bool should_log(level::level_enum log_level) +{ + return default_logger_raw()->should_log(log_level); +} + +SPDLOG_INLINE void set_level(level::level_enum log_level) +{ + details::registry::instance().set_level(log_level); +} + +SPDLOG_INLINE void flush_on(level::level_enum log_level) +{ + details::registry::instance().flush_on(log_level); +} + +SPDLOG_INLINE void set_error_handler(void (*handler)(const std::string &msg)) +{ + details::registry::instance().set_error_handler(handler); +} + +SPDLOG_INLINE void register_logger(std::shared_ptr logger) +{ + details::registry::instance().register_logger(std::move(logger)); +} + +SPDLOG_INLINE void apply_all(const std::function)> &fun) +{ + details::registry::instance().apply_all(fun); +} + +SPDLOG_INLINE void drop(const std::string &name) +{ + details::registry::instance().drop(name); +} + +SPDLOG_INLINE void drop_all() +{ + details::registry::instance().drop_all(); +} + +SPDLOG_INLINE void shutdown() +{ + details::registry::instance().shutdown(); +} + +SPDLOG_INLINE void set_automatic_registration(bool automatic_registration) +{ + details::registry::instance().set_automatic_registration(automatic_registration); +} + +SPDLOG_INLINE std::shared_ptr default_logger() +{ + return details::registry::instance().default_logger(); +} + +SPDLOG_INLINE spdlog::logger *default_logger_raw() +{ + return details::registry::instance().get_default_raw(); +} + +SPDLOG_INLINE void set_default_logger(std::shared_ptr default_logger) +{ + details::registry::instance().set_default_logger(std::move(default_logger)); +} + +SPDLOG_INLINE void apply_logger_env_levels(std::shared_ptr logger) +{ + details::registry::instance().apply_logger_env_levels(std::move(logger)); +} + +} // namespace spdlog diff --git a/tpl/spdlog/include/spdlog/spdlog.h b/tpl/spdlog/include/spdlog/spdlog.h new file mode 100644 index 0000000..fbfe5fb --- /dev/null +++ b/tpl/spdlog/include/spdlog/spdlog.h @@ -0,0 +1,363 @@ +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) + +// spdlog main header file. +// see example.cpp for usage example + +#ifndef SPDLOG_H +#define SPDLOG_H + +#pragma once + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +namespace spdlog { + +using default_factory = synchronous_factory; + +// Create and register a logger with a templated sink type +// The logger's level, formatter and flush level will be set according the +// global settings. +// +// Example: +// spdlog::create("logger_name", "dailylog_filename", 11, 59); +template +inline std::shared_ptr create(std::string logger_name, SinkArgs &&...sink_args) +{ + return default_factory::create(std::move(logger_name), std::forward(sink_args)...); +} + +// Initialize and register a logger, +// formatter and flush level will be set according the global settings. +// +// Useful for initializing manually created loggers with the global settings. +// +// Example: +// auto mylogger = std::make_shared("mylogger", ...); +// spdlog::initialize_logger(mylogger); +SPDLOG_API void initialize_logger(std::shared_ptr logger); + +// Return an existing logger or nullptr if a logger with such name doesn't +// exist. +// example: spdlog::get("my_logger")->info("hello {}", "world"); +SPDLOG_API std::shared_ptr get(const std::string &name); + +// Set global formatter. Each sink in each logger will get a clone of this object +SPDLOG_API void set_formatter(std::unique_ptr formatter); + +// Set global format string. +// example: spdlog::set_pattern("%Y-%m-%d %H:%M:%S.%e %l : %v"); +SPDLOG_API void set_pattern(std::string pattern, pattern_time_type time_type = pattern_time_type::local); + +// enable global backtrace support +SPDLOG_API void enable_backtrace(size_t n_messages); + +// disable global backtrace support +SPDLOG_API void disable_backtrace(); + +// call dump backtrace on default logger +SPDLOG_API void dump_backtrace(); + +// Get global logging level +SPDLOG_API level::level_enum get_level(); + +// Set global logging level +SPDLOG_API void set_level(level::level_enum log_level); + +// Determine whether the default logger should log messages with a certain level +SPDLOG_API bool should_log(level::level_enum lvl); + +// Set global flush level +SPDLOG_API void flush_on(level::level_enum log_level); + +// Start/Restart a periodic flusher thread +// Warning: Use only if all your loggers are thread safe! +template +inline void flush_every(std::chrono::duration interval) +{ + details::registry::instance().flush_every(interval); +} + +// Set global error handler +SPDLOG_API void set_error_handler(void (*handler)(const std::string &msg)); + +// Register the given logger with the given name +SPDLOG_API void register_logger(std::shared_ptr logger); + +// Apply a user defined function on all registered loggers +// Example: +// spdlog::apply_all([&](std::shared_ptr l) {l->flush();}); +SPDLOG_API void apply_all(const std::function)> &fun); + +// Drop the reference to the given logger +SPDLOG_API void drop(const std::string &name); + +// Drop all references from the registry +SPDLOG_API void drop_all(); + +// stop any running threads started by spdlog and clean registry loggers +SPDLOG_API void shutdown(); + +// Automatic registration of loggers when using spdlog::create() or spdlog::create_async +SPDLOG_API void set_automatic_registration(bool automatic_registration); + +// API for using default logger (stdout_color_mt), +// e.g: spdlog::info("Message {}", 1); +// +// The default logger object can be accessed using the spdlog::default_logger(): +// For example, to add another sink to it: +// spdlog::default_logger()->sinks().push_back(some_sink); +// +// The default logger can replaced using spdlog::set_default_logger(new_logger). +// For example, to replace it with a file logger. +// +// IMPORTANT: +// The default API is thread safe (for _mt loggers), but: +// set_default_logger() *should not* be used concurrently with the default API. +// e.g do not call set_default_logger() from one thread while calling spdlog::info() from another. + +SPDLOG_API std::shared_ptr default_logger(); + +SPDLOG_API spdlog::logger *default_logger_raw(); + +SPDLOG_API void set_default_logger(std::shared_ptr default_logger); + +// Initialize logger level based on environment configs. +// +// Useful for applying SPDLOG_LEVEL to manually created loggers. +// +// Example: +// auto mylogger = std::make_shared("mylogger", ...); +// spdlog::apply_logger_env_levels(mylogger); +SPDLOG_API void apply_logger_env_levels(std::shared_ptr logger); + +template +inline void log(source_loc source, level::level_enum lvl, format_string_t fmt, Args &&...args) +{ + default_logger_raw()->log(source, lvl, fmt, std::forward(args)...); +} + +template +inline void log(level::level_enum lvl, format_string_t fmt, Args &&...args) +{ + default_logger_raw()->log(source_loc{}, lvl, fmt, std::forward(args)...); +} + +template +inline void trace(format_string_t fmt, Args &&...args) +{ + default_logger_raw()->trace(fmt, std::forward(args)...); +} + +template +inline void debug(format_string_t fmt, Args &&...args) +{ + default_logger_raw()->debug(fmt, std::forward(args)...); +} + +template +inline void info(format_string_t fmt, Args &&...args) +{ + default_logger_raw()->info(fmt, std::forward(args)...); +} + +template +inline void warn(format_string_t fmt, Args &&...args) +{ + default_logger_raw()->warn(fmt, std::forward(args)...); +} + +template +inline void error(format_string_t fmt, Args &&...args) +{ + default_logger_raw()->error(fmt, std::forward(args)...); +} + +template +inline void critical(format_string_t fmt, Args &&...args) +{ + default_logger_raw()->critical(fmt, std::forward(args)...); +} + +template +inline void log(source_loc source, level::level_enum lvl, const T &msg) +{ + default_logger_raw()->log(source, lvl, msg); +} + +template +inline void log(level::level_enum lvl, const T &msg) +{ + default_logger_raw()->log(lvl, msg); +} + +#ifdef SPDLOG_WCHAR_TO_UTF8_SUPPORT +template +inline void log(source_loc source, level::level_enum lvl, wformat_string_t fmt, Args &&...args) +{ + default_logger_raw()->log(source, lvl, fmt, std::forward(args)...); +} + +template +inline void log(level::level_enum lvl, wformat_string_t fmt, Args &&...args) +{ + default_logger_raw()->log(source_loc{}, lvl, fmt, std::forward(args)...); +} + +template +inline void trace(wformat_string_t fmt, Args &&...args) +{ + default_logger_raw()->trace(fmt, std::forward(args)...); +} + +template +inline void debug(wformat_string_t fmt, Args &&...args) +{ + default_logger_raw()->debug(fmt, std::forward(args)...); +} + +template +inline void info(wformat_string_t fmt, Args &&...args) +{ + default_logger_raw()->info(fmt, std::forward(args)...); +} + +template +inline void warn(wformat_string_t fmt, Args &&...args) +{ + default_logger_raw()->warn(fmt, std::forward(args)...); +} + +template +inline void error(wformat_string_t fmt, Args &&...args) +{ + default_logger_raw()->error(fmt, std::forward(args)...); +} + +template +inline void critical(wformat_string_t fmt, Args &&...args) +{ + default_logger_raw()->critical(fmt, std::forward(args)...); +} +#endif + +template +inline void trace(const T &msg) +{ + default_logger_raw()->trace(msg); +} + +template +inline void debug(const T &msg) +{ + default_logger_raw()->debug(msg); +} + +template +inline void info(const T &msg) +{ + default_logger_raw()->info(msg); +} + +template +inline void warn(const T &msg) +{ + default_logger_raw()->warn(msg); +} + +template +inline void error(const T &msg) +{ + default_logger_raw()->error(msg); +} + +template +inline void critical(const T &msg) +{ + default_logger_raw()->critical(msg); +} + +} // namespace spdlog + +// +// enable/disable log calls at compile time according to global level. +// +// define SPDLOG_ACTIVE_LEVEL to one of those (before including spdlog.h): +// SPDLOG_LEVEL_TRACE, +// SPDLOG_LEVEL_DEBUG, +// SPDLOG_LEVEL_INFO, +// SPDLOG_LEVEL_WARN, +// SPDLOG_LEVEL_ERROR, +// SPDLOG_LEVEL_CRITICAL, +// SPDLOG_LEVEL_OFF +// + +#ifndef SPDLOG_NO_SOURCE_LOC +# define SPDLOG_LOGGER_CALL(logger, level, ...) \ + (logger)->log(spdlog::source_loc{__FILE__, __LINE__, SPDLOG_FUNCTION}, level, __VA_ARGS__) +#else +# define SPDLOG_LOGGER_CALL(logger, level, ...) (logger)->log(spdlog::source_loc{}, level, __VA_ARGS__) +#endif + +#if SPDLOG_ACTIVE_LEVEL <= SPDLOG_LEVEL_TRACE +# define SPDLOG_LOGGER_TRACE(logger, ...) SPDLOG_LOGGER_CALL(logger, spdlog::level::trace, __VA_ARGS__) +# define SPDLOG_TRACE(...) SPDLOG_LOGGER_TRACE(spdlog::default_logger_raw(), __VA_ARGS__) +#else +# define SPDLOG_LOGGER_TRACE(logger, ...) (void)0 +# define SPDLOG_TRACE(...) (void)0 +#endif + +#if SPDLOG_ACTIVE_LEVEL <= SPDLOG_LEVEL_DEBUG +# define SPDLOG_LOGGER_DEBUG(logger, ...) SPDLOG_LOGGER_CALL(logger, spdlog::level::debug, __VA_ARGS__) +# define SPDLOG_DEBUG(...) SPDLOG_LOGGER_DEBUG(spdlog::default_logger_raw(), __VA_ARGS__) +#else +# define SPDLOG_LOGGER_DEBUG(logger, ...) (void)0 +# define SPDLOG_DEBUG(...) (void)0 +#endif + +#if SPDLOG_ACTIVE_LEVEL <= SPDLOG_LEVEL_INFO +# define SPDLOG_LOGGER_INFO(logger, ...) SPDLOG_LOGGER_CALL(logger, spdlog::level::info, __VA_ARGS__) +# define SPDLOG_INFO(...) SPDLOG_LOGGER_INFO(spdlog::default_logger_raw(), __VA_ARGS__) +#else +# define SPDLOG_LOGGER_INFO(logger, ...) (void)0 +# define SPDLOG_INFO(...) (void)0 +#endif + +#if SPDLOG_ACTIVE_LEVEL <= SPDLOG_LEVEL_WARN +# define SPDLOG_LOGGER_WARN(logger, ...) SPDLOG_LOGGER_CALL(logger, spdlog::level::warn, __VA_ARGS__) +# define SPDLOG_WARN(...) SPDLOG_LOGGER_WARN(spdlog::default_logger_raw(), __VA_ARGS__) +#else +# define SPDLOG_LOGGER_WARN(logger, ...) (void)0 +# define SPDLOG_WARN(...) (void)0 +#endif + +#if SPDLOG_ACTIVE_LEVEL <= SPDLOG_LEVEL_ERROR +# define SPDLOG_LOGGER_ERROR(logger, ...) SPDLOG_LOGGER_CALL(logger, spdlog::level::err, __VA_ARGS__) +# define SPDLOG_ERROR(...) SPDLOG_LOGGER_ERROR(spdlog::default_logger_raw(), __VA_ARGS__) +#else +# define SPDLOG_LOGGER_ERROR(logger, ...) (void)0 +# define SPDLOG_ERROR(...) (void)0 +#endif + +#if SPDLOG_ACTIVE_LEVEL <= SPDLOG_LEVEL_CRITICAL +# define SPDLOG_LOGGER_CRITICAL(logger, ...) SPDLOG_LOGGER_CALL(logger, spdlog::level::critical, __VA_ARGS__) +# define SPDLOG_CRITICAL(...) SPDLOG_LOGGER_CRITICAL(spdlog::default_logger_raw(), __VA_ARGS__) +#else +# define SPDLOG_LOGGER_CRITICAL(logger, ...) (void)0 +# define SPDLOG_CRITICAL(...) (void)0 +#endif + +#ifdef SPDLOG_HEADER_ONLY +# include "spdlog-inl.h" +#endif + +#endif // SPDLOG_H diff --git a/tpl/spdlog/include/spdlog/stopwatch.h b/tpl/spdlog/include/spdlog/stopwatch.h new file mode 100644 index 0000000..bea7b8a --- /dev/null +++ b/tpl/spdlog/include/spdlog/stopwatch.h @@ -0,0 +1,69 @@ +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) + +#pragma once + +#include +#include + +// Stopwatch support for spdlog (using std::chrono::steady_clock). +// Displays elapsed seconds since construction as double. +// +// Usage: +// +// spdlog::stopwatch sw; +// ... +// spdlog::debug("Elapsed: {} seconds", sw); => "Elapsed 0.005116733 seconds" +// spdlog::info("Elapsed: {:.6} seconds", sw); => "Elapsed 0.005163 seconds" +// +// +// If other units are needed (e.g. millis instead of double), include "fmt/chrono.h" and use "duration_cast<..>(sw.elapsed())": +// +// #include +//.. +// using std::chrono::duration_cast; +// using std::chrono::milliseconds; +// spdlog::info("Elapsed {}", duration_cast(sw.elapsed())); => "Elapsed 5ms" + +namespace spdlog { +class stopwatch +{ + using clock = std::chrono::steady_clock; + std::chrono::time_point start_tp_; + +public: + stopwatch() + : start_tp_{clock::now()} + {} + + std::chrono::duration elapsed() const + { + return std::chrono::duration(clock::now() - start_tp_); + } + + void reset() + { + start_tp_ = clock::now(); + } +}; +} // namespace spdlog + +// Support for fmt formatting (e.g. "{:012.9}" or just "{}") +namespace +#ifdef SPDLOG_USE_STD_FORMAT + std +#else + fmt +#endif +{ + +template<> +struct formatter : formatter +{ + template + auto format(const spdlog::stopwatch &sw, FormatContext &ctx) const -> decltype(ctx.out()) + { + return formatter::format(sw.elapsed().count(), ctx); + } +}; +} // namespace std diff --git a/tpl/spdlog/include/spdlog/tweakme.h b/tpl/spdlog/include/spdlog/tweakme.h new file mode 100644 index 0000000..5bcb5ff --- /dev/null +++ b/tpl/spdlog/include/spdlog/tweakme.h @@ -0,0 +1,140 @@ +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) + +#pragma once + +/////////////////////////////////////////////////////////////////////////////// +// +// Edit this file to squeeze more performance, and to customize supported +// features +// +/////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////// +// Under Linux, the much faster CLOCK_REALTIME_COARSE clock can be used. +// This clock is less accurate - can be off by dozens of millis - depending on +// the kernel HZ. +// Uncomment to use it instead of the regular clock. +// +// #define SPDLOG_CLOCK_COARSE +/////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////// +// Uncomment if source location logging is not needed. +// This will prevent spdlog from using __FILE__, __LINE__ and SPDLOG_FUNCTION +// +// #define SPDLOG_NO_SOURCE_LOC +/////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////// +// Uncomment if thread id logging is not needed (i.e. no %t in the log pattern). +// This will prevent spdlog from querying the thread id on each log call. +// +// WARNING: If the log pattern contains thread id (i.e, %t) while this flag is +// on, zero will be logged as thread id. +// +// #define SPDLOG_NO_THREAD_ID +/////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////// +// Uncomment to prevent spdlog from using thread local storage. +// +// WARNING: if your program forks, UNCOMMENT this flag to prevent undefined +// thread ids in the children logs. +// +// #define SPDLOG_NO_TLS +/////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////// +// Uncomment to avoid spdlog's usage of atomic log levels +// Use only if your code never modifies a logger's log levels concurrently by +// different threads. +// +// #define SPDLOG_NO_ATOMIC_LEVELS +/////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////// +// Uncomment to enable usage of wchar_t for file names on Windows. +// +// #define SPDLOG_WCHAR_FILENAMES +/////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////// +// Uncomment to override default eol ("\n" or "\r\n" under Linux/Windows) +// +// #define SPDLOG_EOL ";-)\n" +/////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////// +// Uncomment to override default folder separators ("/" or "\\/" under +// Linux/Windows). Each character in the string is treated as a different +// separator. +// +// #define SPDLOG_FOLDER_SEPS "\\" +/////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////// +// Uncomment to use your own copy of the fmt library instead of spdlog's copy. +// In this case spdlog will try to include so set your -I flag +// accordingly. +// +// #define SPDLOG_FMT_EXTERNAL +/////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////// +// Uncomment to use C++20 std::format instead of fmt. +// +// #define SPDLOG_USE_STD_FORMAT +/////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////// +// Uncomment to enable wchar_t support (convert to utf8) +// +// #define SPDLOG_WCHAR_TO_UTF8_SUPPORT +/////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////// +// Uncomment to prevent child processes from inheriting log file descriptors +// +// #define SPDLOG_PREVENT_CHILD_FD +/////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////// +// Uncomment to customize level names (e.g. "MY TRACE") +// +// #define SPDLOG_LEVEL_NAMES { "MY TRACE", "MY DEBUG", "MY INFO", "MY WARNING", "MY ERROR", "MY CRITICAL", "OFF" } +/////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////// +// Uncomment to customize short level names (e.g. "MT") +// These can be longer than one character. +// +// #define SPDLOG_SHORT_LEVEL_NAMES { "T", "D", "I", "W", "E", "C", "O" } +/////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////// +// Uncomment to disable default logger creation. +// This might save some (very) small initialization time if no default logger is needed. +// +// #define SPDLOG_DISABLE_DEFAULT_LOGGER +/////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////// +// Uncomment and set to compile time level with zero cost (default is INFO). +// Macros like SPDLOG_DEBUG(..), SPDLOG_INFO(..) will expand to empty statements if not enabled +// +// #define SPDLOG_ACTIVE_LEVEL SPDLOG_LEVEL_INFO +/////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////// +// Uncomment (and change if desired) macro to use for function names. +// This is compiler dependent. +// __PRETTY_FUNCTION__ might be nicer in clang/gcc, and __FUNCTION__ in msvc. +// Defaults to __FUNCTION__ (should work on all compilers) if not defined. +// +// #ifdef __PRETTY_FUNCTION__ +// # define SPDLOG_FUNCTION __PRETTY_FUNCTION__ +// #else +// # define SPDLOG_FUNCTION __FUNCTION__ +// #endif +/////////////////////////////////////////////////////////////////////////////// diff --git a/tpl/spdlog/include/spdlog/version.h b/tpl/spdlog/include/spdlog/version.h new file mode 100644 index 0000000..633cddc --- /dev/null +++ b/tpl/spdlog/include/spdlog/version.h @@ -0,0 +1,10 @@ +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) + +#pragma once + +#define SPDLOG_VER_MAJOR 1 +#define SPDLOG_VER_MINOR 12 +#define SPDLOG_VER_PATCH 0 + +#define SPDLOG_VERSION (SPDLOG_VER_MAJOR * 10000 + SPDLOG_VER_MINOR * 100 + SPDLOG_VER_PATCH) From 4cf5c40981b022d484800fc6ec1c73c4bd866d32 Mon Sep 17 00:00:00 2001 From: Nicolas Morales Date: Wed, 15 Nov 2023 14:49:25 -0800 Subject: [PATCH 02/11] #19: logging: log collision world, set_entity, tree build, and broadphase --- src/bvh/collision_object.cpp | 81 +++++++++++++++++++------ src/bvh/collision_object.hpp | 6 +- src/bvh/collision_object/broadphase.cpp | 14 ++++- src/bvh/collision_object/impl.cpp | 8 ++- src/bvh/collision_object/impl.hpp | 10 ++- src/bvh/collision_object/types.hpp | 1 - src/bvh/collision_world.cpp | 30 ++++++++- src/bvh/collision_world.hpp | 9 +++ src/bvh/collision_world/impl.hpp | 7 +++ src/bvh/debug/assert.hpp | 25 +++++++- src/bvh/logging.hpp | 50 +++++++++++++++ 11 files changed, 211 insertions(+), 30 deletions(-) create mode 100644 src/bvh/logging.hpp diff --git a/src/bvh/collision_object.cpp b/src/bvh/collision_object.cpp index 0ea587a..3b0b12d 100644 --- a/src/bvh/collision_object.cpp +++ b/src/bvh/collision_object.cpp @@ -77,11 +77,16 @@ namespace bvh collision_object::collision_object( collision_world &_world, std::size_t _idx, std::size_t _overdecomposition ) : m_impl{ std::make_unique< impl >( _world, _idx ) } { - bvh_splitting_geom_axis_ = ::vt::theTrace()->registerUserEventColl("bvh_splitting_geom_axis_"); - bvh_splitting_ml_ = ::vt::theTrace()->registerUserEventColl("bvh_splitting_ml_"); - bvh_set_entity_data_impl_ = ::vt::theTrace()->registerUserEventColl("bvh_set_entity_data_impl_"); - bvh_clustering_ = ::vt::theTrace()->registerUserEventColl("bvh_clustering_"); - bvh_build_trees_ = ::vt::theTrace()->registerUserEventColl("bvh_build_trees_"); + bvh_splitting_geom_axis_ = ::vt::theTrace()->registerUserEventColl( "bvh_splitting_geom_axis_" ); + m_impl->logger->trace( "obj={} registered user tracing event bvh_splitting_geom_axis_", m_impl->collision_idx ); + bvh_splitting_ml_ = ::vt::theTrace()->registerUserEventColl( "bvh_splitting_ml_" ); + m_impl->logger->trace( "obj={} registered user tracing event bvh_splitting_ml_", m_impl->collision_idx ); + bvh_set_entity_data_impl_ = ::vt::theTrace()->registerUserEventColl( "bvh_set_entity_data_impl_" ); + m_impl->logger->trace( "obj={} registered user tracing event bvh_set_entity_data_impl_", m_impl->collision_idx ); + bvh_clustering_ = ::vt::theTrace()->registerUserEventColl( "bvh_clustering_" ); + m_impl->logger->trace( "obj={} registered user tracing event bvh_clustering_", m_impl->collision_idx ); + bvh_build_trees_ = ::vt::theTrace()->registerUserEventColl( "bvh_build_trees_" ); + m_impl->logger->trace( "obj={} registered user tracing event bvh_build_trees_", m_impl->collision_idx ); m_impl->overdecomposition = static_cast< int >( _overdecomposition ); @@ -90,15 +95,19 @@ namespace bvh m_impl->chainset.addIndex( vt_index{ i } ); } + m_impl->logger->trace( "obj={} adding {} local indices", m_impl->collision_idx, m_impl->overdecomposition ); + // Initialize objgroup for per-node data ::vt::runInEpochCollective( "collision_object.make_objgroup", [&](){ m_impl->objgroup = ::vt::theObjGroup()->makeCollective( fmt::vt::format( "collision_object {}", _idx ) ); m_impl->objgroup.get()->self = this; - vt::debug( "objgroup make_collective {:x}\n", m_impl->objgroup.getProxy() ); + m_impl->logger->debug( "obj={} objgroup make_collective {:x}", m_impl->collision_idx, m_impl->objgroup.getProxy() ); }); m_impl->local_patches.resize( m_impl->overdecomposition ); + + m_impl->logger->info( "initialized collision object {}", m_impl->collision_idx ); } collision_object::collision_object( collision_object && ) noexcept = default; @@ -119,7 +128,10 @@ namespace bvh m_impl->local_patches.clear(); m_impl->local_patches.resize( od_factor ); - always_assert( m_impl->num_splits + 1 == od_factor, "error during splitting process, splits {} do not match od factor {}\n", m_impl->num_splits + 1, od_factor ); + BVH_ASSERT_ALWAYS( m_impl->num_splits + 1 == od_factor, + logger(), + "error during splitting process, splits {} do not match od factor {}\n", m_impl->num_splits + 1, + od_factor ); // Preallocate local data buffers. Do this lazily m_impl->narrowphase_patch_messages.resize( od_factor, nullptr ); @@ -135,12 +147,14 @@ namespace bvh const auto sbeg = ( i == 0 ) ? 0 : m_impl->splits_h( i - 1 ); const auto send = ( i == m_impl->num_splits ) ? m_impl->split_indices_h.extent( 0 ) : m_impl->splits_h( i ); const std::size_t nelements = send - sbeg; - ::bvh::vt::debug( "{}: creating broadphase patch for body {} size {} from offset {}\n", ::vt::theContext()->getNode(), m_impl->collision_idx, nelements, sbeg ); + logger().debug( "creating broadphase patch for body {} size {} from offset {}", m_impl->collision_idx, nelements, sbeg ); m_impl->local_patches[i] = broadphase_patch_type( i + rank * od_factor, span< const entity_snapshot >( m_impl->snapshots.data() + sbeg, nelements ) ); } - always_assert( m_impl->local_patches.size() == od_factor, "wrong number of patches\n" ); + BVH_ASSERT_ALWAYS( m_impl->local_patches.size() == od_factor, + logger(), + "wrong number of patches\n" ); } void collision_object::init_broadphase() const @@ -157,8 +171,11 @@ namespace bvh auto coll_size = vt_index{ static_cast< std::size_t >( od_factor * ::vt::theContext()->getNumNodes() ) }; if ( m_impl->broadphase_patch_collection_proxy.getProxy() == ::vt::no_vrt_proxy ) { + logger().info( "lazily constructing broadphase patch collection with {} elements", coll_size ); m_impl->broadphase_patch_collection_proxy = ::vt::makeCollection< broadphase_patch_collection_type >().bounds( coll_size ).bulkInsert().wait(); + logger().info( "lazily constructing narrophase patch collection with {} elements", coll_size ); m_impl->narrowphase_patch_collection_proxy = ::vt::makeCollection< narrowphase_patch_collection_type >().bounds( coll_size ).bulkInsert().wait(); + logger().info( "lazily constructing narrowphase collection with dynamic membership" ); m_impl->narrowphase_collection_proxy = ::vt::makeCollection< narrowphase_collection_type >().dynamicMembership( true ).wait(); } @@ -178,8 +195,11 @@ namespace bvh msg->patch = local_patch; msg->origin_node = rank; msg->local_idx = _local; - ::bvh::vt::debug( "{}: sending broadphase patch {} for body {} size {}\n", ::vt::theContext()->getNode(), - vt_index{ _local.x() + offset }, m_impl->collision_idx, msg->patch.size() ); + logger().debug( " obj={} initialize broadphase patch {} size {}", + vt_index{ _local.x() + offset }, + m_impl->collision_idx, + _local.x() + offset, + msg->patch.size() ); return m_impl->broadphase_patch_collection_proxy[vt_index{ _local.x() + offset }] .sendMsg< broadphase_patch_msg, &details::set_broadphase_patches >( msg.get() ); } else { @@ -194,8 +214,10 @@ namespace bvh ::vt::trace::TraceScopedEvent scope(bvh_build_trees_); // Tree build needs to be done collectively, everyone needs to finish before the next step m_impl->chainset.nextStepCollective( "build_tree_step", [this, offset]( vt_index _idx ) { - ::bvh::vt::debug( "{}: building tree reduction for patch {} for body {}\n", ::vt::theContext()->getNode(), - vt_index{ _idx.x() + offset }, m_impl->collision_idx ); + logger().debug( " obj={} building tree reduction for patch {}", + vt_index{ _idx.x() + offset }, + m_impl->collision_idx, + _idx.x() + offset ); return collision_object_impl::build_trees_top_down( vt_index{ _idx.x() + offset }, m_impl->objgroup, m_impl->broadphase_patch_collection_proxy ); } ); @@ -243,9 +265,11 @@ namespace bvh m_impl->chainset.nextStepCollective( "start broadphase insertion", [this, &_other]( vt_index _local_idx) { if ( _local_idx.x() == 0 ) { - ::bvh::vt::debug( "{}: starting broadphase between body {} and {}\n", - ::vt::theContext()->getNode(), m_impl->collision_idx, _other.m_impl->collision_idx ); + broadphase_logger().info( "starting broadphase between body {} and {}", + m_impl->collision_idx, _other.m_impl->collision_idx ); auto msg = ::vt::makeMessage< collision_object_impl::messages::modify_msg >(); + broadphase_logger().trace( " obj={} begin_narrowphase_modification", + ::vt::theContext()->getNode(), id() ); return m_impl->objgroup[::vt::theContext()->getNode()].sendMsg< collision_object_impl::messages::modify_msg, &collision_object_impl::collision_object_holder::begin_narrowphase_modification >( msg ); } else return pending_send{ nullptr }; @@ -254,14 +278,19 @@ namespace bvh using chainset_type = ::vt::messaging::CollectionChainSet< vt_index >; chainset_type::mergeStepCollective( "broadphase_step",m_impl->chainset, _other.m_impl->chainset, [this, rank, offset, &_other]( vt_index _idx ) { - return collision_object_impl::broadphase( - vt_index{ _idx.x() + offset }, vt_index{ _idx.x() }, rank, - m_impl->broadphase_patch_collection_proxy, m_impl->objgroup, - _other.m_impl->objgroup ); + broadphase_logger().trace( " obj={} target_obj={} start broadphase", + vt_index{ _idx.x() + offset }, id(), _other.id() ); + return collision_object_impl::broadphase( + vt_index{ _idx.x() + offset }, vt_index{ _idx.x() }, rank, + m_impl->broadphase_patch_collection_proxy, m_impl->objgroup, + _other.m_impl->objgroup ); } ); m_impl->chainset.nextStepCollective( "finalize broadphase insertion", [this]( vt_index _local_idx) { - if ( _local_idx.x() == 0 ) { + if ( _local_idx.x() == 0 ) + { + broadphase_logger().trace( " obj={} finish_narrowphase_modification", + ::vt::theContext()->getNode(), id() ); auto msg = ::vt::makeMessage< collision_object_impl::messages::modify_msg >(); return m_impl->objgroup[::vt::theContext()->getNode()].sendMsg< collision_object_impl::messages::modify_msg, &collision_object_impl::collision_object_holder::finish_narrowphase_modification >( msg ); } else @@ -448,4 +477,16 @@ namespace bvh Kokkos::deep_copy( m_impl->split_indices_h, indices_view ); } + spdlog::logger & + collision_object::logger() const noexcept + { + return *m_impl->logger; + } + + spdlog::logger & + collision_object::broadphase_logger() const noexcept + { + return *m_impl->broadphase_logger; + } + } // namespace bvh diff --git a/src/bvh/collision_object.hpp b/src/bvh/collision_object.hpp index 60bb3b5..8c0370d 100644 --- a/src/bvh/collision_object.hpp +++ b/src/bvh/collision_object.hpp @@ -38,6 +38,7 @@ #include #include #include +#include #include "snapshot.hpp" #include "split/split.hpp" @@ -98,7 +99,7 @@ namespace bvh const auto od_factor = this->overdecomposition_factor(); const auto num_splits = od_factor - 1; - ::bvh::vt::debug( "{}: clustering {} elements\n", ::vt::theContext()->getNode(), n ); + logger().debug( "obj={} clustering {} elements\n", id(), n ); if ( n != m_clusterer.size() ) { m_clusterer.resize( n ); @@ -189,6 +190,9 @@ namespace bvh span< const patch<> > local_patches() const noexcept; + spdlog::logger &logger() const noexcept; + spdlog::logger &broadphase_logger() const noexcept; + private: friend class collision_world; diff --git a/src/bvh/collision_object/broadphase.cpp b/src/bvh/collision_object/broadphase.cpp index 052eeb5..3f5cb3e 100644 --- a/src/bvh/collision_object/broadphase.cpp +++ b/src/bvh/collision_object/broadphase.cpp @@ -86,15 +86,25 @@ namespace bvh // tmp_idx[1] = static_cast( tree_obj->get_impl().collision_idx ); // - query_tree( tree, patch, [&_msg, local_idx, origin_node, &patch_obj, &tree_obj, &tok]( std::size_t _p, std::size_t _q ){ + + auto &logger = patch_obj->broadphase_logger(); + logger.debug( "(objp={}, size={}) (objq={}, count={}) starting broadphase", patch_obj->id(), patch.size(), tree_obj->id(), tree.count() ); + + query_tree( tree, patch, [&_msg, &logger, local_idx, origin_node, &patch_obj, &tree_obj, &tok]( std::size_t _p, std::size_t _q ){ collision_object_impl::narrowphase_index idx( static_cast< int >( _p ), static_cast( tree_obj->get_impl().collision_idx ), static_cast< int >( _q ) ); + logger.trace( "found broadphase contact <{}, {}, {}, {}>", + patch_obj->id(), _p, tree_obj->id(), _q ); + logger.trace( "obj={} inserting {} into narrowphase collection", patch_obj->id(), idx ); patch_obj->get_impl().narrowphase_collection_proxy[idx].insert( tok ); + logger.trace( "obj={} adding {} to active narrowphase indices", patch_obj->id(), idx ); patch_obj->get_impl().active_narrowphase_indices.emplace_back( idx ); // auto activate_narrowphase_index_msg = ::vt::makeMessage< active_narrowphase_local_index_msg >(); activate_narrowphase_index_msg->idx = local_idx; + logger.trace( " obj={} insert_active_narrow_local_index local_idx={}", + origin_node, patch_obj->id(), local_idx ); patch_obj->get_impl().objgroup[origin_node].sendMsg< active_narrowphase_local_index_msg, &collision_object_impl::collision_object_holder::insert_active_narrow_local_index >( activate_narrowphase_index_msg ); // // Note that the global index `_q` may not be managed by VT on this rank @@ -102,6 +112,8 @@ namespace bvh // auto tree_msg = ::vt::makeMessage< flag_active_narrowpatch_msg >(); tree_msg->patch_obj = _msg->tree_obj; + logger.trace( " obj={} flag_active_narrowpatch", + _q, patch_obj->id() ); tree_obj->get_impl().broadphase_patch_collection_proxy[_q].sendMsg< flag_active_narrowpatch_msg, &flag_active_narrowpatch >( tree_msg ); } ); } diff --git a/src/bvh/collision_object/impl.cpp b/src/bvh/collision_object/impl.cpp index d64f26d..e619b9a 100644 --- a/src/bvh/collision_object/impl.cpp +++ b/src/bvh/collision_object/impl.cpp @@ -41,7 +41,9 @@ namespace bvh split_indices( fmt::format( "contact entity {} split indices", _idx ), 0 ), splits( fmt::format( "contact entity {} splits", _idx ), 0 ), split_indices_h( fmt::format( "contact entity host {} split indices", _idx ), 0 ), - splits_h( fmt::format( "contact entity host {} splits", _idx ), 0 ) + splits_h( fmt::format( "contact entity host {} splits", _idx ), 0 ), + logger( _world.collision_object_logger() ), + broadphase_logger( _world.collision_object_broadphase_logger() ) { } @@ -60,15 +62,19 @@ namespace bvh void collision_object_holder::setup_narrowphase(setup_narrowphase_msg *_msg ) { + auto &logger = self->broadphase_logger(); auto &impl = self->get_impl(); auto rank = static_cast< int >( ::vt::theContext()->getNode() ); const auto od_factor = impl.overdecomposition; const std::size_t od_offset = rank * od_factor; auto &patches = impl.narrowphase_patch_collection_proxy; + logger.debug( "obj={}, setting up {} active narrowphase patches", + self->id(), impl.active_narrowphase_indices.size() ); for ( const auto idx : impl.active_narrowphase_local_index ) { auto send_msg = impl.prepare_local_patch_for_sending( idx, rank ); + logger.trace( " obj={} narrowphase_patch_copy", od_offset + idx, self->id() ); patches[od_offset + idx].sendMsg< narrowphase_patch_msg, &collision_object_impl::narrowphase_patch_copy >( send_msg ); } } diff --git a/src/bvh/collision_object/impl.hpp b/src/bvh/collision_object/impl.hpp index 026031d..e71fa62 100644 --- a/src/bvh/collision_object/impl.hpp +++ b/src/bvh/collision_object/impl.hpp @@ -86,6 +86,8 @@ namespace bvh ::vt::MsgPtr< collision_object_impl::narrowphase_patch_msg > prepare_local_patch_for_sending( std::size_t _local_idx, int _rank ) { + auto &logger = *broadphase_logger; + using narrowphase_patch_msg = collision_object_impl::narrowphase_patch_msg; const auto idx = _local_idx; @@ -100,8 +102,8 @@ namespace bvh send_msg->data_size = chunk_data_size; std::size_t offset = 0; - ::bvh::vt::debug( "{}: sending narrowphase patch {} for body {} size {}\n", ::vt::theContext()->getNode(), - vt_index{ _local_idx + rank * overdecomposition }, collision_idx, nelements ); + logger.debug( "obj={} sending narrowphase patch {} with {} num elements", + collision_idx, vt_index{ _local_idx + rank * overdecomposition }, nelements ); // Should be replaced with VT serialization for (std::size_t j = sbeg; j < send; ++j) { @@ -175,6 +177,10 @@ namespace bvh host_view< std::size_t * > split_indices_h; host_view< std::size_t * > splits_h; std::size_t num_splits = 0; ///< The number of actual splits -- may be les than splits.extent( 0 ) + + // Loggers + std::shared_ptr< spdlog::logger > logger; + std::shared_ptr< spdlog::logger > broadphase_logger; }; namespace collision_object_impl diff --git a/src/bvh/collision_object/types.hpp b/src/bvh/collision_object/types.hpp index 4690082..7f17363 100644 --- a/src/bvh/collision_object/types.hpp +++ b/src/bvh/collision_object/types.hpp @@ -233,7 +233,6 @@ namespace bvh narrowphase_collection_type() : active( false ) { - ::bvh::vt::debug( "{}: constructing narrowphase entry\n", ::vt::theContext()->getNode() ); } bool active = false; diff --git a/src/bvh/collision_world.cpp b/src/bvh/collision_world.cpp index 04ddf22..ab0f776 100644 --- a/src/bvh/collision_world.cpp +++ b/src/bvh/collision_world.cpp @@ -33,6 +33,9 @@ #include "collision_world.hpp" #include "collision_object.hpp" #include "collision_world/impl.hpp" +#include "logging.hpp" +#include +#include #include #include @@ -42,8 +45,21 @@ namespace bvh collision_world::collision_world( std::size_t _overdecomposition_factor ) : m_impl( std::make_unique< impl >() ) { + auto stdout_sink = std::make_shared< spdlog::sinks::stdout_color_sink_st >(); + stdout_sink->set_level( spdlog::level::trace ); + m_impl->collision_world_logger = logging::make_logger( "collision_world", stdout_sink ); + m_impl->collision_world_logger->trace( "Initialized collision world logger" ); + m_impl->collision_object_logger = logging::make_logger( "collision_object", stdout_sink ); + m_impl->collision_world_logger->trace( "Initialized collision object logger" ); + m_impl->collision_object_broadphase_logger = logging::make_logger( "collision_object.broadphase", stdout_sink ); + m_impl->collision_world_logger->trace( "Initialized collision object broadphase logger" ); + m_impl->overdecomposition = _overdecomposition_factor; - m_impl->bvh_impl_functor_ = ::vt::theTrace()->registerUserEventColl("bvh_impl_functor_"); + auto user_event_name = "bvh_impl_functor_"; + m_impl->bvh_impl_functor_ = ::vt::theTrace()->registerUserEventColl( user_event_name); + m_impl->collision_world_logger->trace( "registered user tracing event {}", user_event_name ); + + m_impl->collision_world_logger->info( "Initialized collision world with overdecomposition factor {}", _overdecomposition_factor ); } collision_world::~collision_world() = default; @@ -105,4 +121,16 @@ namespace bvh m_impl->epoch = ::vt::no_epoch; } + + std::shared_ptr< spdlog::logger > + collision_world::collision_object_logger() const + { + return m_impl->collision_object_logger; + } + + std::shared_ptr< spdlog::logger > + collision_world::collision_object_broadphase_logger() const + { + return m_impl->collision_object_broadphase_logger; + } } diff --git a/src/bvh/collision_world.hpp b/src/bvh/collision_world.hpp index b0f9f7d..71a0fc3 100644 --- a/src/bvh/collision_world.hpp +++ b/src/bvh/collision_world.hpp @@ -39,11 +39,17 @@ #include "snapshot.hpp" #include "util/functional.hpp" #include "tree_build.hpp" +#include namespace bvh { class collision_object; + struct world_config + { + spdlog::level::level_enum log_levels = spdlog::level::info; + }; + class collision_world { public: @@ -89,6 +95,9 @@ namespace bvh void start_iteration(); void finish_iteration(); + std::shared_ptr< spdlog::logger > collision_object_logger() const; + std::shared_ptr< spdlog::logger > collision_object_broadphase_logger() const; + private: struct impl; diff --git a/src/bvh/collision_world/impl.hpp b/src/bvh/collision_world/impl.hpp index 2dcc02d..aa45785 100644 --- a/src/bvh/collision_world/impl.hpp +++ b/src/bvh/collision_world/impl.hpp @@ -37,6 +37,10 @@ #include #include +#define SPDLOG_HEADER_ONLY +#include +#include + namespace bvh { @@ -60,6 +64,9 @@ namespace bvh ::vt::trace::UserEventIDType bvh_impl_functor_ = ::vt::trace::no_user_event_id; + std::shared_ptr< spdlog::logger > collision_world_logger; + std::shared_ptr< spdlog::logger > collision_object_logger; + std::shared_ptr< spdlog::logger > collision_object_broadphase_logger; }; } diff --git a/src/bvh/debug/assert.hpp b/src/bvh/debug/assert.hpp index b6f319a..298a0be 100644 --- a/src/bvh/debug/assert.hpp +++ b/src/bvh/debug/assert.hpp @@ -37,6 +37,7 @@ #include #include #include "../vt/print.hpp" +#include namespace bvh { @@ -45,7 +46,7 @@ namespace bvh #else constexpr int assert_debug_level = 0; #endif - + namespace detail { template< bool Enable > @@ -57,7 +58,7 @@ namespace bvh // Do nothing } }; - + template<> struct debug_assert_impl< true > { @@ -72,7 +73,7 @@ namespace bvh } }; } - + template< int DebugLevel, typename... Args > void debug_assert_level( bool _val, const std::string &_msg, Args &&... _args ) { @@ -97,7 +98,25 @@ namespace bvh { always_assert( false, _msg, std::forward< Args >( _args )... ); } + + namespace detail + { + inline void assert_die( spdlog::logger &_logger, const char *_file, unsigned int _line, const char *_assertion, + const std::string &_msg ) + { + _logger.critical( "assertion failed at {}:{}: {} ({})", _file, _line, _assertion, _msg ); + std::terminate(); + } + + inline void assert_die( std::shared_ptr< spdlog::logger > _logger, const char *_file, unsigned int _line, + const char *_assertion, const std::string &_msg ) + { + assert_die( *_logger, _file, _line, _assertion, _msg ); + } + } // namespace detail } +#define BVH_ASSERT_ALWAYS( expr, logger, ... ) \ + ( static_cast< bool >( expr ) ? void( 0 ) : ::bvh::detail::assert_die( logger, __FILE__, __LINE__, #expr, fmt::format( __VA_ARGS__ ) ) ) #endif // INC_BVH_DEBUG_ASSERT_HPP diff --git a/src/bvh/logging.hpp b/src/bvh/logging.hpp new file mode 100644 index 0000000..d4d8227 --- /dev/null +++ b/src/bvh/logging.hpp @@ -0,0 +1,50 @@ +#ifndef INC_BVH_LOGGING_HPP +#define INC_BVH_LOGGING_HPP + +#include +#include +#include +#include +#include +#include + +namespace bvh::logging +{ + class rank_formatter_flag : public spdlog::custom_flag_formatter + { + public: + + void + format(const spdlog::details::log_msg &, const std::tm &, spdlog::memory_buf_t &_dest ) override + { + std::string rank_str = std::to_string( ::vt::theContext()->getNode() ); + _dest.append( rank_str.data(), rank_str.data() + rank_str.size() ); + } + + std::unique_ptr< spdlog::custom_flag_formatter > + clone() const override + { + return std::make_unique< rank_formatter_flag >(); + } + }; + + inline std::unique_ptr< spdlog::pattern_formatter > + make_formatter() + { + auto ret = std::make_unique< spdlog::pattern_formatter >(); + ret->add_flag< rank_formatter_flag >( 'N' ).set_pattern( "[%N] %+" ); + return ret; + } + + inline std::shared_ptr< spdlog::logger > + make_logger( std::string _name, spdlog::sink_ptr _sink ) + { + auto ret = std::make_shared< spdlog::logger >( std::move( _name ), std::move( _sink ) ); + ret->set_formatter( make_formatter() ); + ret->set_level( spdlog::level::trace ); + + return ret; + } +} + +#endif // INC_BVH_LOGGING_HPP From 195cbb134808889680631ab40694e8e742ff93c6 Mon Sep 17 00:00:00 2001 From: Nicolas Morales Date: Thu, 16 Nov 2023 14:52:50 -0800 Subject: [PATCH 03/11] #19: logging: log narrowphase --- src/bvh/collision_object.cpp | 10 +- src/bvh/collision_object.hpp | 1 + src/bvh/collision_object/impl.cpp | 188 ++++++++++++++--------- src/bvh/collision_object/impl.hpp | 1 + src/bvh/collision_object/narrowphase.cpp | 8 +- src/bvh/collision_object/types.hpp | 81 +++++----- src/bvh/collision_world.cpp | 8 + src/bvh/collision_world.hpp | 1 + src/bvh/collision_world/impl.hpp | 1 + tests/SerializerTest.cpp | 114 +++++++------- 10 files changed, 236 insertions(+), 177 deletions(-) diff --git a/src/bvh/collision_object.cpp b/src/bvh/collision_object.cpp index 3b0b12d..d6f48d7 100644 --- a/src/bvh/collision_object.cpp +++ b/src/bvh/collision_object.cpp @@ -174,7 +174,9 @@ namespace bvh logger().info( "lazily constructing broadphase patch collection with {} elements", coll_size ); m_impl->broadphase_patch_collection_proxy = ::vt::makeCollection< broadphase_patch_collection_type >().bounds( coll_size ).bulkInsert().wait(); logger().info( "lazily constructing narrophase patch collection with {} elements", coll_size ); - m_impl->narrowphase_patch_collection_proxy = ::vt::makeCollection< narrowphase_patch_collection_type >().bounds( coll_size ).bulkInsert().wait(); + m_impl->narrowphase_patch_collection_proxy = ::vt::makeCollection< narrowphase_patch_collection_type >() + .elementConstructor( [this]( narrowphase_patch_collection_type::IndexType ){ return std::make_unique< narrowphase_patch_collection_type >( m_impl->objgroup ); } ) + .bounds( coll_size ).bulkInsert().wait(); logger().info( "lazily constructing narrowphase collection with dynamic membership" ); m_impl->narrowphase_collection_proxy = ::vt::makeCollection< narrowphase_collection_type >().dynamicMembership( true ).wait(); } @@ -489,4 +491,10 @@ namespace bvh return *m_impl->broadphase_logger; } + spdlog::logger & + collision_object::narrowphase_logger() const noexcept + { + return *m_impl->narrowphase_logger; + } + } // namespace bvh diff --git a/src/bvh/collision_object.hpp b/src/bvh/collision_object.hpp index 8c0370d..0385ff1 100644 --- a/src/bvh/collision_object.hpp +++ b/src/bvh/collision_object.hpp @@ -192,6 +192,7 @@ namespace bvh spdlog::logger &logger() const noexcept; spdlog::logger &broadphase_logger() const noexcept; + spdlog::logger &narrowphase_logger() const noexcept; private: diff --git a/src/bvh/collision_object/impl.cpp b/src/bvh/collision_object/impl.cpp index e619b9a..2f06008 100644 --- a/src/bvh/collision_object/impl.cpp +++ b/src/bvh/collision_object/impl.cpp @@ -36,31 +36,32 @@ namespace bvh { collision_object::impl::impl( collision_world &_world, std::size_t _idx ) - : world( &_world ), collision_idx( _idx ), + : world( &_world ), + collision_idx( _idx ), snapshots( fmt::format( "contact entity {} snapshot", _idx ), 0 ), split_indices( fmt::format( "contact entity {} split indices", _idx ), 0 ), splits( fmt::format( "contact entity {} splits", _idx ), 0 ), split_indices_h( fmt::format( "contact entity host {} split indices", _idx ), 0 ), splits_h( fmt::format( "contact entity host {} splits", _idx ), 0 ), logger( _world.collision_object_logger() ), - broadphase_logger( _world.collision_object_broadphase_logger() ) - { - } + broadphase_logger( _world.collision_object_broadphase_logger() ), + narrowphase_logger( _world.collision_object_narrowphase_logger() ) + {} - namespace collision_object_impl { + namespace collision_object_impl + { // // Define member functions for the class 'collision_object_impl::collision_object_holder' // declared in `types.hpp` // - void collision_object_holder::insert_active_narrow_local_index(active_narrowphase_local_index_msg *_msg ) + void collision_object_holder::insert_active_narrow_local_index( active_narrowphase_local_index_msg *_msg ) { self->get_impl().active_narrowphase_local_index.insert( _msg->idx.x() ); } - void - collision_object_holder::setup_narrowphase(setup_narrowphase_msg *_msg ) + void collision_object_holder::setup_narrowphase( setup_narrowphase_msg *_msg ) { auto &logger = self->broadphase_logger(); auto &impl = self->get_impl(); @@ -69,86 +70,90 @@ namespace bvh const std::size_t od_offset = rank * od_factor; auto &patches = impl.narrowphase_patch_collection_proxy; - logger.debug( "obj={}, setting up {} active narrowphase patches", - self->id(), impl.active_narrowphase_indices.size() ); + logger.debug( "obj={}, setting up {} narrowphase patches marked as ready to activate", self->id(), + impl.active_narrowphase_indices.size() ); for ( const auto idx : impl.active_narrowphase_local_index ) { auto send_msg = impl.prepare_local_patch_for_sending( idx, rank ); logger.trace( " obj={} narrowphase_patch_copy", od_offset + idx, self->id() ); - patches[od_offset + idx].sendMsg< narrowphase_patch_msg, &collision_object_impl::narrowphase_patch_copy >( send_msg ); + patches[od_offset + idx].sendMsg< narrowphase_patch_msg, &collision_object_impl::narrowphase_patch_copy >( + send_msg ); } } - void - collision_object_holder::activate_narrowphase( - start_activate_narrowphase_msg *_msg ) + void collision_object_holder::activate_narrowphase( start_activate_narrowphase_msg *_msg ) { + auto &logger = self->narrowphase_logger(); auto &impl = self->get_impl(); + + logger.debug( "obj={}, activating {} narrowphase patches", self->id(), impl.active_narrowphase_indices.size() ); for ( auto &&idx : impl.active_narrowphase_indices ) { auto msg = ::vt::makeMessage< activate_narrowphase_msg >(); - impl.narrowphase_collection_proxy[idx].sendMsg< activate_narrowphase_msg, &collision_object_impl::activate_narrowphase >( msg.get() ); + logger.trace( " obj={} activate_narrowphase", idx, self->id() ); + impl.narrowphase_collection_proxy[idx] + .sendMsg< activate_narrowphase_msg, &collision_object_impl::activate_narrowphase >( msg.get() ); } } - void - collision_object_holder::request_ghosts( - start_ghosting_msg *_msg ) + void collision_object_holder::request_ghosts( start_ghosting_msg *_msg ) { + auto &logger = self->narrowphase_logger(); auto &impl = self->get_impl(); for ( auto &&idx : impl.active_narrowphase_indices ) { auto msg = ::vt::makeMessage< start_ghosting_msg >(); msg->this_obj = _msg->this_obj; msg->other_obj = _msg->other_obj; - impl.narrowphase_collection_proxy[idx].sendMsg< start_ghosting_msg, &collision_object_impl::start_ghosting >( msg.get() ); + logger.trace( " objp={}, objq={} start_ghosting", idx, _msg->this_obj.get()->self->id(), + _msg->other_obj.get()->self->id() ); + impl.narrowphase_collection_proxy[idx].sendMsg< start_ghosting_msg, &collision_object_impl::start_ghosting >( + msg.get() ); } } - void - collision_object_holder::start_narrowphase( - start_narrowphase_msg *_msg ) + void collision_object_holder::start_narrowphase( start_narrowphase_msg *_msg ) { auto &impl = self->get_impl(); for ( auto &&idx : impl.active_narrowphase_indices ) { auto msg = ::vt::makeMessage< start_narrowphase_msg >(); - impl.narrowphase_collection_proxy[idx].sendMsg< start_narrowphase_msg, &collision_object_impl::start_narrowphase >( msg.get() ); + impl.narrowphase_collection_proxy[idx] + .sendMsg< start_narrowphase_msg, &collision_object_impl::start_narrowphase >( msg.get() ); } } - void - collision_object_holder::clear_narrowphase( - clear_narrowphase_msg *_msg ) + void collision_object_holder::clear_narrowphase( clear_narrowphase_msg *_msg ) { auto &impl = self->get_impl(); for ( auto &&idx : impl.active_narrowphase_indices ) { auto msg = ::vt::makeMessage< clear_narrowphase_msg >(); - impl.narrowphase_collection_proxy[idx].sendMsg< clear_narrowphase_msg, &collision_object_impl::clear_narrowphase >( msg.get() ); + impl.narrowphase_collection_proxy[idx] + .sendMsg< clear_narrowphase_msg, &collision_object_impl::clear_narrowphase >( msg.get() ); } } - void - collision_object_holder::begin_narrowphase_modification( messages::modify_msg * ) - { - ::vt::theMsg()->pushEpoch( ::vt::term::any_epoch_sentinel ); - self->get_impl().narrowphase_modification_token = self->get_impl().narrowphase_collection_proxy.beginModification( "broadphase contact insertion" ); - ::vt::theMsg()->popEpoch( ::vt::term::any_epoch_sentinel ); - } + void collision_object_holder::begin_narrowphase_modification( messages::modify_msg * ) + { + ::vt::theMsg()->pushEpoch( ::vt::term::any_epoch_sentinel ); + self->get_impl().narrowphase_modification_token + = self->get_impl().narrowphase_collection_proxy.beginModification( "broadphase contact insertion" ); + ::vt::theMsg()->popEpoch( ::vt::term::any_epoch_sentinel ); + } - void - collision_object_holder::finish_narrowphase_modification( messages::modify_msg * ) - { - self->get_impl().narrowphase_collection_proxy.finishModification( std::move( *self->get_impl().narrowphase_modification_token ) ); - self->get_impl().narrowphase_modification_token = {}; - } + void collision_object_holder::finish_narrowphase_modification( messages::modify_msg * ) + { + self->get_impl().narrowphase_collection_proxy.finishModification( + std::move( *self->get_impl().narrowphase_modification_token ) ); + self->get_impl().narrowphase_modification_token = {}; + } - void - collision_object_holder::cache_patch( ghost_msg *_msg ) + void collision_object_holder::cache_patch( ghost_msg *_msg ) { - ::bvh::vt::debug( "{}: caching patch idx {}\n", ::vt::theContext()->getNode(), _msg->idx ); auto &impl = self->get_impl(); + auto &logger = self->narrowphase_logger(); + logger.debug( "obj={} caching patch idx {}", impl.collision_idx, _msg->idx ); auto &ent = impl.narrowphase_patch_cache[_msg->idx]; @@ -157,19 +162,18 @@ namespace bvh ent.patch_data = _msg->patch_data; } - void - collision_object_holder::set_result( result_msg *_msg ) + void collision_object_holder::set_result( result_msg *_msg ) { self->get_impl().local_results.emplace_back( _msg->result ); } - void activate_narrowphase( collision_object_impl::narrowphase_collection_type *_narrow, activate_narrowphase_msg * ) { _narrow->active = true; } - namespace detail { + namespace detail + { struct ghost_request_msg : ::vt::CollectionMessage< collision_object_impl::narrowphase_patch_collection_type > { @@ -180,9 +184,11 @@ namespace bvh void request_ghost( collision_object_impl::narrowphase_patch_collection_type *_patch, ghost_request_msg *_msg ) { + const auto &obj = _patch->collision_object.get()->self; + auto &logger = obj->narrowphase_logger(); // Find destination node for the narrowphase collection element auto dst = _msg->dest_node; - ::bvh::vt::debug( "{}: requesting ghost for index {} to node {}\n", ::vt::theContext()->getNode(), _patch->getIndex(), dst ); + logger.debug( "obj={} requesting ghost for index {} to node {}", obj->id(), _patch->getIndex(), dst ); // Build up ghost_destination list/group. In ghosting step, // this element will be transferred to every node in ghost_destination. @@ -190,72 +196,83 @@ namespace bvh _patch->ghost_destinations.emplace( dst ); } - } // namespace detail + } // namespace detail void start_ghosting( collision_object_impl::narrowphase_collection_type *_narrow, start_ghosting_msg *_msg ) { auto idx = _narrow->getIndex(); auto &this_obj = _msg->this_obj.get()->self; auto &other_obj = _msg->other_obj.get()->self; + auto &logger = this_obj->narrowphase_logger(); // Only do anything if this is active to prev ent residual elements // from earlier iterations if ( !_narrow->active ) { - ::bvh::vt::debug( "{}: skipping ({}, {}, {}, {}) -- not active\n", ::vt::theContext()->getNode(), this_obj->get_impl().collision_idx, idx[0], idx[1], idx[2] ); + logger.trace( "skipping <{}, {}, {}, {}> -- not active", this_obj->id(), idx[0], idx[1], idx[2] ); return; } // Only run if we are looking at the right "other obj" if ( other_obj->get_impl().collision_idx != static_cast< std::size_t >( idx.y() ) ) { - ::bvh::vt::debug( "{}: skipping ({}, {}, {}, {}) -- mismatched index\n", ::vt::theContext()->getNode(), this_obj->get_impl().collision_idx, idx[0], idx[1], idx[2] ); + logger.trace( "skipping <{}, {}, {}, {}> -- mismatched index", this_obj->id(), idx[0], idx[1], idx[2] ); return; } // Ignore self collisions (this will usually be caught by the above condition) if ( this_obj->get_impl().collision_idx == static_cast< std::size_t >( idx.y() ) ) { - ::bvh::vt::debug( "{}: skipping ({}, {}, {}, {}) -- self collision\n", ::vt::theContext()->getNode(), this_obj->get_impl().collision_idx, idx[0], idx[1], idx[2] ); + logger.trace( "{}: skipping <{}, {}, {}, {}> -- self collision", this_obj->id(), idx[0], idx[1], idx[2] ); return; } _narrow->this_proxy = _msg->this_obj; _narrow->other_proxy = _msg->other_obj; - ::bvh::vt::debug( "{}: start_ghosting ({}, {}, {}, {})\n", ::vt::theContext()->getNode(), this_obj->get_impl().collision_idx, idx[0], idx[1], idx[2] ); + logger.debug( "start ghosting <{}, {}, {}, {}>", this_obj->id(), idx[0], idx[1], idx[2] ); auto rank = ::vt::theContext()->getNode(); // Send ghost request to this obj auto msg = ::vt::makeMessage< detail::ghost_request_msg >(); msg->idx = idx; msg->proxy = _narrow->getCollectionProxy(); - //msg->ordering = 0; + // msg->ordering = 0; msg->dest_node = rank; auto this_idx = collision_object_impl::vt_index{ static_cast< std::size_t >( idx[0] ) }; - this_obj->get_impl().narrowphase_patch_collection_proxy[this_idx].sendMsg< detail::ghost_request_msg, &detail::request_ghost >( msg.get() ); + logger.trace( " obj={} requesting patch {} from object {}", this_idx, this_obj->id(), this_idx.x(), + this_obj->id() ); + this_obj->get_impl() + .narrowphase_patch_collection_proxy[this_idx] + .sendMsg< detail::ghost_request_msg, &detail::request_ghost >( msg.get() ); // Send ghost request to other obj auto other_msg = ::vt::makeMessage< detail::ghost_request_msg >(); other_msg->idx = idx; other_msg->proxy = _narrow->getCollectionProxy(); other_msg->dest_node = rank; - //other_msg->ordering = 1; + // other_msg->ordering = 1; auto other_idx = collision_object_impl::vt_index{ static_cast< std::size_t >( idx[2] ) }; - other_obj->get_impl().narrowphase_patch_collection_proxy[other_idx].sendMsg< detail::ghost_request_msg, &detail::request_ghost >( other_msg.get() ); + logger.trace( " obj={} requesting patch {} from object {}", other_idx, this_obj->id(), other_idx.x(), + other_obj->id() ); + other_obj->get_impl() + .narrowphase_patch_collection_proxy[other_idx] + .sendMsg< detail::ghost_request_msg, &detail::request_ghost >( other_msg.get() ); } - void - start_narrowphase( narrowphase_collection_type *_narrow, start_narrowphase_msg * ) + void start_narrowphase( narrowphase_collection_type *_narrow, start_narrowphase_msg * ) { auto idx = _narrow->getIndex(); - ::bvh::vt::debug( "{}: narrowphase ({}, {}, {}) epoch={}\n", ::vt::theContext()->getNode(), idx[0], idx[1], idx[2], ::vt::theMsg()->getEpoch() ); auto &this_obj = *_narrow->this_proxy.get()->self; auto &other_obj = *_narrow->other_proxy.get()->self; auto &this_impl = this_obj.get_impl(); auto &other_impl = other_obj.get_impl(); + auto &logger = this_obj.narrowphase_logger(); + logger.debug( "executing narrowphase <{}, {}, {}, {}> in epoch={}", this_obj.id(), idx[0], idx[1], + idx[2], ::vt::theMsg()->getEpoch() ); + // Run actual narrowphase functor auto &world = *this_obj.get_impl().world; auto &world_impl = get_impl( world ); @@ -266,25 +283,29 @@ namespace bvh // Only run if we are looking at the right "other obj" if ( other_obj.get_impl().collision_idx != static_cast< std::size_t >( idx.y() ) ) { - ::bvh::vt::debug( "{}: skipping ({}, {}, {}, {}) -- mismatched index\n", ::vt::theContext()->getNode(), this_obj.get_impl().collision_idx, idx[0], idx[1], idx[2] ); + logger.trace( "skipping <{}, {}, {}, {}> -- mismatched index", + this_obj.id(), idx[0], idx[1], idx[2] ); return; } // Ignore self collisions (this will usually be caught by the above condition) if ( this_obj.get_impl().collision_idx == static_cast< std::size_t >( idx.y() ) ) { - ::bvh::vt::debug( "{}: skipping ({}, {}, {}, {}) -- self collision\n", ::vt::theContext()->getNode(), this_obj.get_impl().collision_idx, idx[0], idx[1], idx[2] ); + logger.trace( "skipping <{}, {}, {}, {}> -- self collision", + this_obj.id(), idx[0], idx[1], idx[2] ); return; } - always_assert(this_impl.narrowphase_patch_cache.find( this_index ) != this_impl.narrowphase_patch_cache.end(), - " Rank {} this_index {} - not present in `narrowphase_patch_cache`\n", ::vt::theContext()->getNode(), - this_index); + BVH_ASSERT_ALWAYS( this_impl.narrowphase_patch_cache.find( this_index ) != this_impl.narrowphase_patch_cache.end(), + logger, + "this_index={} - not present in `narrowphase_patch_cache`", + this_index ); const auto &this_cache = this_impl.narrowphase_patch_cache.at( this_index ); - always_assert(other_impl.narrowphase_patch_cache.find( other_index ) != other_impl.narrowphase_patch_cache.end(), - " Rank {} other_index {} - not present in `narrowphase_patch_cache`\n", ::vt::theContext()->getNode(), - other_index); + BVH_ASSERT_ALWAYS( other_impl.narrowphase_patch_cache.find( other_index ) != other_impl.narrowphase_patch_cache.end(), + logger, + "other_index={} - not present in `narrowphase_patch_cache`", + other_index ); const auto &other_cache = other_impl.narrowphase_patch_cache.at( other_index ); ::vt::NodeType left_node = this_cache.origin_node; @@ -292,30 +313,45 @@ namespace bvh if ( world_impl.functor ) { - ::vt::trace::TraceScopedEvent scope(world_impl.bvh_impl_functor_); - auto r = world_impl.functor( this_obj, this_cache.meta, static_cast< std::size_t >( idx[0] ), this_cache.patch_data.data(), this_cache.patch_data.size(), - other_obj, other_cache.meta, static_cast< std::size_t >( idx[2] ), other_cache.patch_data.data(), other_cache.patch_data.size() ); + ::vt::trace::TraceScopedEvent scope( world_impl.bvh_impl_functor_ ); + auto r = world_impl.functor( this_obj, this_cache.meta, static_cast< std::size_t >( idx[0] ), + this_cache.patch_data.data(), this_cache.patch_data.size(), other_obj, + other_cache.meta, static_cast< std::size_t >( idx[2] ), + other_cache.patch_data.data(), other_cache.patch_data.size() ); if ( r.a.size() > 0 ) { auto lmsg = ::vt::makeMessage< result_msg >(); lmsg->result = std::move( r.a ); - this_obj.get_impl().objgroup[left_node].sendMsg< result_msg, &collision_object_impl::collision_object_holder::set_result >( lmsg ); + logger.trace( " result from <{}, {}, {}, {}>", + left_node, this_obj.id(), idx[0], idx[1], idx[2] ); + this_obj.get_impl() + .objgroup[left_node] + .sendMsg< result_msg, &collision_object_impl::collision_object_holder::set_result >( lmsg ); } if ( r.b.size() > 0 ) { auto rmsg = ::vt::makeMessage< result_msg >(); rmsg->result = std::move( r.b ); - this_obj.get_impl().objgroup[right_node].sendMsg< result_msg, &collision_object_impl::collision_object_holder::set_result >( rmsg ); + logger.trace( " result from <{}, {}, {}, {}>", + right_node, this_obj.id(), idx[0], idx[1], idx[2] ); + this_obj.get_impl() + .objgroup[right_node] + .sendMsg< result_msg, &collision_object_impl::collision_object_holder::set_result >( rmsg ); } } } - void clear_narrowphase( collision_object_impl::narrowphase_collection_type *_narrow, clear_narrowphase_msg* ) + void clear_narrowphase( collision_object_impl::narrowphase_collection_type *_narrow, clear_narrowphase_msg * ) { + auto &this_obj = *_narrow->this_proxy.get()->self; + auto &logger = this_obj.narrowphase_logger(); + const auto idx = _narrow->getIndex(); + logger.trace( "clearing narrowphase index <{}, {}, {}, {}>", + this_obj.id(), idx[0], idx[1], idx[2] ); _narrow->active = false; } - } // namespace collision_object_impl -} // namespace bvh + } // namespace collision_object_impl +} // namespace bvh diff --git a/src/bvh/collision_object/impl.hpp b/src/bvh/collision_object/impl.hpp index e71fa62..bb53983 100644 --- a/src/bvh/collision_object/impl.hpp +++ b/src/bvh/collision_object/impl.hpp @@ -181,6 +181,7 @@ namespace bvh // Loggers std::shared_ptr< spdlog::logger > logger; std::shared_ptr< spdlog::logger > broadphase_logger; + std::shared_ptr< spdlog::logger > narrowphase_logger; }; namespace collision_object_impl diff --git a/src/bvh/collision_object/narrowphase.cpp b/src/bvh/collision_object/narrowphase.cpp index 3178c5f..a00113c 100644 --- a/src/bvh/collision_object/narrowphase.cpp +++ b/src/bvh/collision_object/narrowphase.cpp @@ -41,8 +41,6 @@ namespace bvh { namespace collision_object_impl { - void (*narrowphase_patch_collection_type::migrate_hook)( narrowphase_patch_collection_type * ) = nullptr; - pending_send activate_narrowphase( vt_index _local_idx, collision_object_proxy_type _this_obj ) { auto msg = ::vt::makeMessage< start_activate_narrowphase_msg >(); @@ -111,10 +109,12 @@ namespace bvh void send_ghost( collision_object_impl::narrowphase_patch_collection_type *_patch, send_ghost_msg *_msg ) { - ::bvh::vt::debug( "{}: index {} has {} destinations\n", ::vt::theContext()->getNode(), _patch->getIndex(), _patch->ghost_destinations.size() ); + const auto &obj = *_patch->collision_object.get()->self; + auto &logger = obj.narrowphase_logger(); + logger.debug( "obj={} index {} has {} destinations", obj.id(), _patch->getIndex(), _patch->ghost_destinations.size() ); for ( auto &&d : _patch->ghost_destinations ) { - ::bvh::vt::debug( "{}: sending ghost for idx {} to node {}\n", ::vt::theContext()->getNode(), _patch->getIndex(), d ); + logger.debug( " obj={} sending ghost for idx {}", d, obj.id(), _patch->getIndex() ); auto msg = ::vt::makeMessage< ghost_msg >(); msg->meta = _patch->patch_meta; msg->patch_data = _patch->bytes; diff --git a/src/bvh/collision_object/types.hpp b/src/bvh/collision_object/types.hpp index 7f17363..a681f72 100644 --- a/src/bvh/collision_object/types.hpp +++ b/src/bvh/collision_object/types.hpp @@ -36,6 +36,7 @@ #include "../tree.hpp" #include "../serialization/bvh_serialize.hpp" #include "../patch.hpp" +#include #include #include #include @@ -105,44 +106,6 @@ namespace bvh } }; - struct narrowphase_patch_collection_type : ::vt::Collection< narrowphase_patch_collection_type, vt_index > - { - static void ( * migrate_hook )( narrowphase_patch_collection_type * ); - - using MessageParentType = ::vt::Collection< narrowphase_patch_collection_type, vt_index >; - vt_msg_serialize_required(); - - patch<> patch_meta; - std::vector< unsigned char > bytes; - ::vt::NodeType origin_node = ::vt::uninitialized_destination; - std::unordered_set< ::vt::NodeType > ghost_destinations; - - void epiMigrateIn() override - { - if ( migrate_hook ) - migrate_hook( this ); - } - - template< typename Serializer > - void serialize( Serializer &_s ) - { - MessageParentType::serialize( _s ); - _s | patch_meta | bytes | origin_node | ghost_destinations; - } - }; - - // Byte serializable - struct narrowphase_patch_msg : ::vt::CollectionMessage< narrowphase_patch_collection_type > - { - patch<> patch_meta; - ::vt::NodeType origin_node = ::vt::uninitialized_destination; - std::size_t data_size = 0; - - // Used with makeMessageSz, invalid otherwise! - unsigned char *user_data() { return reinterpret_cast< unsigned char * >( this ) + sizeof( narrowphase_patch_msg ); } - const unsigned char *user_data() const { return reinterpret_cast< const unsigned char * >( this ) + sizeof( narrowphase_patch_msg ); } - }; - struct result_msg : ::vt::Message { using MessageParentType = ::vt::Message; @@ -219,6 +182,48 @@ namespace bvh using collision_object_proxy_type = ::vt::objgroup::ObjGroupManager::ProxyType< collision_object_holder >; + struct narrowphase_patch_collection_type : ::vt::Collection< narrowphase_patch_collection_type, vt_index > + { + using MessageParentType = ::vt::Collection< narrowphase_patch_collection_type, vt_index >; + vt_msg_serialize_required(); + + narrowphase_patch_collection_type() = default; + explicit narrowphase_patch_collection_type( collision_object_proxy_type _coll_obj ) + : collision_object( _coll_obj ) + {} + + patch<> patch_meta; + std::vector< unsigned char > bytes; + ::vt::NodeType origin_node = ::vt::uninitialized_destination; + std::unordered_set< ::vt::NodeType > ghost_destinations; + collision_object_proxy_type collision_object; + + template< typename Serializer > void serialize( Serializer &_s ) + { + MessageParentType::serialize( _s ); + _s | patch_meta | bytes | origin_node | ghost_destinations | collision_object; + } + }; + + // Byte serializable + struct narrowphase_patch_msg : ::vt::CollectionMessage< narrowphase_patch_collection_type > + { + patch<> patch_meta; + ::vt::NodeType origin_node = ::vt::uninitialized_destination; + std::size_t data_size = 0; + + // Used with makeMessageSz, invalid otherwise! + unsigned char *user_data() + { + return reinterpret_cast< unsigned char * >( this ) + sizeof( narrowphase_patch_msg ); + } + + const unsigned char *user_data() const + { + return reinterpret_cast< const unsigned char * >( this ) + sizeof( narrowphase_patch_msg ); + } + }; + /** * 3D index -- first dimension references the patch id, * the second index references the object id, of the colliding obj, diff --git a/src/bvh/collision_world.cpp b/src/bvh/collision_world.cpp index ab0f776..a65b775 100644 --- a/src/bvh/collision_world.cpp +++ b/src/bvh/collision_world.cpp @@ -53,6 +53,8 @@ namespace bvh m_impl->collision_world_logger->trace( "Initialized collision object logger" ); m_impl->collision_object_broadphase_logger = logging::make_logger( "collision_object.broadphase", stdout_sink ); m_impl->collision_world_logger->trace( "Initialized collision object broadphase logger" ); + m_impl->collision_object_narrowphase_logger = logging::make_logger( "collision_object.narrowphase", stdout_sink ); + m_impl->collision_world_logger->trace( "Initialized collision object narrowphase logger" ); m_impl->overdecomposition = _overdecomposition_factor; auto user_event_name = "bvh_impl_functor_"; @@ -133,4 +135,10 @@ namespace bvh { return m_impl->collision_object_broadphase_logger; } + + std::shared_ptr< spdlog::logger > + collision_world::collision_object_narrowphase_logger() const + { + return m_impl->collision_object_narrowphase_logger; + } } diff --git a/src/bvh/collision_world.hpp b/src/bvh/collision_world.hpp index 71a0fc3..bf4780c 100644 --- a/src/bvh/collision_world.hpp +++ b/src/bvh/collision_world.hpp @@ -97,6 +97,7 @@ namespace bvh std::shared_ptr< spdlog::logger > collision_object_logger() const; std::shared_ptr< spdlog::logger > collision_object_broadphase_logger() const; + std::shared_ptr< spdlog::logger > collision_object_narrowphase_logger() const; private: diff --git a/src/bvh/collision_world/impl.hpp b/src/bvh/collision_world/impl.hpp index aa45785..6a5366f 100644 --- a/src/bvh/collision_world/impl.hpp +++ b/src/bvh/collision_world/impl.hpp @@ -67,6 +67,7 @@ namespace bvh std::shared_ptr< spdlog::logger > collision_world_logger; std::shared_ptr< spdlog::logger > collision_object_logger; std::shared_ptr< spdlog::logger > collision_object_broadphase_logger; + std::shared_ptr< spdlog::logger > collision_object_narrowphase_logger; }; } diff --git a/tests/SerializerTest.cpp b/tests/SerializerTest.cpp index 2ea90b9..4046fdf 100644 --- a/tests/SerializerTest.cpp +++ b/tests/SerializerTest.cpp @@ -55,7 +55,7 @@ TEMPLATE_TEST_CASE("a single value can be serialized", "[serializer]", int, doub REQUIRE( serialized->getSize() == sizeof( T ) + 12 ); auto b = *checkpoint::deserialize< T >( serialized->getBuffer() ); - + REQUIRE( b == T{5} ); } @@ -188,7 +188,6 @@ TEST_CASE("narrowphase_patches collection serialization", "[serializer][collisio using narrowphase_patch_collection_type = bvh::collision_object_impl::narrowphase_patch_collection_type; if ( ::vt::theContext()->getNumNodes() > 1 ) { - narrowphase_patch_collection_type::migrate_hook = &narrowphase_patch_check; auto coll_size = vt_index{ static_cast< std::size_t >( 4 * ::vt::theContext()->getNumNodes() ) }; auto ep = ::vt::theTerm()->makeEpochCollective( "narrowphase_patch_test" ); ::vt::theMsg()->pushEpoch( ep ); @@ -227,7 +226,6 @@ TEST_CASE("narrowphase_patches collection serialization", "[serializer][collisio ::vt::theMsg()->popEpoch(); ::vt::theTerm()->finishedEpoch( ep ); ::vt::runSchedulerThrough( ep ); - narrowphase_patch_collection_type::migrate_hook = nullptr; } } @@ -241,7 +239,7 @@ TEMPLATE_TEST_CASE("multiple values can be serialized", "[serializer]", int, dou s << T{ 17 } << static_cast< T >( 21.3 ) << static_cast< T >( 3.9 ); s >> a >> b >> c; - + REQUIRE( a == T{ 17 } ); REQUIRE( b == static_cast< T >( 21.3 ) ); REQUIRE( c == static_cast< T >( 3.9 ) ); @@ -251,13 +249,13 @@ TEST_CASE("multiple differently-typed values can be serialized", "[serializer]") { bvh::serializer s; s << 5 << 3.7 << 1.1f; - + int a; double b; float c; - + s >> a >> b >> c; - + REQUIRE( a == 5 ); REQUIRE( b == 3.7 ); REQUIRE( c == 1.1f ); @@ -283,7 +281,7 @@ TEST_CASE("strings can be serialized", "[serializer]") TEST_CASE("char array literals can be serialized and deserialized as strings", "[serializer]") { using namespace std::string_literals; - + bvh::serializer s; s << "hello, " << "world"; @@ -300,19 +298,19 @@ TEST_CASE("char array literals can be serialized and deserialized as strings", " TEST_CASE("a simple vector can be serialized", "[serializer]") { using namespace std::string_literals; - + bvh::serializer s; - + auto v = std::vector< int >{ 1, 2, 3 }; - + s << v; std::vector< int > r; s >> r; - + REQUIRE( r.size() == v.size() ); - + for ( std::size_t i = 0; i < r.size(); ++i ) REQUIRE( r[i] == v[i] ); } @@ -321,9 +319,9 @@ struct NonTrivial { NonTrivial() = default; NonTrivial( int _m ) : m( _m ) {} - + int m; - + virtual ~NonTrivial() {} }; @@ -332,7 +330,7 @@ bvh::serializer_interface< Serializer > & operator<<( bvh::serializer_interface< Serializer > &_serializer, const NonTrivial &_nt ) { _serializer << _nt.m; - + return _serializer; } @@ -341,26 +339,26 @@ bvh::serializer_interface< Serializer > & operator>>( bvh::serializer_interface< Serializer > &_serializer, NonTrivial &_nt ) { _serializer >> _nt.m; - + return _serializer; } TEST_CASE("vectors of custom serialized types can be serialized", "[serializer]") { using namespace std::string_literals; - + bvh::serializer s; - + auto v = std::vector< NonTrivial >{ 1, 2, 3 }; - + s << v; std::vector< NonTrivial > r; s >> r; - + REQUIRE( r.size() == v.size() ); - + for ( std::size_t i = 0; i < r.size(); ++i ) REQUIRE( r[i].m == v[i].m ); } @@ -368,19 +366,19 @@ TEST_CASE("vectors of custom serialized types can be serialized", "[serializer]" TEST_CASE("a nontrivial vector that wraps an int can be identically deserialized as a vector of ints", "[serializer]") { using namespace std::string_literals; - + bvh::serializer s; - + auto v = std::vector< NonTrivial >{ 1, 2, 3 }; - + s << v; std::vector< int > r; s >> r; - + REQUIRE( r.size() == v.size() ); - + for ( std::size_t i = 0; i < r.size(); ++i ) REQUIRE( r[i] == v[i].m ); } @@ -388,19 +386,19 @@ TEST_CASE("a nontrivial vector that wraps an int can be identically deserialized TEST_CASE("a vector of ints can be identically deserialized as nontrivial wrapper type", "[serializer]") { using namespace std::string_literals; - + bvh::serializer s; - + auto v = std::vector< int >{ 1, 2, 3 }; - + s << v; std::vector< NonTrivial > r; s >> r; - + REQUIRE( r.size() == v.size() ); - + for ( std::size_t i = 0; i < r.size(); ++i ) REQUIRE( r[i].m == v[i] ); } @@ -408,35 +406,35 @@ TEST_CASE("a vector of ints can be identically deserialized as nontrivial wrappe TEST_CASE("a dop26d can be serialized", "[serializer]") { auto kdop = bvh::dop_26d::from_sphere( 0.0, 0.0, 0.0, 1.0 ); - + bvh::serializer s; - + s << kdop; - + bvh::dop_26d kdop2; - + s >> kdop2; - + REQUIRE( kdop == kdop2 ); } TEST_CASE("an empty tree can be serialized", "[serializer]") { auto tree = bvh::snapshot_tree_26d< Element >{}; - + bvh::serializer s; - + s << tree; - + auto tree2 = bvh::snapshot_tree_26d< Element >{}; - + s >> tree2; - + REQUIRE( tree2.debug_validate() ); - + REQUIRE( tree2.count() == 0 ); REQUIRE( tree.count() == tree2.count() ); - + REQUIRE( tree == tree2 ); } @@ -444,20 +442,20 @@ TEST_CASE("a tree can be serialized", "[serializer]") { auto elements = buildElementGrid( 2, 2, 2 ); auto tree = bvh::build_snapshot_tree_top_down(elements ); - + bvh::serializer s; - + s << tree; - + auto tree2 = bvh::snapshot_tree_26d< Element >{}; - + s >> tree2; - + REQUIRE_NOTHROW( tree2.debug_validate() ); - + REQUIRE( tree2.count() == elements.size() ); REQUIRE( tree.count() == tree2.count() ); - + REQUIRE( tree == tree2 ); } @@ -465,20 +463,20 @@ TEST_CASE("a tree with a single element can be serialized", "[serializer]") { auto elements = buildElementGrid( 1, 1, 1 ); auto tree = bvh::build_snapshot_tree_top_down(elements ); - + bvh::serializer s; - + s << tree; - + auto tree2 = bvh::snapshot_tree_26d< Element >{}; - + s >> tree2; - + REQUIRE_NOTHROW( tree2.debug_validate() ); - + REQUIRE( tree2.count() == elements.size() ); REQUIRE( tree.count() == tree2.count() ); - + REQUIRE( tree == tree2 ); } #endif From dbfae14e0199b56a6f33f9a8536326bdc5ad796c Mon Sep 17 00:00:00 2001 From: Nicolas Morales Date: Thu, 16 Nov 2023 15:07:40 -0800 Subject: [PATCH 04/11] #19: logging: for now, flush on every output --- src/bvh/logging.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/bvh/logging.hpp b/src/bvh/logging.hpp index d4d8227..590892c 100644 --- a/src/bvh/logging.hpp +++ b/src/bvh/logging.hpp @@ -42,6 +42,7 @@ namespace bvh::logging auto ret = std::make_shared< spdlog::logger >( std::move( _name ), std::move( _sink ) ); ret->set_formatter( make_formatter() ); ret->set_level( spdlog::level::trace ); + ret->flush_on( spdlog::level::trace ); return ret; } From 7bc5f67fe5b7b9d172a7cee585b07366bb85bb71 Mon Sep 17 00:00:00 2001 From: Nicolas Morales Date: Thu, 16 Nov 2023 16:06:38 -0800 Subject: [PATCH 05/11] #19: logging: add extra logs for narrowphase activation --- src/bvh/collision_object/impl.cpp | 4 ++++ src/bvh/collision_object/impl.hpp | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/src/bvh/collision_object/impl.cpp b/src/bvh/collision_object/impl.cpp index 2f06008..302f991 100644 --- a/src/bvh/collision_object/impl.cpp +++ b/src/bvh/collision_object/impl.cpp @@ -169,6 +169,10 @@ namespace bvh void activate_narrowphase( collision_object_impl::narrowphase_collection_type *_narrow, activate_narrowphase_msg * ) { + const auto &this_obj = *_narrow->this_proxy.get()->self; + auto &logger = this_obj.narrowphase_logger(); + auto idx = _narrow->getIndex(); + logger.trace( "marking <{}, {}, {}, {}> as active", this_obj.id(), idx[0], idx[1], idx[2] ); _narrow->active = true; } diff --git a/src/bvh/collision_object/impl.hpp b/src/bvh/collision_object/impl.hpp index bb53983..b3d5889 100644 --- a/src/bvh/collision_object/impl.hpp +++ b/src/bvh/collision_object/impl.hpp @@ -51,6 +51,10 @@ namespace bvh narrowphase_patch_copy( collision_object_impl::narrowphase_patch_collection_type *_patch, narrowphase_patch_msg *_msg ) { + const auto &obj = *_patch->collision_object.get()->self; + auto &logger = obj.narrowphase_logger(); + auto idx = _patch->getIndex(); + logger.debug( "late initializing narrowphase patch {} with {} bytes", idx.x(), _msg->data_size ); _patch->ghost_destinations.clear(); _patch->patch_meta = _msg->patch_meta; _patch->bytes.resize(_msg->data_size); From 094838538c277c10713c50f05db23500393d5024 Mon Sep 17 00:00:00 2001 From: Nicolas Morales Date: Mon, 20 Nov 2023 09:45:04 -0800 Subject: [PATCH 06/11] #19: logging: fix invalid proxy and add parameterization for logging --- src/bvh/collision_object/impl.cpp | 5 +++-- src/bvh/collision_object/types.hpp | 4 +++- src/bvh/collision_world.cpp | 10 +++++----- src/bvh/collision_world.hpp | 5 +++-- src/bvh/logging.hpp | 9 +++++---- 5 files changed, 19 insertions(+), 14 deletions(-) diff --git a/src/bvh/collision_object/impl.cpp b/src/bvh/collision_object/impl.cpp index 302f991..3baf7f3 100644 --- a/src/bvh/collision_object/impl.cpp +++ b/src/bvh/collision_object/impl.cpp @@ -90,6 +90,7 @@ namespace bvh for ( auto &&idx : impl.active_narrowphase_indices ) { auto msg = ::vt::makeMessage< activate_narrowphase_msg >(); + msg->this_obj = self->get_impl().objgroup; logger.trace( " obj={} activate_narrowphase", idx, self->id() ); impl.narrowphase_collection_proxy[idx] .sendMsg< activate_narrowphase_msg, &collision_object_impl::activate_narrowphase >( msg.get() ); @@ -167,9 +168,9 @@ namespace bvh self->get_impl().local_results.emplace_back( _msg->result ); } - void activate_narrowphase( collision_object_impl::narrowphase_collection_type *_narrow, activate_narrowphase_msg * ) + void activate_narrowphase( collision_object_impl::narrowphase_collection_type *_narrow, activate_narrowphase_msg *_msg ) { - const auto &this_obj = *_narrow->this_proxy.get()->self; + const auto &this_obj = *_msg->this_obj.get()->self; auto &logger = this_obj.narrowphase_logger(); auto idx = _narrow->getIndex(); logger.trace( "marking <{}, {}, {}, {}> as active", this_obj.id(), idx[0], idx[1], idx[2] ); diff --git a/src/bvh/collision_object/types.hpp b/src/bvh/collision_object/types.hpp index a681f72..b3499d1 100644 --- a/src/bvh/collision_object/types.hpp +++ b/src/bvh/collision_object/types.hpp @@ -259,7 +259,9 @@ namespace bvh { }; struct activate_narrowphase_msg : ::vt::CollectionMessage< collision_object_impl::narrowphase_collection_type > - { }; + { + collision_object_proxy_type this_obj; + }; struct start_ghosting_msg : ::vt::CollectionMessage< collision_object_impl::narrowphase_collection_type > { diff --git a/src/bvh/collision_world.cpp b/src/bvh/collision_world.cpp index a65b775..0e978e9 100644 --- a/src/bvh/collision_world.cpp +++ b/src/bvh/collision_world.cpp @@ -42,18 +42,18 @@ namespace bvh { - collision_world::collision_world( std::size_t _overdecomposition_factor ) + collision_world::collision_world( std::size_t _overdecomposition_factor, const world_config &_cfg ) : m_impl( std::make_unique< impl >() ) { auto stdout_sink = std::make_shared< spdlog::sinks::stdout_color_sink_st >(); stdout_sink->set_level( spdlog::level::trace ); - m_impl->collision_world_logger = logging::make_logger( "collision_world", stdout_sink ); + m_impl->collision_world_logger = logging::make_logger( "collision_world", stdout_sink, _cfg ); m_impl->collision_world_logger->trace( "Initialized collision world logger" ); - m_impl->collision_object_logger = logging::make_logger( "collision_object", stdout_sink ); + m_impl->collision_object_logger = logging::make_logger( "collision_object", stdout_sink, _cfg ); m_impl->collision_world_logger->trace( "Initialized collision object logger" ); - m_impl->collision_object_broadphase_logger = logging::make_logger( "collision_object.broadphase", stdout_sink ); + m_impl->collision_object_broadphase_logger = logging::make_logger( "collision_object.broadphase", stdout_sink, _cfg ); m_impl->collision_world_logger->trace( "Initialized collision object broadphase logger" ); - m_impl->collision_object_narrowphase_logger = logging::make_logger( "collision_object.narrowphase", stdout_sink ); + m_impl->collision_object_narrowphase_logger = logging::make_logger( "collision_object.narrowphase", stdout_sink, _cfg ); m_impl->collision_world_logger->trace( "Initialized collision object narrowphase logger" ); m_impl->overdecomposition = _overdecomposition_factor; diff --git a/src/bvh/collision_world.hpp b/src/bvh/collision_world.hpp index bf4780c..6d4ee32 100644 --- a/src/bvh/collision_world.hpp +++ b/src/bvh/collision_world.hpp @@ -47,7 +47,8 @@ namespace bvh struct world_config { - spdlog::level::level_enum log_levels = spdlog::level::info; + spdlog::level::level_enum log_levels = spdlog::level::trace; + spdlog::level::level_enum flush_level = spdlog::level::trace; }; class collision_world @@ -57,7 +58,7 @@ namespace bvh template< typename T > using narrowphase_functor = std::function< narrowphase_result_pair( const broadphase_collision< T > &, const broadphase_collision< T > & ) >; - explicit collision_world( std::size_t _overdecomposition_factor ); + explicit collision_world( std::size_t _overdecomposition_factor, const world_config &_cfg = {} ); ~collision_world(); collision_world( const collision_world & ) = delete; diff --git a/src/bvh/logging.hpp b/src/bvh/logging.hpp index 590892c..ee8d398 100644 --- a/src/bvh/logging.hpp +++ b/src/bvh/logging.hpp @@ -7,6 +7,7 @@ #include #include #include +#include "collision_world.hpp" namespace bvh::logging { @@ -36,13 +37,13 @@ namespace bvh::logging return ret; } - inline std::shared_ptr< spdlog::logger > - make_logger( std::string _name, spdlog::sink_ptr _sink ) + inline std::shared_ptr< spdlog::logger > make_logger( std::string _name, spdlog::sink_ptr _sink, + const world_config &_cfg ) { auto ret = std::make_shared< spdlog::logger >( std::move( _name ), std::move( _sink ) ); ret->set_formatter( make_formatter() ); - ret->set_level( spdlog::level::trace ); - ret->flush_on( spdlog::level::trace ); + ret->set_level( _cfg.log_levels ); + ret->flush_on( _cfg.flush_level ); return ret; } From 75b765747a2647aadc2ed2e23e875626789598af Mon Sep 17 00:00:00 2001 From: Nicolas Morales Date: Mon, 20 Nov 2023 10:50:36 -0800 Subject: [PATCH 07/11] #19: logging: add additional tracing for request ghosts step --- src/bvh/collision_object/narrowphase.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/bvh/collision_object/narrowphase.cpp b/src/bvh/collision_object/narrowphase.cpp index a00113c..fb68393 100644 --- a/src/bvh/collision_object/narrowphase.cpp +++ b/src/bvh/collision_object/narrowphase.cpp @@ -93,9 +93,11 @@ namespace bvh { auto &this_obj = _this_obj.get()->self; auto &other_obj = _other_obj.get()->self; + auto &logger = this_obj->narrowphase_logger(); auto msg = ::vt::makeMessage< start_ghosting_msg >(); msg->this_obj = this_obj->get_impl().objgroup; msg->other_obj = other_obj->get_impl().objgroup; + logger.debug( " requesting ghosts for objects {} and {} in potential collision", this_obj->id(), other_obj->id() ); return _this_obj[::vt::theContext()->getNode()].sendMsg< start_ghosting_msg, &collision_object_impl::collision_object_holder::request_ghosts >( msg ); } From 5e3e03efdd7095aef98d4cd9130c51c3b23aed8f Mon Sep 17 00:00:00 2001 From: Nicolas Morales Date: Tue, 21 Nov 2023 13:12:13 -0800 Subject: [PATCH 08/11] #19: logging: add more epochs to logging --- src/bvh/collision_object/impl.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/bvh/collision_object/impl.cpp b/src/bvh/collision_object/impl.cpp index 3baf7f3..bcf9980 100644 --- a/src/bvh/collision_object/impl.cpp +++ b/src/bvh/collision_object/impl.cpp @@ -32,6 +32,7 @@ */ #include "impl.hpp" #include "narrowphase.hpp" +#include namespace bvh { @@ -173,7 +174,7 @@ namespace bvh const auto &this_obj = *_msg->this_obj.get()->self; auto &logger = this_obj.narrowphase_logger(); auto idx = _narrow->getIndex(); - logger.trace( "marking <{}, {}, {}, {}> as active", this_obj.id(), idx[0], idx[1], idx[2] ); + logger.trace( "marking <{}, {}, {}, {}> as active (epoch={:x})", this_obj.id(), idx[0], idx[1], idx[2], ::vt::envelopeGetEpoch( _msg->env ) ); _narrow->active = true; } @@ -245,7 +246,7 @@ namespace bvh // msg->ordering = 0; msg->dest_node = rank; auto this_idx = collision_object_impl::vt_index{ static_cast< std::size_t >( idx[0] ) }; - logger.trace( " obj={} requesting patch {} from object {}", this_idx, this_obj->id(), this_idx.x(), + logger.trace( " obj={} requesting primary patch {} from object {}", this_idx, this_obj->id(), this_idx.x(), this_obj->id() ); this_obj->get_impl() .narrowphase_patch_collection_proxy[this_idx] @@ -258,7 +259,7 @@ namespace bvh other_msg->dest_node = rank; // other_msg->ordering = 1; auto other_idx = collision_object_impl::vt_index{ static_cast< std::size_t >( idx[2] ) }; - logger.trace( " obj={} requesting patch {} from object {}", other_idx, this_obj->id(), other_idx.x(), + logger.trace( " obj={} requesting secondary patch {} from object {}", other_idx, this_obj->id(), other_idx.x(), other_obj->id() ); other_obj->get_impl() .narrowphase_patch_collection_proxy[other_idx] From c6d9b6101d0d4e6dce3f8b66b78aab0c257ed105 Mon Sep 17 00:00:00 2001 From: Nicolas Morales Date: Tue, 23 Apr 2024 13:19:38 -0700 Subject: [PATCH 09/11] #19: logging: add formatters for k-dops and vec types --- src/bvh/collision_object.cpp | 2 +- src/bvh/kdop.hpp | 42 ++++++++++++++++++++++++++++++++++++ src/bvh/math/vec.hpp | 19 ++++++++++++++++ 3 files changed, 62 insertions(+), 1 deletion(-) diff --git a/src/bvh/collision_object.cpp b/src/bvh/collision_object.cpp index d6f48d7..ab3ba97 100644 --- a/src/bvh/collision_object.cpp +++ b/src/bvh/collision_object.cpp @@ -99,7 +99,7 @@ namespace bvh // Initialize objgroup for per-node data ::vt::runInEpochCollective( "collision_object.make_objgroup", [&](){ - m_impl->objgroup = ::vt::theObjGroup()->makeCollective( fmt::vt::format( "collision_object {}", _idx ) ); + m_impl->objgroup = ::vt::theObjGroup()->makeCollective( fmt::format( "collision_object {}", _idx ) ); m_impl->objgroup.get()->self = this; m_impl->logger->debug( "obj={} objgroup make_collective {:x}", m_impl->collision_idx, m_impl->objgroup.getProxy() ); diff --git a/src/bvh/kdop.hpp b/src/bvh/kdop.hpp index d2bfd42..a91b76c 100644 --- a/src/bvh/kdop.hpp +++ b/src/bvh/kdop.hpp @@ -43,6 +43,7 @@ #include "util/attributes.hpp" #include "util/kokkos.hpp" #include "iterators/transform_iterator.hpp" +#include namespace bvh { @@ -714,4 +715,45 @@ namespace bvh }; } +template< typename T > +struct fmt::formatter< bvh::extent< T > > : nested_formatter< T > +{ + auto format( bvh::extent< T > _ext, format_context &_ctx ) const + { + return this->write_padded( _ctx, [=]( auto out ) { + return format_to( out, "[{}, {}]", this->nested( _ext.min ), this->nested( _ext.max ) ); + } ); + } +}; + +template< typename T, int K, typename D > +struct fmt::formatter< bvh::kdop_base< T, K, D > > : nested_formatter< bvh::extent< T > > +{ + auto format( const bvh::kdop_base< T, K, D > &_kd, format_context &_ctx ) const + { + return this->write_padded( _ctx, [=]( auto out ) { + if constexpr ( K <= 0 ) + return format_to( out, "{}-dop: ", K ); + + auto pos = format_to( out, "{}-dop: {}", K, this->nested( _kd.extents[0] ) ); + for ( int i = 1; i < K / 2; ++i ) + pos = format_to( pos, ", {}", this->nested( _kd.extents[i] ) ); + + return pos; + } ); + } +}; + +template< typename T > +struct fmt::formatter< bvh::dop_6< T > > : fmt::formatter< bvh::kdop_base< T, 6, bvh::dop_6< T > > > +{}; + +template< typename T > +struct fmt::formatter< bvh::dop_18< T > > : fmt::formatter< bvh::kdop_base< T, 18, bvh::dop_18< T > > > +{}; + +template< typename T > +struct fmt::formatter< bvh::dop_26< T > > : fmt::formatter< bvh::kdop_base< T, 26, bvh::dop_26< T > > > +{}; + #endif // INC_BVH_KDOP_HPP diff --git a/src/bvh/math/vec.hpp b/src/bvh/math/vec.hpp index 2266820..bddbea6 100644 --- a/src/bvh/math/vec.hpp +++ b/src/bvh/math/vec.hpp @@ -46,6 +46,7 @@ #include "../util/kokkos.hpp" #include "named_access.hpp" #include "ops/vec_ops.hpp" +#include namespace bvh { @@ -342,4 +343,22 @@ namespace bvh } // namespace m } // namespace bvh +template< typename T, unsigned N > +struct fmt::formatter< bvh::m::vec< T, N > > : nested_formatter< T > +{ + auto format( bvh::m::vec< T, N > _vec, format_context &_ctx ) const + { + return this->write_padded( _ctx, [=]( auto out ) { + if constexpr ( N == 0 ) + return format_to( out, "<>" ); + + auto pos = format_to( out, "< {}", this->nested( _vec[0] ) ); + for ( unsigned i = 1; i < N; ++i ) + pos = format_to( pos, ", {}", this->nested( _vec[i] ) ); + + return format_to( pos, " >" ); + } ); + } +}; + #endif // INC_BVH_MATH_VEC_HPP From 3a21bcf271d2304853bbc376c309069e696342a4 Mon Sep 17 00:00:00 2001 From: Nicolas Morales Date: Thu, 6 Jun 2024 11:18:17 -0700 Subject: [PATCH 10/11] #19: use external spdlog --- CMakeLists.txt | 3 + src/bvh/collision_world/impl.hpp | 1 - tpl/CMakeLists.txt | 1 - tpl/spdlog/CMakeLists.txt | 10 - tpl/spdlog/include/spdlog/async.h | 99 -- tpl/spdlog/include/spdlog/async_logger-inl.h | 90 -- tpl/spdlog/include/spdlog/async_logger.h | 68 - tpl/spdlog/include/spdlog/cfg/argv.h | 44 - tpl/spdlog/include/spdlog/cfg/env.h | 38 - tpl/spdlog/include/spdlog/cfg/helpers-inl.h | 120 -- tpl/spdlog/include/spdlog/cfg/helpers.h | 29 - tpl/spdlog/include/spdlog/common-inl.h | 82 - tpl/spdlog/include/spdlog/common.h | 426 ----- .../include/spdlog/details/backtracer-inl.h | 75 - .../include/spdlog/details/backtracer.h | 46 - .../include/spdlog/details/circular_q.h | 146 -- .../include/spdlog/details/console_globals.h | 32 - .../include/spdlog/details/file_helper-inl.h | 180 --- .../include/spdlog/details/file_helper.h | 62 - .../include/spdlog/details/fmt_helper.h | 164 -- .../include/spdlog/details/log_msg-inl.h | 37 - tpl/spdlog/include/spdlog/details/log_msg.h | 37 - .../spdlog/details/log_msg_buffer-inl.h | 58 - .../include/spdlog/details/log_msg_buffer.h | 33 - .../include/spdlog/details/mpmc_blocking_q.h | 154 -- .../include/spdlog/details/null_mutex.h | 45 - tpl/spdlog/include/spdlog/details/os-inl.h | 635 -------- tpl/spdlog/include/spdlog/details/os.h | 122 -- .../spdlog/details/periodic_worker-inl.h | 28 - .../include/spdlog/details/periodic_worker.h | 60 - .../include/spdlog/details/registry-inl.h | 315 ---- tpl/spdlog/include/spdlog/details/registry.h | 123 -- .../spdlog/details/synchronous_factory.h | 24 - .../spdlog/details/tcp_client-windows.h | 160 -- .../include/spdlog/details/tcp_client.h | 146 -- .../include/spdlog/details/thread_pool-inl.h | 137 -- .../include/spdlog/details/thread_pool.h | 122 -- .../spdlog/details/udp_client-windows.h | 113 -- .../include/spdlog/details/udp_client.h | 94 -- .../include/spdlog/details/windows_include.h | 11 - tpl/spdlog/include/spdlog/fmt/bin_to_hex.h | 248 --- tpl/spdlog/include/spdlog/fmt/chrono.h | 22 - tpl/spdlog/include/spdlog/fmt/compile.h | 22 - tpl/spdlog/include/spdlog/fmt/fmt.h | 33 - tpl/spdlog/include/spdlog/fmt/ostr.h | 22 - tpl/spdlog/include/spdlog/fmt/ranges.h | 22 - tpl/spdlog/include/spdlog/fmt/std.h | 23 - tpl/spdlog/include/spdlog/fmt/xchar.h | 22 - tpl/spdlog/include/spdlog/formatter.h | 18 - tpl/spdlog/include/spdlog/fwd.h | 18 - tpl/spdlog/include/spdlog/logger-inl.h | 257 --- tpl/spdlog/include/spdlog/logger.h | 427 ----- .../include/spdlog/pattern_formatter-inl.h | 1436 ----------------- tpl/spdlog/include/spdlog/pattern_formatter.h | 128 -- .../include/spdlog/sinks/android_sink.h | 146 -- .../include/spdlog/sinks/ansicolor_sink-inl.h | 145 -- .../include/spdlog/sinks/ansicolor_sink.h | 118 -- .../include/spdlog/sinks/base_sink-inl.h | 63 - tpl/spdlog/include/spdlog/sinks/base_sink.h | 52 - .../spdlog/sinks/basic_file_sink-inl.h | 44 - .../include/spdlog/sinks/basic_file_sink.h | 60 - .../include/spdlog/sinks/callback_sink.h | 61 - .../include/spdlog/sinks/daily_file_sink.h | 247 --- tpl/spdlog/include/spdlog/sinks/dist_sink.h | 97 -- .../include/spdlog/sinks/dup_filter_sink.h | 96 -- .../include/spdlog/sinks/hourly_file_sink.h | 204 --- tpl/spdlog/include/spdlog/sinks/kafka_sink.h | 133 -- tpl/spdlog/include/spdlog/sinks/mongo_sink.h | 107 -- tpl/spdlog/include/spdlog/sinks/msvc_sink.h | 71 - tpl/spdlog/include/spdlog/sinks/null_sink.h | 44 - .../include/spdlog/sinks/ostream_sink.h | 50 - tpl/spdlog/include/spdlog/sinks/qt_sinks.h | 292 ---- .../include/spdlog/sinks/ringbuffer_sink.h | 74 - .../spdlog/sinks/rotating_file_sink-inl.h | 152 -- .../include/spdlog/sinks/rotating_file_sink.h | 81 - tpl/spdlog/include/spdlog/sinks/sink-inl.h | 25 - tpl/spdlog/include/spdlog/sinks/sink.h | 35 - .../spdlog/sinks/stdout_color_sinks-inl.h | 38 - .../include/spdlog/sinks/stdout_color_sinks.h | 45 - .../include/spdlog/sinks/stdout_sinks-inl.h | 138 -- .../include/spdlog/sinks/stdout_sinks.h | 87 - tpl/spdlog/include/spdlog/sinks/syslog_sink.h | 109 -- .../include/spdlog/sinks/systemd_sink.h | 126 -- tpl/spdlog/include/spdlog/sinks/tcp_sink.h | 81 - tpl/spdlog/include/spdlog/sinks/udp_sink.h | 74 - .../include/spdlog/sinks/win_eventlog_sink.h | 289 ---- .../include/spdlog/sinks/wincolor_sink-inl.h | 175 -- .../include/spdlog/sinks/wincolor_sink.h | 85 - tpl/spdlog/include/spdlog/spdlog-inl.h | 125 -- tpl/spdlog/include/spdlog/spdlog.h | 363 ----- tpl/spdlog/include/spdlog/stopwatch.h | 69 - tpl/spdlog/include/spdlog/tweakme.h | 140 -- tpl/spdlog/include/spdlog/version.h | 10 - 93 files changed, 3 insertions(+), 11216 deletions(-) delete mode 100644 tpl/spdlog/CMakeLists.txt delete mode 100644 tpl/spdlog/include/spdlog/async.h delete mode 100644 tpl/spdlog/include/spdlog/async_logger-inl.h delete mode 100644 tpl/spdlog/include/spdlog/async_logger.h delete mode 100644 tpl/spdlog/include/spdlog/cfg/argv.h delete mode 100644 tpl/spdlog/include/spdlog/cfg/env.h delete mode 100644 tpl/spdlog/include/spdlog/cfg/helpers-inl.h delete mode 100644 tpl/spdlog/include/spdlog/cfg/helpers.h delete mode 100644 tpl/spdlog/include/spdlog/common-inl.h delete mode 100644 tpl/spdlog/include/spdlog/common.h delete mode 100644 tpl/spdlog/include/spdlog/details/backtracer-inl.h delete mode 100644 tpl/spdlog/include/spdlog/details/backtracer.h delete mode 100644 tpl/spdlog/include/spdlog/details/circular_q.h delete mode 100644 tpl/spdlog/include/spdlog/details/console_globals.h delete mode 100644 tpl/spdlog/include/spdlog/details/file_helper-inl.h delete mode 100644 tpl/spdlog/include/spdlog/details/file_helper.h delete mode 100644 tpl/spdlog/include/spdlog/details/fmt_helper.h delete mode 100644 tpl/spdlog/include/spdlog/details/log_msg-inl.h delete mode 100644 tpl/spdlog/include/spdlog/details/log_msg.h delete mode 100644 tpl/spdlog/include/spdlog/details/log_msg_buffer-inl.h delete mode 100644 tpl/spdlog/include/spdlog/details/log_msg_buffer.h delete mode 100644 tpl/spdlog/include/spdlog/details/mpmc_blocking_q.h delete mode 100644 tpl/spdlog/include/spdlog/details/null_mutex.h delete mode 100644 tpl/spdlog/include/spdlog/details/os-inl.h delete mode 100644 tpl/spdlog/include/spdlog/details/os.h delete mode 100644 tpl/spdlog/include/spdlog/details/periodic_worker-inl.h delete mode 100644 tpl/spdlog/include/spdlog/details/periodic_worker.h delete mode 100644 tpl/spdlog/include/spdlog/details/registry-inl.h delete mode 100644 tpl/spdlog/include/spdlog/details/registry.h delete mode 100644 tpl/spdlog/include/spdlog/details/synchronous_factory.h delete mode 100644 tpl/spdlog/include/spdlog/details/tcp_client-windows.h delete mode 100644 tpl/spdlog/include/spdlog/details/tcp_client.h delete mode 100644 tpl/spdlog/include/spdlog/details/thread_pool-inl.h delete mode 100644 tpl/spdlog/include/spdlog/details/thread_pool.h delete mode 100644 tpl/spdlog/include/spdlog/details/udp_client-windows.h delete mode 100644 tpl/spdlog/include/spdlog/details/udp_client.h delete mode 100644 tpl/spdlog/include/spdlog/details/windows_include.h delete mode 100644 tpl/spdlog/include/spdlog/fmt/bin_to_hex.h delete mode 100644 tpl/spdlog/include/spdlog/fmt/chrono.h delete mode 100644 tpl/spdlog/include/spdlog/fmt/compile.h delete mode 100644 tpl/spdlog/include/spdlog/fmt/fmt.h delete mode 100644 tpl/spdlog/include/spdlog/fmt/ostr.h delete mode 100644 tpl/spdlog/include/spdlog/fmt/ranges.h delete mode 100644 tpl/spdlog/include/spdlog/fmt/std.h delete mode 100644 tpl/spdlog/include/spdlog/fmt/xchar.h delete mode 100644 tpl/spdlog/include/spdlog/formatter.h delete mode 100644 tpl/spdlog/include/spdlog/fwd.h delete mode 100644 tpl/spdlog/include/spdlog/logger-inl.h delete mode 100644 tpl/spdlog/include/spdlog/logger.h delete mode 100644 tpl/spdlog/include/spdlog/pattern_formatter-inl.h delete mode 100644 tpl/spdlog/include/spdlog/pattern_formatter.h delete mode 100644 tpl/spdlog/include/spdlog/sinks/android_sink.h delete mode 100644 tpl/spdlog/include/spdlog/sinks/ansicolor_sink-inl.h delete mode 100644 tpl/spdlog/include/spdlog/sinks/ansicolor_sink.h delete mode 100644 tpl/spdlog/include/spdlog/sinks/base_sink-inl.h delete mode 100644 tpl/spdlog/include/spdlog/sinks/base_sink.h delete mode 100644 tpl/spdlog/include/spdlog/sinks/basic_file_sink-inl.h delete mode 100644 tpl/spdlog/include/spdlog/sinks/basic_file_sink.h delete mode 100644 tpl/spdlog/include/spdlog/sinks/callback_sink.h delete mode 100644 tpl/spdlog/include/spdlog/sinks/daily_file_sink.h delete mode 100644 tpl/spdlog/include/spdlog/sinks/dist_sink.h delete mode 100644 tpl/spdlog/include/spdlog/sinks/dup_filter_sink.h delete mode 100644 tpl/spdlog/include/spdlog/sinks/hourly_file_sink.h delete mode 100644 tpl/spdlog/include/spdlog/sinks/kafka_sink.h delete mode 100644 tpl/spdlog/include/spdlog/sinks/mongo_sink.h delete mode 100644 tpl/spdlog/include/spdlog/sinks/msvc_sink.h delete mode 100644 tpl/spdlog/include/spdlog/sinks/null_sink.h delete mode 100644 tpl/spdlog/include/spdlog/sinks/ostream_sink.h delete mode 100644 tpl/spdlog/include/spdlog/sinks/qt_sinks.h delete mode 100644 tpl/spdlog/include/spdlog/sinks/ringbuffer_sink.h delete mode 100644 tpl/spdlog/include/spdlog/sinks/rotating_file_sink-inl.h delete mode 100644 tpl/spdlog/include/spdlog/sinks/rotating_file_sink.h delete mode 100644 tpl/spdlog/include/spdlog/sinks/sink-inl.h delete mode 100644 tpl/spdlog/include/spdlog/sinks/sink.h delete mode 100644 tpl/spdlog/include/spdlog/sinks/stdout_color_sinks-inl.h delete mode 100644 tpl/spdlog/include/spdlog/sinks/stdout_color_sinks.h delete mode 100644 tpl/spdlog/include/spdlog/sinks/stdout_sinks-inl.h delete mode 100644 tpl/spdlog/include/spdlog/sinks/stdout_sinks.h delete mode 100644 tpl/spdlog/include/spdlog/sinks/syslog_sink.h delete mode 100644 tpl/spdlog/include/spdlog/sinks/systemd_sink.h delete mode 100644 tpl/spdlog/include/spdlog/sinks/tcp_sink.h delete mode 100644 tpl/spdlog/include/spdlog/sinks/udp_sink.h delete mode 100644 tpl/spdlog/include/spdlog/sinks/win_eventlog_sink.h delete mode 100644 tpl/spdlog/include/spdlog/sinks/wincolor_sink-inl.h delete mode 100644 tpl/spdlog/include/spdlog/sinks/wincolor_sink.h delete mode 100644 tpl/spdlog/include/spdlog/spdlog-inl.h delete mode 100644 tpl/spdlog/include/spdlog/spdlog.h delete mode 100644 tpl/spdlog/include/spdlog/stopwatch.h delete mode 100644 tpl/spdlog/include/spdlog/tweakme.h delete mode 100644 tpl/spdlog/include/spdlog/version.h diff --git a/CMakeLists.txt b/CMakeLists.txt index d497d00..e1f2209 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -109,6 +109,9 @@ endif() set_property(TARGET bvh PROPERTY CXX_STANDARD ${Kokkos_CXX_STANDARD}) target_link_libraries(bvh PUBLIC Kokkos::kokkos) +find_package(spdlog 1.13 REQUIRED) +target_link_libraries(bvh PUBLIC spdlog::spdlog) + option(BVH_ENABLE_TRACING "Enable detailed performance tracing (may have an impact on performance" OFF) if (BVH_ENABLE_TRACING) find_package(perf REQUIRED) diff --git a/src/bvh/collision_world/impl.hpp b/src/bvh/collision_world/impl.hpp index 6a5366f..92d9f52 100644 --- a/src/bvh/collision_world/impl.hpp +++ b/src/bvh/collision_world/impl.hpp @@ -37,7 +37,6 @@ #include #include -#define SPDLOG_HEADER_ONLY #include #include diff --git a/tpl/CMakeLists.txt b/tpl/CMakeLists.txt index 0fdf09c..e69de29 100644 --- a/tpl/CMakeLists.txt +++ b/tpl/CMakeLists.txt @@ -1 +0,0 @@ -add_subdirectory(spdlog) diff --git a/tpl/spdlog/CMakeLists.txt b/tpl/spdlog/CMakeLists.txt deleted file mode 100644 index 8c1926d..0000000 --- a/tpl/spdlog/CMakeLists.txt +++ /dev/null @@ -1,10 +0,0 @@ - -#find_package(fmt 10.0.0 REQUIRED) - -#target_link_libraries(bvh PUBLIC fmt::fmt) - -target_compile_definitions(bvh PUBLIC SPDLOG_FMT_EXTERNAL SPDLOG_ACTIVE_LEVEL=0) - -target_include_directories(bvh PUBLIC - $ - ) diff --git a/tpl/spdlog/include/spdlog/async.h b/tpl/spdlog/include/spdlog/async.h deleted file mode 100644 index 94f9f6d..0000000 --- a/tpl/spdlog/include/spdlog/async.h +++ /dev/null @@ -1,99 +0,0 @@ -// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. -// Distributed under the MIT License (http://opensource.org/licenses/MIT) - -#pragma once - -// -// Async logging using global thread pool -// All loggers created here share same global thread pool. -// Each log message is pushed to a queue along with a shared pointer to the -// logger. -// If a logger deleted while having pending messages in the queue, it's actual -// destruction will defer -// until all its messages are processed by the thread pool. -// This is because each message in the queue holds a shared_ptr to the -// originating logger. - -#include -#include -#include - -#include -#include -#include - -namespace spdlog { - -namespace details { -static const size_t default_async_q_size = 8192; -} - -// async logger factory - creates async loggers backed with thread pool. -// if a global thread pool doesn't already exist, create it with default queue -// size of 8192 items and single thread. -template -struct async_factory_impl -{ - template - static std::shared_ptr create(std::string logger_name, SinkArgs &&...args) - { - auto ®istry_inst = details::registry::instance(); - - // create global thread pool if not already exists.. - - auto &mutex = registry_inst.tp_mutex(); - std::lock_guard tp_lock(mutex); - auto tp = registry_inst.get_tp(); - if (tp == nullptr) - { - tp = std::make_shared(details::default_async_q_size, 1U); - registry_inst.set_tp(tp); - } - - auto sink = std::make_shared(std::forward(args)...); - auto new_logger = std::make_shared(std::move(logger_name), std::move(sink), std::move(tp), OverflowPolicy); - registry_inst.initialize_logger(new_logger); - return new_logger; - } -}; - -using async_factory = async_factory_impl; -using async_factory_nonblock = async_factory_impl; - -template -inline std::shared_ptr create_async(std::string logger_name, SinkArgs &&...sink_args) -{ - return async_factory::create(std::move(logger_name), std::forward(sink_args)...); -} - -template -inline std::shared_ptr create_async_nb(std::string logger_name, SinkArgs &&...sink_args) -{ - return async_factory_nonblock::create(std::move(logger_name), std::forward(sink_args)...); -} - -// set global thread pool. -inline void init_thread_pool( - size_t q_size, size_t thread_count, std::function on_thread_start, std::function on_thread_stop) -{ - auto tp = std::make_shared(q_size, thread_count, on_thread_start, on_thread_stop); - details::registry::instance().set_tp(std::move(tp)); -} - -inline void init_thread_pool(size_t q_size, size_t thread_count, std::function on_thread_start) -{ - init_thread_pool(q_size, thread_count, on_thread_start, [] {}); -} - -inline void init_thread_pool(size_t q_size, size_t thread_count) -{ - init_thread_pool( - q_size, thread_count, [] {}, [] {}); -} - -// get the global thread pool. -inline std::shared_ptr thread_pool() -{ - return details::registry::instance().get_tp(); -} -} // namespace spdlog diff --git a/tpl/spdlog/include/spdlog/async_logger-inl.h b/tpl/spdlog/include/spdlog/async_logger-inl.h deleted file mode 100644 index 4de8382..0000000 --- a/tpl/spdlog/include/spdlog/async_logger-inl.h +++ /dev/null @@ -1,90 +0,0 @@ -// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. -// Distributed under the MIT License (http://opensource.org/licenses/MIT) - -#pragma once - -#ifndef SPDLOG_HEADER_ONLY -# include -#endif - -#include -#include - -#include -#include - -SPDLOG_INLINE spdlog::async_logger::async_logger( - std::string logger_name, sinks_init_list sinks_list, std::weak_ptr tp, async_overflow_policy overflow_policy) - : async_logger(std::move(logger_name), sinks_list.begin(), sinks_list.end(), std::move(tp), overflow_policy) -{} - -SPDLOG_INLINE spdlog::async_logger::async_logger( - std::string logger_name, sink_ptr single_sink, std::weak_ptr tp, async_overflow_policy overflow_policy) - : async_logger(std::move(logger_name), {std::move(single_sink)}, std::move(tp), overflow_policy) -{} - -// send the log message to the thread pool -SPDLOG_INLINE void spdlog::async_logger::sink_it_(const details::log_msg &msg){ - SPDLOG_TRY{if (auto pool_ptr = thread_pool_.lock()){pool_ptr->post_log(shared_from_this(), msg, overflow_policy_); -} -else -{ - throw_spdlog_ex("async log: thread pool doesn't exist anymore"); -} -} -SPDLOG_LOGGER_CATCH(msg.source) -} - -// send flush request to the thread pool -SPDLOG_INLINE void spdlog::async_logger::flush_(){ - SPDLOG_TRY{if (auto pool_ptr = thread_pool_.lock()){pool_ptr->post_flush(shared_from_this(), overflow_policy_); -} -else -{ - throw_spdlog_ex("async flush: thread pool doesn't exist anymore"); -} -} -SPDLOG_LOGGER_CATCH(source_loc()) -} - -// -// backend functions - called from the thread pool to do the actual job -// -SPDLOG_INLINE void spdlog::async_logger::backend_sink_it_(const details::log_msg &msg) -{ - for (auto &sink : sinks_) - { - if (sink->should_log(msg.level)) - { - SPDLOG_TRY - { - sink->log(msg); - } - SPDLOG_LOGGER_CATCH(msg.source) - } - } - - if (should_flush_(msg)) - { - backend_flush_(); - } -} - -SPDLOG_INLINE void spdlog::async_logger::backend_flush_() -{ - for (auto &sink : sinks_) - { - SPDLOG_TRY - { - sink->flush(); - } - SPDLOG_LOGGER_CATCH(source_loc()) - } -} - -SPDLOG_INLINE std::shared_ptr spdlog::async_logger::clone(std::string new_name) -{ - auto cloned = std::make_shared(*this); - cloned->name_ = std::move(new_name); - return cloned; -} diff --git a/tpl/spdlog/include/spdlog/async_logger.h b/tpl/spdlog/include/spdlog/async_logger.h deleted file mode 100644 index 91a93fc..0000000 --- a/tpl/spdlog/include/spdlog/async_logger.h +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. -// Distributed under the MIT License (http://opensource.org/licenses/MIT) - -#pragma once - -// Fast asynchronous logger. -// Uses pre allocated queue. -// Creates a single back thread to pop messages from the queue and log them. -// -// Upon each log write the logger: -// 1. Checks if its log level is enough to log the message -// 2. Push a new copy of the message to a queue (or block the caller until -// space is available in the queue) -// Upon destruction, logs all remaining messages in the queue before -// destructing.. - -#include - -namespace spdlog { - -// Async overflow policy - block by default. -enum class async_overflow_policy -{ - block, // Block until message can be enqueued - overrun_oldest // Discard oldest message in the queue if full when trying to - // add new item. -}; - -namespace details { -class thread_pool; -} - -class SPDLOG_API async_logger final : public std::enable_shared_from_this, public logger -{ - friend class details::thread_pool; - -public: - template - async_logger(std::string logger_name, It begin, It end, std::weak_ptr tp, - async_overflow_policy overflow_policy = async_overflow_policy::block) - : logger(std::move(logger_name), begin, end) - , thread_pool_(std::move(tp)) - , overflow_policy_(overflow_policy) - {} - - async_logger(std::string logger_name, sinks_init_list sinks_list, std::weak_ptr tp, - async_overflow_policy overflow_policy = async_overflow_policy::block); - - async_logger(std::string logger_name, sink_ptr single_sink, std::weak_ptr tp, - async_overflow_policy overflow_policy = async_overflow_policy::block); - - std::shared_ptr clone(std::string new_name) override; - -protected: - void sink_it_(const details::log_msg &msg) override; - void flush_() override; - void backend_sink_it_(const details::log_msg &incoming_log_msg); - void backend_flush_(); - -private: - std::weak_ptr thread_pool_; - async_overflow_policy overflow_policy_; -}; -} // namespace spdlog - -#ifdef SPDLOG_HEADER_ONLY -# include "async_logger-inl.h" -#endif diff --git a/tpl/spdlog/include/spdlog/cfg/argv.h b/tpl/spdlog/include/spdlog/cfg/argv.h deleted file mode 100644 index 36d9f1c..0000000 --- a/tpl/spdlog/include/spdlog/cfg/argv.h +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. -// Distributed under the MIT License (http://opensource.org/licenses/MIT) - -#pragma once -#include -#include - -// -// Init log levels using each argv entry that starts with "SPDLOG_LEVEL=" -// -// set all loggers to debug level: -// example.exe "SPDLOG_LEVEL=debug" - -// set logger1 to trace level -// example.exe "SPDLOG_LEVEL=logger1=trace" - -// turn off all logging except for logger1 and logger2: -// example.exe "SPDLOG_LEVEL=off,logger1=debug,logger2=info" - -namespace spdlog { -namespace cfg { - -// search for SPDLOG_LEVEL= in the args and use it to init the levels -inline void load_argv_levels(int argc, const char **argv) -{ - const std::string spdlog_level_prefix = "SPDLOG_LEVEL="; - for (int i = 1; i < argc; i++) - { - std::string arg = argv[i]; - if (arg.find(spdlog_level_prefix) == 0) - { - auto levels_string = arg.substr(spdlog_level_prefix.size()); - helpers::load_levels(levels_string); - } - } -} - -inline void load_argv_levels(int argc, char **argv) -{ - load_argv_levels(argc, const_cast(argv)); -} - -} // namespace cfg -} // namespace spdlog diff --git a/tpl/spdlog/include/spdlog/cfg/env.h b/tpl/spdlog/include/spdlog/cfg/env.h deleted file mode 100644 index 1f39ebb..0000000 --- a/tpl/spdlog/include/spdlog/cfg/env.h +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. -// Distributed under the MIT License (http://opensource.org/licenses/MIT) - -#pragma once -#include -#include -#include - -// -// Init levels and patterns from env variables SPDLOG_LEVEL -// Inspired from Rust's "env_logger" crate (https://crates.io/crates/env_logger). -// Note - fallback to "info" level on unrecognized levels -// -// Examples: -// -// set global level to debug: -// export SPDLOG_LEVEL=debug -// -// turn off all logging except for logger1: -// export SPDLOG_LEVEL="*=off,logger1=debug" -// - -// turn off all logging except for logger1 and logger2: -// export SPDLOG_LEVEL="off,logger1=debug,logger2=info" - -namespace spdlog { -namespace cfg { -inline void load_env_levels() -{ - auto env_val = details::os::getenv("SPDLOG_LEVEL"); - if (!env_val.empty()) - { - helpers::load_levels(env_val); - } -} - -} // namespace cfg -} // namespace spdlog diff --git a/tpl/spdlog/include/spdlog/cfg/helpers-inl.h b/tpl/spdlog/include/spdlog/cfg/helpers-inl.h deleted file mode 100644 index 675a13a..0000000 --- a/tpl/spdlog/include/spdlog/cfg/helpers-inl.h +++ /dev/null @@ -1,120 +0,0 @@ -// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. -// Distributed under the MIT License (http://opensource.org/licenses/MIT) - -#pragma once - -#ifndef SPDLOG_HEADER_ONLY -# include -#endif - -#include -#include -#include - -#include -#include -#include -#include - -namespace spdlog { -namespace cfg { -namespace helpers { - -// inplace convert to lowercase -inline std::string &to_lower_(std::string &str) -{ - std::transform( - str.begin(), str.end(), str.begin(), [](char ch) { return static_cast((ch >= 'A' && ch <= 'Z') ? ch + ('a' - 'A') : ch); }); - return str; -} - -// inplace trim spaces -inline std::string &trim_(std::string &str) -{ - const char *spaces = " \n\r\t"; - str.erase(str.find_last_not_of(spaces) + 1); - str.erase(0, str.find_first_not_of(spaces)); - return str; -} - -// return (name,value) trimmed pair from given "name=value" string. -// return empty string on missing parts -// "key=val" => ("key", "val") -// " key = val " => ("key", "val") -// "key=" => ("key", "") -// "val" => ("", "val") - -inline std::pair extract_kv_(char sep, const std::string &str) -{ - auto n = str.find(sep); - std::string k, v; - if (n == std::string::npos) - { - v = str; - } - else - { - k = str.substr(0, n); - v = str.substr(n + 1); - } - return std::make_pair(trim_(k), trim_(v)); -} - -// return vector of key/value pairs from sequence of "K1=V1,K2=V2,.." -// "a=AAA,b=BBB,c=CCC,.." => {("a","AAA"),("b","BBB"),("c", "CCC"),...} -inline std::unordered_map extract_key_vals_(const std::string &str) -{ - std::string token; - std::istringstream token_stream(str); - std::unordered_map rv{}; - while (std::getline(token_stream, token, ',')) - { - if (token.empty()) - { - continue; - } - auto kv = extract_kv_('=', token); - rv[kv.first] = kv.second; - } - return rv; -} - -SPDLOG_INLINE void load_levels(const std::string &input) -{ - if (input.empty() || input.size() > 512) - { - return; - } - - auto key_vals = extract_key_vals_(input); - std::unordered_map levels; - level::level_enum global_level = level::info; - bool global_level_found = false; - - for (auto &name_level : key_vals) - { - auto &logger_name = name_level.first; - auto level_name = to_lower_(name_level.second); - auto level = level::from_str(level_name); - // ignore unrecognized level names - if (level == level::off && level_name != "off") - { - continue; - } - if (logger_name.empty()) // no logger name indicate global level - { - global_level_found = true; - global_level = level; - } - else - { - levels[logger_name] = level; - } - } - - details::registry::instance().set_levels(std::move(levels), global_level_found ? &global_level : nullptr); -} - -} // namespace helpers -} // namespace cfg -} // namespace spdlog diff --git a/tpl/spdlog/include/spdlog/cfg/helpers.h b/tpl/spdlog/include/spdlog/cfg/helpers.h deleted file mode 100644 index ab7584e..0000000 --- a/tpl/spdlog/include/spdlog/cfg/helpers.h +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. -// Distributed under the MIT License (http://opensource.org/licenses/MIT) - -#pragma once - -#include -#include - -namespace spdlog { -namespace cfg { -namespace helpers { -// -// Init levels from given string -// -// Examples: -// -// set global level to debug: "debug" -// turn off all logging except for logger1: "off,logger1=debug" -// turn off all logging except for logger1 and logger2: "off,logger1=debug,logger2=info" -// -SPDLOG_API void load_levels(const std::string &txt); -} // namespace helpers - -} // namespace cfg -} // namespace spdlog - -#ifdef SPDLOG_HEADER_ONLY -# include "helpers-inl.h" -#endif // SPDLOG_HEADER_ONLY diff --git a/tpl/spdlog/include/spdlog/common-inl.h b/tpl/spdlog/include/spdlog/common-inl.h deleted file mode 100644 index 728f983..0000000 --- a/tpl/spdlog/include/spdlog/common-inl.h +++ /dev/null @@ -1,82 +0,0 @@ -// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. -// Distributed under the MIT License (http://opensource.org/licenses/MIT) - -#pragma once - -#ifndef SPDLOG_HEADER_ONLY -# include -#endif - -#include -#include - -namespace spdlog { -namespace level { - -#if __cplusplus >= 201703L -constexpr -#endif - static string_view_t level_string_views[] SPDLOG_LEVEL_NAMES; - -static const char *short_level_names[] SPDLOG_SHORT_LEVEL_NAMES; - -SPDLOG_INLINE const string_view_t &to_string_view(spdlog::level::level_enum l) SPDLOG_NOEXCEPT -{ - return level_string_views[l]; -} - -SPDLOG_INLINE const char *to_short_c_str(spdlog::level::level_enum l) SPDLOG_NOEXCEPT -{ - return short_level_names[l]; -} - -SPDLOG_INLINE spdlog::level::level_enum from_str(const std::string &name) SPDLOG_NOEXCEPT -{ - auto it = std::find(std::begin(level_string_views), std::end(level_string_views), name); - if (it != std::end(level_string_views)) - return static_cast(std::distance(std::begin(level_string_views), it)); - - // check also for "warn" and "err" before giving up.. - if (name == "warn") - { - return level::warn; - } - if (name == "err") - { - return level::err; - } - return level::off; -} -} // namespace level - -SPDLOG_INLINE spdlog_ex::spdlog_ex(std::string msg) - : msg_(std::move(msg)) -{} - -SPDLOG_INLINE spdlog_ex::spdlog_ex(const std::string &msg, int last_errno) -{ -#ifdef SPDLOG_USE_STD_FORMAT - msg_ = std::system_error(std::error_code(last_errno, std::generic_category()), msg).what(); -#else - memory_buf_t outbuf; - fmt::format_system_error(outbuf, last_errno, msg.c_str()); - msg_ = fmt::to_string(outbuf); -#endif -} - -SPDLOG_INLINE const char *spdlog_ex::what() const SPDLOG_NOEXCEPT -{ - return msg_.c_str(); -} - -SPDLOG_INLINE void throw_spdlog_ex(const std::string &msg, int last_errno) -{ - SPDLOG_THROW(spdlog_ex(msg, last_errno)); -} - -SPDLOG_INLINE void throw_spdlog_ex(std::string msg) -{ - SPDLOG_THROW(spdlog_ex(std::move(msg))); -} - -} // namespace spdlog diff --git a/tpl/spdlog/include/spdlog/common.h b/tpl/spdlog/include/spdlog/common.h deleted file mode 100644 index 2f1f9fd..0000000 --- a/tpl/spdlog/include/spdlog/common.h +++ /dev/null @@ -1,426 +0,0 @@ -// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. -// Distributed under the MIT License (http://opensource.org/licenses/MIT) - -#pragma once - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef SPDLOG_USE_STD_FORMAT -# include -# if __cpp_lib_format >= 202207L -# include -# else -# include -# endif -#endif - -#ifdef SPDLOG_COMPILED_LIB -# undef SPDLOG_HEADER_ONLY -# if defined(SPDLOG_SHARED_LIB) -# if defined(_WIN32) -# ifdef spdlog_EXPORTS -# define SPDLOG_API __declspec(dllexport) -# else // !spdlog_EXPORTS -# define SPDLOG_API __declspec(dllimport) -# endif -# else // !defined(_WIN32) -# define SPDLOG_API __attribute__((visibility("default"))) -# endif -# else // !defined(SPDLOG_SHARED_LIB) -# define SPDLOG_API -# endif -# define SPDLOG_INLINE -#else // !defined(SPDLOG_COMPILED_LIB) -# define SPDLOG_API -# define SPDLOG_HEADER_ONLY -# define SPDLOG_INLINE inline -#endif // #ifdef SPDLOG_COMPILED_LIB - -#include - -#if !defined(SPDLOG_USE_STD_FORMAT) && FMT_VERSION >= 80000 // backward compatibility with fmt versions older than 8 -# define SPDLOG_FMT_RUNTIME(format_string) fmt::runtime(format_string) -# define SPDLOG_FMT_STRING(format_string) FMT_STRING(format_string) -# if defined(SPDLOG_WCHAR_FILENAMES) || defined(SPDLOG_WCHAR_TO_UTF8_SUPPORT) -# include -# endif -#else -# define SPDLOG_FMT_RUNTIME(format_string) format_string -# define SPDLOG_FMT_STRING(format_string) format_string -#endif - -// visual studio up to 2013 does not support noexcept nor constexpr -#if defined(_MSC_VER) && (_MSC_VER < 1900) -# define SPDLOG_NOEXCEPT _NOEXCEPT -# define SPDLOG_CONSTEXPR -# define SPDLOG_CONSTEXPR_FUNC inline -#else -# define SPDLOG_NOEXCEPT noexcept -# define SPDLOG_CONSTEXPR constexpr -#if __cplusplus >= 201402L && FMT_VERSION >= 80000 -# define SPDLOG_CONSTEXPR_FUNC constexpr -# else -# define SPDLOG_CONSTEXPR_FUNC inline -# endif -#endif - -#if defined(__GNUC__) || defined(__clang__) -# define SPDLOG_DEPRECATED __attribute__((deprecated)) -#elif defined(_MSC_VER) -# define SPDLOG_DEPRECATED __declspec(deprecated) -#else -# define SPDLOG_DEPRECATED -#endif - -// disable thread local on msvc 2013 -#ifndef SPDLOG_NO_TLS -# if (defined(_MSC_VER) && (_MSC_VER < 1900)) || defined(__cplusplus_winrt) -# define SPDLOG_NO_TLS 1 -# endif -#endif - -#ifndef SPDLOG_FUNCTION -# define SPDLOG_FUNCTION static_cast(__FUNCTION__) -#endif - -#ifdef SPDLOG_NO_EXCEPTIONS -# define SPDLOG_TRY -# define SPDLOG_THROW(ex) \ - do \ - { \ - printf("spdlog fatal error: %s\n", ex.what()); \ - std::abort(); \ - } while (0) -# define SPDLOG_CATCH_STD -#else -# define SPDLOG_TRY try -# define SPDLOG_THROW(ex) throw(ex) -# define SPDLOG_CATCH_STD \ - catch (const std::exception &) \ - {} -#endif - -namespace spdlog { - -class formatter; - -namespace sinks { -class sink; -} - -#if defined(_WIN32) && defined(SPDLOG_WCHAR_FILENAMES) -using filename_t = std::wstring; -// allow macro expansion to occur in SPDLOG_FILENAME_T -# define SPDLOG_FILENAME_T_INNER(s) L##s -# define SPDLOG_FILENAME_T(s) SPDLOG_FILENAME_T_INNER(s) -#else -using filename_t = std::string; -# define SPDLOG_FILENAME_T(s) s -#endif - -using log_clock = std::chrono::system_clock; -using sink_ptr = std::shared_ptr; -using sinks_init_list = std::initializer_list; -using err_handler = std::function; -#ifdef SPDLOG_USE_STD_FORMAT -namespace fmt_lib = std; - -using string_view_t = std::string_view; -using memory_buf_t = std::string; - -template -# if __cpp_lib_format >= 202207L -using format_string_t = std::format_string; -# else -using format_string_t = std::string_view; -# endif - -template -struct is_convertible_to_basic_format_string : std::integral_constant>::value> -{}; - -# if defined(SPDLOG_WCHAR_FILENAMES) || defined(SPDLOG_WCHAR_TO_UTF8_SUPPORT) -using wstring_view_t = std::wstring_view; -using wmemory_buf_t = std::wstring; - -template -# if __cpp_lib_format >= 202207L -using wformat_string_t = std::wformat_string; -# else -using wformat_string_t = std::wstring_view; -# endif -# endif -# define SPDLOG_BUF_TO_STRING(x) x -#else // use fmt lib instead of std::format -namespace fmt_lib = fmt; - -using string_view_t = fmt::basic_string_view; -using memory_buf_t = fmt::basic_memory_buffer; - -template< typename... Args > -#if FMT_VERSION >= 90101 -using format_string_t = fmt::format_string< Args... >; -#else -using format_string_t = std::string_view; -#endif - -template -using remove_cvref_t = typename std::remove_cv::type>::type; - -template -# if FMT_VERSION >= 90101 -using fmt_runtime_string = fmt::runtime_format_string; -# elif FMT_VERSION >= 80000 -using fmt_runtime_string = fmt::basic_runtime; -#else -using fmt_runtime_string = std::basic_string_view; -# endif - -// clang doesn't like SFINAE disabled constructor in std::is_convertible<> so have to repeat the condition from basic_format_string here, -// in addition, fmt::basic_runtime is only convertible to basic_format_string but not basic_string_view -template -struct is_convertible_to_basic_format_string - : std::integral_constant>::value || std::is_same, fmt_runtime_string>::value> -{}; - -# if defined(SPDLOG_WCHAR_FILENAMES) || defined(SPDLOG_WCHAR_TO_UTF8_SUPPORT) -using wstring_view_t = fmt::basic_string_view; -using wmemory_buf_t = fmt::basic_memory_buffer; - -template -using wformat_string_t = fmt::wformat_string; -# endif -# define SPDLOG_BUF_TO_STRING(x) fmt::to_string(x) -#endif - -#ifdef SPDLOG_WCHAR_TO_UTF8_SUPPORT -# ifndef _WIN32 -# error SPDLOG_WCHAR_TO_UTF8_SUPPORT only supported on windows -# endif // _WIN32 -#endif // SPDLOG_WCHAR_TO_UTF8_SUPPORT - -template -struct is_convertible_to_any_format_string : std::integral_constant::value || - is_convertible_to_basic_format_string::value> -{}; - -#if defined(SPDLOG_NO_ATOMIC_LEVELS) -using level_t = details::null_atomic_int; -#else -using level_t = std::atomic; -#endif - -#define SPDLOG_LEVEL_TRACE 0 -#define SPDLOG_LEVEL_DEBUG 1 -#define SPDLOG_LEVEL_INFO 2 -#define SPDLOG_LEVEL_WARN 3 -#define SPDLOG_LEVEL_ERROR 4 -#define SPDLOG_LEVEL_CRITICAL 5 -#define SPDLOG_LEVEL_OFF 6 - -#if !defined(SPDLOG_ACTIVE_LEVEL) -# define SPDLOG_ACTIVE_LEVEL SPDLOG_LEVEL_INFO -#endif - -// Log level enum -namespace level { -enum level_enum : int -{ - trace = SPDLOG_LEVEL_TRACE, - debug = SPDLOG_LEVEL_DEBUG, - info = SPDLOG_LEVEL_INFO, - warn = SPDLOG_LEVEL_WARN, - err = SPDLOG_LEVEL_ERROR, - critical = SPDLOG_LEVEL_CRITICAL, - off = SPDLOG_LEVEL_OFF, - n_levels -}; - -#define SPDLOG_LEVEL_NAME_TRACE spdlog::string_view_t("trace", 5) -#define SPDLOG_LEVEL_NAME_DEBUG spdlog::string_view_t("debug", 5) -#define SPDLOG_LEVEL_NAME_INFO spdlog::string_view_t("info", 4) -#define SPDLOG_LEVEL_NAME_WARNING spdlog::string_view_t("warning", 7) -#define SPDLOG_LEVEL_NAME_ERROR spdlog::string_view_t("error", 5) -#define SPDLOG_LEVEL_NAME_CRITICAL spdlog::string_view_t("critical", 8) -#define SPDLOG_LEVEL_NAME_OFF spdlog::string_view_t("off", 3) - -#if !defined(SPDLOG_LEVEL_NAMES) -# define SPDLOG_LEVEL_NAMES \ - { \ - SPDLOG_LEVEL_NAME_TRACE, SPDLOG_LEVEL_NAME_DEBUG, SPDLOG_LEVEL_NAME_INFO, SPDLOG_LEVEL_NAME_WARNING, SPDLOG_LEVEL_NAME_ERROR, \ - SPDLOG_LEVEL_NAME_CRITICAL, SPDLOG_LEVEL_NAME_OFF \ - } -#endif - -#if !defined(SPDLOG_SHORT_LEVEL_NAMES) - -# define SPDLOG_SHORT_LEVEL_NAMES \ - { \ - "T", "D", "I", "W", "E", "C", "O" \ - } -#endif - -SPDLOG_API const string_view_t &to_string_view(spdlog::level::level_enum l) SPDLOG_NOEXCEPT; -SPDLOG_API const char *to_short_c_str(spdlog::level::level_enum l) SPDLOG_NOEXCEPT; -SPDLOG_API spdlog::level::level_enum from_str(const std::string &name) SPDLOG_NOEXCEPT; - -} // namespace level - -// -// Color mode used by sinks with color support. -// -enum class color_mode -{ - always, - automatic, - never -}; - -// -// Pattern time - specific time getting to use for pattern_formatter. -// local time by default -// -enum class pattern_time_type -{ - local, // log localtime - utc // log utc -}; - -// -// Log exception -// -class SPDLOG_API spdlog_ex : public std::exception -{ -public: - explicit spdlog_ex(std::string msg); - spdlog_ex(const std::string &msg, int last_errno); - const char *what() const SPDLOG_NOEXCEPT override; - -private: - std::string msg_; -}; - -[[noreturn]] SPDLOG_API void throw_spdlog_ex(const std::string &msg, int last_errno); -[[noreturn]] SPDLOG_API void throw_spdlog_ex(std::string msg); - -struct source_loc -{ - SPDLOG_CONSTEXPR source_loc() = default; - SPDLOG_CONSTEXPR source_loc(const char *filename_in, int line_in, const char *funcname_in) - : filename{filename_in} - , line{line_in} - , funcname{funcname_in} - {} - - SPDLOG_CONSTEXPR bool empty() const SPDLOG_NOEXCEPT - { - return line == 0; - } - const char *filename{nullptr}; - int line{0}; - const char *funcname{nullptr}; -}; - -struct file_event_handlers -{ - file_event_handlers() - : before_open(nullptr) - , after_open(nullptr) - , before_close(nullptr) - , after_close(nullptr) - {} - - std::function before_open; - std::function after_open; - std::function before_close; - std::function after_close; -}; - -namespace details { - -// to_string_view - -SPDLOG_CONSTEXPR_FUNC spdlog::string_view_t to_string_view(const memory_buf_t &buf) SPDLOG_NOEXCEPT -{ - return spdlog::string_view_t{buf.data(), buf.size()}; -} - -SPDLOG_CONSTEXPR_FUNC spdlog::string_view_t to_string_view(spdlog::string_view_t str) SPDLOG_NOEXCEPT -{ - return str; -} - -#if defined(SPDLOG_WCHAR_FILENAMES) || defined(SPDLOG_WCHAR_TO_UTF8_SUPPORT) -SPDLOG_CONSTEXPR_FUNC spdlog::wstring_view_t to_string_view(const wmemory_buf_t &buf) SPDLOG_NOEXCEPT -{ - return spdlog::wstring_view_t{buf.data(), buf.size()}; -} - -SPDLOG_CONSTEXPR_FUNC spdlog::wstring_view_t to_string_view(spdlog::wstring_view_t str) SPDLOG_NOEXCEPT -{ - return str; -} -#endif - -#if !defined( SPDLOG_USE_STD_FORMAT ) && FMT_VERSION >= 80000 -template -inline fmt::basic_string_view to_string_view(fmt::basic_format_string fmt) -{ - return fmt; -} -#elif __cpp_lib_format >= 202207L -template -SPDLOG_CONSTEXPR_FUNC std::basic_string_view to_string_view(std::basic_format_string fmt) SPDLOG_NOEXCEPT -{ - return fmt.get(); -} -#endif - -// make_unique support for pre c++14 - -#if __cplusplus >= 201402L // C++14 and beyond -using std::enable_if_t; -using std::make_unique; -#else -template -using enable_if_t = typename std::enable_if::type; - -template -std::unique_ptr make_unique(Args &&...args) -{ - static_assert(!std::is_array::value, "arrays not supported"); - return std::unique_ptr(new T(std::forward(args)...)); -} -#endif - -// to avoid useless casts (see https://github.com/nlohmann/json/issues/2893#issuecomment-889152324) -template::value, int> = 0> -constexpr T conditional_static_cast(U value) -{ - return static_cast(value); -} - -template::value, int> = 0> -constexpr T conditional_static_cast(U value) -{ - return value; -} - -} // namespace details -} // namespace spdlog - -#ifdef SPDLOG_HEADER_ONLY -# include "common-inl.h" -#endif diff --git a/tpl/spdlog/include/spdlog/details/backtracer-inl.h b/tpl/spdlog/include/spdlog/details/backtracer-inl.h deleted file mode 100644 index 40eba40..0000000 --- a/tpl/spdlog/include/spdlog/details/backtracer-inl.h +++ /dev/null @@ -1,75 +0,0 @@ -// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. -// Distributed under the MIT License (http://opensource.org/licenses/MIT) - -#pragma once - -#ifndef SPDLOG_HEADER_ONLY -# include -#endif -namespace spdlog { -namespace details { -SPDLOG_INLINE backtracer::backtracer(const backtracer &other) -{ - std::lock_guard lock(other.mutex_); - enabled_ = other.enabled(); - messages_ = other.messages_; -} - -SPDLOG_INLINE backtracer::backtracer(backtracer &&other) SPDLOG_NOEXCEPT -{ - std::lock_guard lock(other.mutex_); - enabled_ = other.enabled(); - messages_ = std::move(other.messages_); -} - -SPDLOG_INLINE backtracer &backtracer::operator=(backtracer other) -{ - std::lock_guard lock(mutex_); - enabled_ = other.enabled(); - messages_ = std::move(other.messages_); - return *this; -} - -SPDLOG_INLINE void backtracer::enable(size_t size) -{ - std::lock_guard lock{mutex_}; - enabled_.store(true, std::memory_order_relaxed); - messages_ = circular_q{size}; -} - -SPDLOG_INLINE void backtracer::disable() -{ - std::lock_guard lock{mutex_}; - enabled_.store(false, std::memory_order_relaxed); -} - -SPDLOG_INLINE bool backtracer::enabled() const -{ - return enabled_.load(std::memory_order_relaxed); -} - -SPDLOG_INLINE void backtracer::push_back(const log_msg &msg) -{ - std::lock_guard lock{mutex_}; - messages_.push_back(log_msg_buffer{msg}); -} - -SPDLOG_INLINE bool backtracer::empty() const -{ - std::lock_guard lock{mutex_}; - return messages_.empty(); -} - -// pop all items in the q and apply the given fun on each of them. -SPDLOG_INLINE void backtracer::foreach_pop(std::function fun) -{ - std::lock_guard lock{mutex_}; - while (!messages_.empty()) - { - auto &front_msg = messages_.front(); - fun(front_msg); - messages_.pop_front(); - } -} -} // namespace details -} // namespace spdlog diff --git a/tpl/spdlog/include/spdlog/details/backtracer.h b/tpl/spdlog/include/spdlog/details/backtracer.h deleted file mode 100644 index 13785d8..0000000 --- a/tpl/spdlog/include/spdlog/details/backtracer.h +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. -// Distributed under the MIT License (http://opensource.org/licenses/MIT) - -#pragma once - -#include -#include - -#include -#include -#include - -// Store log messages in circular buffer. -// Useful for storing debug data in case of error/warning happens. - -namespace spdlog { -namespace details { -class SPDLOG_API backtracer -{ - mutable std::mutex mutex_; - std::atomic enabled_{false}; - circular_q messages_; - -public: - backtracer() = default; - backtracer(const backtracer &other); - - backtracer(backtracer &&other) SPDLOG_NOEXCEPT; - backtracer &operator=(backtracer other); - - void enable(size_t size); - void disable(); - bool enabled() const; - void push_back(const log_msg &msg); - bool empty() const; - - // pop all items in the q and apply the given fun on each of them. - void foreach_pop(std::function fun); -}; - -} // namespace details -} // namespace spdlog - -#ifdef SPDLOG_HEADER_ONLY -# include "backtracer-inl.h" -#endif diff --git a/tpl/spdlog/include/spdlog/details/circular_q.h b/tpl/spdlog/include/spdlog/details/circular_q.h deleted file mode 100644 index e4fd5fd..0000000 --- a/tpl/spdlog/include/spdlog/details/circular_q.h +++ /dev/null @@ -1,146 +0,0 @@ -// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. -// Distributed under the MIT License (http://opensource.org/licenses/MIT) - -// circular q view of std::vector. -#pragma once - -#include -#include - -namespace spdlog { -namespace details { -template -class circular_q -{ - size_t max_items_ = 0; - typename std::vector::size_type head_ = 0; - typename std::vector::size_type tail_ = 0; - size_t overrun_counter_ = 0; - std::vector v_; - -public: - using value_type = T; - - // empty ctor - create a disabled queue with no elements allocated at all - circular_q() = default; - - explicit circular_q(size_t max_items) - : max_items_(max_items + 1) // one item is reserved as marker for full q - , v_(max_items_) - {} - - circular_q(const circular_q &) = default; - circular_q &operator=(const circular_q &) = default; - - // move cannot be default, - // since we need to reset head_, tail_, etc to zero in the moved object - circular_q(circular_q &&other) SPDLOG_NOEXCEPT - { - copy_moveable(std::move(other)); - } - - circular_q &operator=(circular_q &&other) SPDLOG_NOEXCEPT - { - copy_moveable(std::move(other)); - return *this; - } - - // push back, overrun (oldest) item if no room left - void push_back(T &&item) - { - if (max_items_ > 0) - { - v_[tail_] = std::move(item); - tail_ = (tail_ + 1) % max_items_; - - if (tail_ == head_) // overrun last item if full - { - head_ = (head_ + 1) % max_items_; - ++overrun_counter_; - } - } - } - - // Return reference to the front item. - // If there are no elements in the container, the behavior is undefined. - const T &front() const - { - return v_[head_]; - } - - T &front() - { - return v_[head_]; - } - - // Return number of elements actually stored - size_t size() const - { - if (tail_ >= head_) - { - return tail_ - head_; - } - else - { - return max_items_ - (head_ - tail_); - } - } - - // Return const reference to item by index. - // If index is out of range 0…size()-1, the behavior is undefined. - const T &at(size_t i) const - { - assert(i < size()); - return v_[(head_ + i) % max_items_]; - } - - // Pop item from front. - // If there are no elements in the container, the behavior is undefined. - void pop_front() - { - head_ = (head_ + 1) % max_items_; - } - - bool empty() const - { - return tail_ == head_; - } - - bool full() const - { - // head is ahead of the tail by 1 - if (max_items_ > 0) - { - return ((tail_ + 1) % max_items_) == head_; - } - return false; - } - - size_t overrun_counter() const - { - return overrun_counter_; - } - - void reset_overrun_counter() - { - overrun_counter_ = 0; - } - -private: - // copy from other&& and reset it to disabled state - void copy_moveable(circular_q &&other) SPDLOG_NOEXCEPT - { - max_items_ = other.max_items_; - head_ = other.head_; - tail_ = other.tail_; - overrun_counter_ = other.overrun_counter_; - v_ = std::move(other.v_); - - // put &&other in disabled, but valid state - other.max_items_ = 0; - other.head_ = other.tail_ = 0; - other.overrun_counter_ = 0; - } -}; -} // namespace details -} // namespace spdlog diff --git a/tpl/spdlog/include/spdlog/details/console_globals.h b/tpl/spdlog/include/spdlog/details/console_globals.h deleted file mode 100644 index 665201d..0000000 --- a/tpl/spdlog/include/spdlog/details/console_globals.h +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. -// Distributed under the MIT License (http://opensource.org/licenses/MIT) - -#pragma once - -#include -#include - -namespace spdlog { -namespace details { - -struct console_mutex -{ - using mutex_t = std::mutex; - static mutex_t &mutex() - { - static mutex_t s_mutex; - return s_mutex; - } -}; - -struct console_nullmutex -{ - using mutex_t = null_mutex; - static mutex_t &mutex() - { - static mutex_t s_mutex; - return s_mutex; - } -}; -} // namespace details -} // namespace spdlog diff --git a/tpl/spdlog/include/spdlog/details/file_helper-inl.h b/tpl/spdlog/include/spdlog/details/file_helper-inl.h deleted file mode 100644 index 74c89a8..0000000 --- a/tpl/spdlog/include/spdlog/details/file_helper-inl.h +++ /dev/null @@ -1,180 +0,0 @@ -// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. -// Distributed under the MIT License (http://opensource.org/licenses/MIT) - -#pragma once - -#ifndef SPDLOG_HEADER_ONLY -# include -#endif - -#include -#include - -#include -#include -#include -#include -#include -#include - -namespace spdlog { -namespace details { - -SPDLOG_INLINE file_helper::file_helper(const file_event_handlers &event_handlers) - : event_handlers_(event_handlers) -{} - -SPDLOG_INLINE file_helper::~file_helper() -{ - close(); -} - -SPDLOG_INLINE void file_helper::open(const filename_t &fname, bool truncate) -{ - close(); - filename_ = fname; - - auto *mode = SPDLOG_FILENAME_T("ab"); - auto *trunc_mode = SPDLOG_FILENAME_T("wb"); - - if (event_handlers_.before_open) - { - event_handlers_.before_open(filename_); - } - for (int tries = 0; tries < open_tries_; ++tries) - { - // create containing folder if not exists already. - os::create_dir(os::dir_name(fname)); - if (truncate) - { - // Truncate by opening-and-closing a tmp file in "wb" mode, always - // opening the actual log-we-write-to in "ab" mode, since that - // interacts more politely with eternal processes that might - // rotate/truncate the file underneath us. - std::FILE *tmp; - if (os::fopen_s(&tmp, fname, trunc_mode)) - { - continue; - } - std::fclose(tmp); - } - if (!os::fopen_s(&fd_, fname, mode)) - { - if (event_handlers_.after_open) - { - event_handlers_.after_open(filename_, fd_); - } - return; - } - - details::os::sleep_for_millis(open_interval_); - } - - throw_spdlog_ex("Failed opening file " + os::filename_to_str(filename_) + " for writing", errno); -} - -SPDLOG_INLINE void file_helper::reopen(bool truncate) -{ - if (filename_.empty()) - { - throw_spdlog_ex("Failed re opening file - was not opened before"); - } - this->open(filename_, truncate); -} - -SPDLOG_INLINE void file_helper::flush() -{ - if (std::fflush(fd_) != 0) - { - throw_spdlog_ex("Failed flush to file " + os::filename_to_str(filename_), errno); - } -} - -SPDLOG_INLINE void file_helper::sync() -{ - if (!os::fsync(fd_)) - { - throw_spdlog_ex("Failed to fsync file " + os::filename_to_str(filename_), errno); - } -} - -SPDLOG_INLINE void file_helper::close() -{ - if (fd_ != nullptr) - { - if (event_handlers_.before_close) - { - event_handlers_.before_close(filename_, fd_); - } - - std::fclose(fd_); - fd_ = nullptr; - - if (event_handlers_.after_close) - { - event_handlers_.after_close(filename_); - } - } -} - -SPDLOG_INLINE void file_helper::write(const memory_buf_t &buf) -{ - size_t msg_size = buf.size(); - auto data = buf.data(); - if (std::fwrite(data, 1, msg_size, fd_) != msg_size) - { - throw_spdlog_ex("Failed writing to file " + os::filename_to_str(filename_), errno); - } -} - -SPDLOG_INLINE size_t file_helper::size() const -{ - if (fd_ == nullptr) - { - throw_spdlog_ex("Cannot use size() on closed file " + os::filename_to_str(filename_)); - } - return os::filesize(fd_); -} - -SPDLOG_INLINE const filename_t &file_helper::filename() const -{ - return filename_; -} - -// -// return file path and its extension: -// -// "mylog.txt" => ("mylog", ".txt") -// "mylog" => ("mylog", "") -// "mylog." => ("mylog.", "") -// "/dir1/dir2/mylog.txt" => ("/dir1/dir2/mylog", ".txt") -// -// the starting dot in filenames is ignored (hidden files): -// -// ".mylog" => (".mylog". "") -// "my_folder/.mylog" => ("my_folder/.mylog", "") -// "my_folder/.mylog.txt" => ("my_folder/.mylog", ".txt") -SPDLOG_INLINE std::tuple file_helper::split_by_extension(const filename_t &fname) -{ - auto ext_index = fname.rfind('.'); - - // no valid extension found - return whole path and empty string as - // extension - if (ext_index == filename_t::npos || ext_index == 0 || ext_index == fname.size() - 1) - { - return std::make_tuple(fname, filename_t()); - } - - // treat cases like "/etc/rc.d/somelogfile or "/abc/.hiddenfile" - auto folder_index = fname.find_last_of(details::os::folder_seps_filename); - if (folder_index != filename_t::npos && folder_index >= ext_index - 1) - { - return std::make_tuple(fname, filename_t()); - } - - // finally - return a valid base and extension tuple - return std::make_tuple(fname.substr(0, ext_index), fname.substr(ext_index)); -} - -} // namespace details -} // namespace spdlog diff --git a/tpl/spdlog/include/spdlog/details/file_helper.h b/tpl/spdlog/include/spdlog/details/file_helper.h deleted file mode 100644 index f42a5eb..0000000 --- a/tpl/spdlog/include/spdlog/details/file_helper.h +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. -// Distributed under the MIT License (http://opensource.org/licenses/MIT) - -#pragma once - -#include -#include - -namespace spdlog { -namespace details { - -// Helper class for file sinks. -// When failing to open a file, retry several times(5) with a delay interval(10 ms). -// Throw spdlog_ex exception on errors. - -class SPDLOG_API file_helper -{ -public: - file_helper() = default; - explicit file_helper(const file_event_handlers &event_handlers); - - file_helper(const file_helper &) = delete; - file_helper &operator=(const file_helper &) = delete; - ~file_helper(); - - void open(const filename_t &fname, bool truncate = false); - void reopen(bool truncate); - void flush(); - void sync(); - void close(); - void write(const memory_buf_t &buf); - size_t size() const; - const filename_t &filename() const; - - // - // return file path and its extension: - // - // "mylog.txt" => ("mylog", ".txt") - // "mylog" => ("mylog", "") - // "mylog." => ("mylog.", "") - // "/dir1/dir2/mylog.txt" => ("/dir1/dir2/mylog", ".txt") - // - // the starting dot in filenames is ignored (hidden files): - // - // ".mylog" => (".mylog". "") - // "my_folder/.mylog" => ("my_folder/.mylog", "") - // "my_folder/.mylog.txt" => ("my_folder/.mylog", ".txt") - static std::tuple split_by_extension(const filename_t &fname); - -private: - const int open_tries_ = 5; - const unsigned int open_interval_ = 10; - std::FILE *fd_{nullptr}; - filename_t filename_; - file_event_handlers event_handlers_; -}; -} // namespace details -} // namespace spdlog - -#ifdef SPDLOG_HEADER_ONLY -# include "file_helper-inl.h" -#endif diff --git a/tpl/spdlog/include/spdlog/details/fmt_helper.h b/tpl/spdlog/include/spdlog/details/fmt_helper.h deleted file mode 100644 index d986718..0000000 --- a/tpl/spdlog/include/spdlog/details/fmt_helper.h +++ /dev/null @@ -1,164 +0,0 @@ -// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. -// Distributed under the MIT License (http://opensource.org/licenses/MIT) -#pragma once - -#include -#include -#include -#include -#include - -#ifdef SPDLOG_USE_STD_FORMAT -# include -# include -#endif - -// Some fmt helpers to efficiently format and pad ints and strings -namespace spdlog { -namespace details { -namespace fmt_helper { - -inline void append_string_view(spdlog::string_view_t view, memory_buf_t &dest) -{ - auto *buf_ptr = view.data(); - dest.append(buf_ptr, buf_ptr + view.size()); -} - -#ifdef SPDLOG_USE_STD_FORMAT -template -inline void append_int(T n, memory_buf_t &dest) -{ - // Buffer should be large enough to hold all digits (digits10 + 1) and a sign - SPDLOG_CONSTEXPR const auto BUF_SIZE = std::numeric_limits::digits10 + 2; - char buf[BUF_SIZE]; - - auto [ptr, ec] = std::to_chars(buf, buf + BUF_SIZE, n, 10); - if (ec == std::errc()) - { - dest.append(buf, ptr); - } - else - { - throw_spdlog_ex("Failed to format int", static_cast(ec)); - } -} -#else -template -inline void append_int(T n, memory_buf_t &dest) -{ - fmt::format_int i(n); - dest.append(i.data(), i.data() + i.size()); -} -#endif - -template -SPDLOG_CONSTEXPR_FUNC unsigned int count_digits_fallback(T n) -{ - // taken from fmt: https://github.com/fmtlib/fmt/blob/8.0.1/include/fmt/format.h#L899-L912 - unsigned int count = 1; - for (;;) - { - // Integer division is slow so do it for a group of four digits instead - // of for every digit. The idea comes from the talk by Alexandrescu - // "Three Optimization Tips for C++". See speed-test for a comparison. - if (n < 10) - return count; - if (n < 100) - return count + 1; - if (n < 1000) - return count + 2; - if (n < 10000) - return count + 3; - n /= 10000u; - count += 4; - } -} - -template -inline unsigned int count_digits(T n) -{ - using count_type = typename std::conditional<(sizeof(T) > sizeof(uint32_t)), uint64_t, uint32_t>::type; -#ifdef SPDLOG_USE_STD_FORMAT - return count_digits_fallback(static_cast(n)); -#else - return static_cast(fmt:: -// fmt 7.0.0 renamed the internal namespace to detail. -// See: https://github.com/fmtlib/fmt/issues/1538 -# if FMT_VERSION < 70000 - internal -# else - detail -# endif - ::count_digits(static_cast(n))); -#endif -} - -inline void pad2(int n, memory_buf_t &dest) -{ - if (n >= 0 && n < 100) // 0-99 - { - dest.push_back(static_cast('0' + n / 10)); - dest.push_back(static_cast('0' + n % 10)); - } - else // unlikely, but just in case, let fmt deal with it - { - fmt_lib::format_to(std::back_inserter(dest), SPDLOG_FMT_STRING("{:02}"), n); - } -} - -template -inline void pad_uint(T n, unsigned int width, memory_buf_t &dest) -{ - static_assert(std::is_unsigned::value, "pad_uint must get unsigned T"); - for (auto digits = count_digits(n); digits < width; digits++) - { - dest.push_back('0'); - } - append_int(n, dest); -} - -template -inline void pad3(T n, memory_buf_t &dest) -{ - static_assert(std::is_unsigned::value, "pad3 must get unsigned T"); - if (n < 1000) - { - dest.push_back(static_cast(n / 100 + '0')); - n = n % 100; - dest.push_back(static_cast((n / 10) + '0')); - dest.push_back(static_cast((n % 10) + '0')); - } - else - { - append_int(n, dest); - } -} - -template -inline void pad6(T n, memory_buf_t &dest) -{ - pad_uint(n, 6, dest); -} - -template -inline void pad9(T n, memory_buf_t &dest) -{ - pad_uint(n, 9, dest); -} - -// return fraction of a second of the given time_point. -// e.g. -// fraction(tp) -> will return the millis part of the second -template -inline ToDuration time_fraction(log_clock::time_point tp) -{ - using std::chrono::duration_cast; - using std::chrono::seconds; - auto duration = tp.time_since_epoch(); - auto secs = duration_cast(duration); - return duration_cast(duration) - duration_cast(secs); -} - -} // namespace fmt_helper -} // namespace details -} // namespace spdlog diff --git a/tpl/spdlog/include/spdlog/details/log_msg-inl.h b/tpl/spdlog/include/spdlog/details/log_msg-inl.h deleted file mode 100644 index c6e8a7e..0000000 --- a/tpl/spdlog/include/spdlog/details/log_msg-inl.h +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. -// Distributed under the MIT License (http://opensource.org/licenses/MIT) - -#pragma once - -#ifndef SPDLOG_HEADER_ONLY -# include -#endif - -#include - -namespace spdlog { -namespace details { - -SPDLOG_INLINE log_msg::log_msg(spdlog::log_clock::time_point log_time, spdlog::source_loc loc, string_view_t a_logger_name, - spdlog::level::level_enum lvl, spdlog::string_view_t msg) - : logger_name(a_logger_name) - , level(lvl) - , time(log_time) -#ifndef SPDLOG_NO_THREAD_ID - , thread_id(os::thread_id()) -#endif - , source(loc) - , payload(msg) -{} - -SPDLOG_INLINE log_msg::log_msg( - spdlog::source_loc loc, string_view_t a_logger_name, spdlog::level::level_enum lvl, spdlog::string_view_t msg) - : log_msg(os::now(), loc, a_logger_name, lvl, msg) -{} - -SPDLOG_INLINE log_msg::log_msg(string_view_t a_logger_name, spdlog::level::level_enum lvl, spdlog::string_view_t msg) - : log_msg(os::now(), source_loc{}, a_logger_name, lvl, msg) -{} - -} // namespace details -} // namespace spdlog diff --git a/tpl/spdlog/include/spdlog/details/log_msg.h b/tpl/spdlog/include/spdlog/details/log_msg.h deleted file mode 100644 index fed51ab..0000000 --- a/tpl/spdlog/include/spdlog/details/log_msg.h +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. -// Distributed under the MIT License (http://opensource.org/licenses/MIT) - -#pragma once - -#include -#include - -namespace spdlog { -namespace details { -struct SPDLOG_API log_msg -{ - log_msg() = default; - log_msg(log_clock::time_point log_time, source_loc loc, string_view_t logger_name, level::level_enum lvl, string_view_t msg); - log_msg(source_loc loc, string_view_t logger_name, level::level_enum lvl, string_view_t msg); - log_msg(string_view_t logger_name, level::level_enum lvl, string_view_t msg); - log_msg(const log_msg &other) = default; - log_msg &operator=(const log_msg &other) = default; - - string_view_t logger_name; - level::level_enum level{level::off}; - log_clock::time_point time; - size_t thread_id{0}; - - // wrapping the formatted text with color (updated by pattern_formatter). - mutable size_t color_range_start{0}; - mutable size_t color_range_end{0}; - - source_loc source; - string_view_t payload; -}; -} // namespace details -} // namespace spdlog - -#ifdef SPDLOG_HEADER_ONLY -# include "log_msg-inl.h" -#endif diff --git a/tpl/spdlog/include/spdlog/details/log_msg_buffer-inl.h b/tpl/spdlog/include/spdlog/details/log_msg_buffer-inl.h deleted file mode 100644 index 84d83dc..0000000 --- a/tpl/spdlog/include/spdlog/details/log_msg_buffer-inl.h +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. -// Distributed under the MIT License (http://opensource.org/licenses/MIT) - -#pragma once - -#ifndef SPDLOG_HEADER_ONLY -# include -#endif - -namespace spdlog { -namespace details { - -SPDLOG_INLINE log_msg_buffer::log_msg_buffer(const log_msg &orig_msg) - : log_msg{orig_msg} -{ - buffer.append(logger_name.begin(), logger_name.end()); - buffer.append(payload.begin(), payload.end()); - update_string_views(); -} - -SPDLOG_INLINE log_msg_buffer::log_msg_buffer(const log_msg_buffer &other) - : log_msg{other} -{ - buffer.append(logger_name.begin(), logger_name.end()); - buffer.append(payload.begin(), payload.end()); - update_string_views(); -} - -SPDLOG_INLINE log_msg_buffer::log_msg_buffer(log_msg_buffer &&other) SPDLOG_NOEXCEPT : log_msg{other}, buffer{std::move(other.buffer)} -{ - update_string_views(); -} - -SPDLOG_INLINE log_msg_buffer &log_msg_buffer::operator=(const log_msg_buffer &other) -{ - log_msg::operator=(other); - buffer.clear(); - buffer.append(other.buffer.data(), other.buffer.data() + other.buffer.size()); - update_string_views(); - return *this; -} - -SPDLOG_INLINE log_msg_buffer &log_msg_buffer::operator=(log_msg_buffer &&other) SPDLOG_NOEXCEPT -{ - log_msg::operator=(other); - buffer = std::move(other.buffer); - update_string_views(); - return *this; -} - -SPDLOG_INLINE void log_msg_buffer::update_string_views() -{ - logger_name = string_view_t{buffer.data(), logger_name.size()}; - payload = string_view_t{buffer.data() + logger_name.size(), payload.size()}; -} - -} // namespace details -} // namespace spdlog diff --git a/tpl/spdlog/include/spdlog/details/log_msg_buffer.h b/tpl/spdlog/include/spdlog/details/log_msg_buffer.h deleted file mode 100644 index 8105506..0000000 --- a/tpl/spdlog/include/spdlog/details/log_msg_buffer.h +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. -// Distributed under the MIT License (http://opensource.org/licenses/MIT) - -#pragma once - -#include - -namespace spdlog { -namespace details { - -// Extend log_msg with internal buffer to store its payload. -// This is needed since log_msg holds string_views that points to stack data. - -class SPDLOG_API log_msg_buffer : public log_msg -{ - memory_buf_t buffer; - void update_string_views(); - -public: - log_msg_buffer() = default; - explicit log_msg_buffer(const log_msg &orig_msg); - log_msg_buffer(const log_msg_buffer &other); - log_msg_buffer(log_msg_buffer &&other) SPDLOG_NOEXCEPT; - log_msg_buffer &operator=(const log_msg_buffer &other); - log_msg_buffer &operator=(log_msg_buffer &&other) SPDLOG_NOEXCEPT; -}; - -} // namespace details -} // namespace spdlog - -#ifdef SPDLOG_HEADER_ONLY -# include "log_msg_buffer-inl.h" -#endif diff --git a/tpl/spdlog/include/spdlog/details/mpmc_blocking_q.h b/tpl/spdlog/include/spdlog/details/mpmc_blocking_q.h deleted file mode 100644 index 101ea8c..0000000 --- a/tpl/spdlog/include/spdlog/details/mpmc_blocking_q.h +++ /dev/null @@ -1,154 +0,0 @@ -// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. -// Distributed under the MIT License (http://opensource.org/licenses/MIT) - -#pragma once - -// multi producer-multi consumer blocking queue. -// enqueue(..) - will block until room found to put the new message. -// enqueue_nowait(..) - will return immediately with false if no room left in -// the queue. -// dequeue_for(..) - will block until the queue is not empty or timeout have -// passed. - -#include - -#include -#include - -namespace spdlog { -namespace details { - -template -class mpmc_blocking_queue -{ -public: - using item_type = T; - explicit mpmc_blocking_queue(size_t max_items) - : q_(max_items) - {} - -#ifndef __MINGW32__ - // try to enqueue and block if no room left - void enqueue(T &&item) - { - { - std::unique_lock lock(queue_mutex_); - pop_cv_.wait(lock, [this] { return !this->q_.full(); }); - q_.push_back(std::move(item)); - } - push_cv_.notify_one(); - } - - // enqueue immediately. overrun oldest message in the queue if no room left. - void enqueue_nowait(T &&item) - { - { - std::unique_lock lock(queue_mutex_); - q_.push_back(std::move(item)); - } - push_cv_.notify_one(); - } - - // dequeue with a timeout. - // Return true, if succeeded dequeue item, false otherwise - bool dequeue_for(T &popped_item, std::chrono::milliseconds wait_duration) - { - { - std::unique_lock lock(queue_mutex_); - if (!push_cv_.wait_for(lock, wait_duration, [this] { return !this->q_.empty(); })) - { - return false; - } - popped_item = std::move(q_.front()); - q_.pop_front(); - } - pop_cv_.notify_one(); - return true; - } - - // blocking dequeue without a timeout. - void dequeue(T &popped_item) - { - { - std::unique_lock lock(queue_mutex_); - push_cv_.wait(lock, [this] { return !this->q_.empty(); }); - popped_item = std::move(q_.front()); - q_.pop_front(); - } - pop_cv_.notify_one(); - } - -#else - // apparently mingw deadlocks if the mutex is released before cv.notify_one(), - // so release the mutex at the very end each function. - - // try to enqueue and block if no room left - void enqueue(T &&item) - { - std::unique_lock lock(queue_mutex_); - pop_cv_.wait(lock, [this] { return !this->q_.full(); }); - q_.push_back(std::move(item)); - push_cv_.notify_one(); - } - - // enqueue immediately. overrun oldest message in the queue if no room left. - void enqueue_nowait(T &&item) - { - std::unique_lock lock(queue_mutex_); - q_.push_back(std::move(item)); - push_cv_.notify_one(); - } - - // dequeue with a timeout. - // Return true, if succeeded dequeue item, false otherwise - bool dequeue_for(T &popped_item, std::chrono::milliseconds wait_duration) - { - std::unique_lock lock(queue_mutex_); - if (!push_cv_.wait_for(lock, wait_duration, [this] { return !this->q_.empty(); })) - { - return false; - } - popped_item = std::move(q_.front()); - q_.pop_front(); - pop_cv_.notify_one(); - return true; - } - - // blocking dequeue without a timeout. - void dequeue(T &popped_item) - { - std::unique_lock lock(queue_mutex_); - push_cv_.wait(lock, [this] { return !this->q_.empty(); }); - popped_item = std::move(q_.front()); - q_.pop_front(); - pop_cv_.notify_one(); - } - -#endif - - size_t overrun_counter() - { - std::unique_lock lock(queue_mutex_); - return q_.overrun_counter(); - } - - size_t size() - { - std::unique_lock lock(queue_mutex_); - return q_.size(); - } - - void reset_overrun_counter() - { - std::unique_lock lock(queue_mutex_); - q_.reset_overrun_counter(); - } - -private: - std::mutex queue_mutex_; - std::condition_variable push_cv_; - std::condition_variable pop_cv_; - spdlog::details::circular_q q_; -}; -} // namespace details -} // namespace spdlog diff --git a/tpl/spdlog/include/spdlog/details/null_mutex.h b/tpl/spdlog/include/spdlog/details/null_mutex.h deleted file mode 100644 index 6550a7b..0000000 --- a/tpl/spdlog/include/spdlog/details/null_mutex.h +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. -// Distributed under the MIT License (http://opensource.org/licenses/MIT) - -#pragma once - -#include -#include -// null, no cost dummy "mutex" and dummy "atomic" int - -namespace spdlog { -namespace details { -struct null_mutex -{ - void lock() const {} - void unlock() const {} -}; - -struct null_atomic_int -{ - int value; - null_atomic_int() = default; - - explicit null_atomic_int(int new_value) - : value(new_value) - {} - - int load(std::memory_order = std::memory_order_relaxed) const - { - return value; - } - - void store(int new_value, std::memory_order = std::memory_order_relaxed) - { - value = new_value; - } - - int exchange(int new_value, std::memory_order = std::memory_order_relaxed) - { - std::swap(new_value, value); - return new_value; // return value before the call - } -}; - -} // namespace details -} // namespace spdlog diff --git a/tpl/spdlog/include/spdlog/details/os-inl.h b/tpl/spdlog/include/spdlog/details/os-inl.h deleted file mode 100644 index ea8864e..0000000 --- a/tpl/spdlog/include/spdlog/details/os-inl.h +++ /dev/null @@ -1,635 +0,0 @@ -// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. -// Distributed under the MIT License (http://opensource.org/licenses/MIT) - -#pragma once - -#ifndef SPDLOG_HEADER_ONLY -# include -#endif - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef _WIN32 - -# include // for _get_osfhandle, _isatty, _fileno -# include // for _get_pid -# include -# include // for FlushFileBuffers - -# ifdef __MINGW32__ -# include -# endif - -# if defined(SPDLOG_WCHAR_TO_UTF8_SUPPORT) || defined(SPDLOG_WCHAR_FILENAMES) -# include -# include -# endif - -# include // for _mkdir/_wmkdir - -#else // unix - -# include -# include - -# ifdef __linux__ -# include //Use gettid() syscall under linux to get thread id - -# elif defined(_AIX) -# include // for pthread_getthrds_np - -# elif defined(__DragonFly__) || defined(__FreeBSD__) -# include // for pthread_getthreadid_np - -# elif defined(__NetBSD__) -# include // for _lwp_self - -# elif defined(__sun) -# include // for thr_self -# endif - -#endif // unix - -#if defined __APPLE__ -# include -#endif - -#ifndef __has_feature // Clang - feature checking macros. -# define __has_feature(x) 0 // Compatibility with non-clang compilers. -#endif - -namespace spdlog { -namespace details { -namespace os { - -SPDLOG_INLINE spdlog::log_clock::time_point now() SPDLOG_NOEXCEPT -{ - -#if defined __linux__ && defined SPDLOG_CLOCK_COARSE - timespec ts; - ::clock_gettime(CLOCK_REALTIME_COARSE, &ts); - return std::chrono::time_point( - std::chrono::duration_cast(std::chrono::seconds(ts.tv_sec) + std::chrono::nanoseconds(ts.tv_nsec))); - -#else - return log_clock::now(); -#endif -} -SPDLOG_INLINE std::tm localtime(const std::time_t &time_tt) SPDLOG_NOEXCEPT -{ - -#ifdef _WIN32 - std::tm tm; - ::localtime_s(&tm, &time_tt); -#else - std::tm tm; - ::localtime_r(&time_tt, &tm); -#endif - return tm; -} - -SPDLOG_INLINE std::tm localtime() SPDLOG_NOEXCEPT -{ - std::time_t now_t = ::time(nullptr); - return localtime(now_t); -} - -SPDLOG_INLINE std::tm gmtime(const std::time_t &time_tt) SPDLOG_NOEXCEPT -{ - -#ifdef _WIN32 - std::tm tm; - ::gmtime_s(&tm, &time_tt); -#else - std::tm tm; - ::gmtime_r(&time_tt, &tm); -#endif - return tm; -} - -SPDLOG_INLINE std::tm gmtime() SPDLOG_NOEXCEPT -{ - std::time_t now_t = ::time(nullptr); - return gmtime(now_t); -} - -// fopen_s on non windows for writing -SPDLOG_INLINE bool fopen_s(FILE **fp, const filename_t &filename, const filename_t &mode) -{ -#ifdef _WIN32 -# ifdef SPDLOG_WCHAR_FILENAMES - *fp = ::_wfsopen((filename.c_str()), mode.c_str(), _SH_DENYNO); -# else - *fp = ::_fsopen((filename.c_str()), mode.c_str(), _SH_DENYNO); -# endif -# if defined(SPDLOG_PREVENT_CHILD_FD) - if (*fp != nullptr) - { - auto file_handle = reinterpret_cast(_get_osfhandle(::_fileno(*fp))); - if (!::SetHandleInformation(file_handle, HANDLE_FLAG_INHERIT, 0)) - { - ::fclose(*fp); - *fp = nullptr; - } - } -# endif -#else // unix -# if defined(SPDLOG_PREVENT_CHILD_FD) - const int mode_flag = mode == SPDLOG_FILENAME_T("ab") ? O_APPEND : O_TRUNC; - const int fd = ::open((filename.c_str()), O_CREAT | O_WRONLY | O_CLOEXEC | mode_flag, mode_t(0644)); - if (fd == -1) - { - return true; - } - *fp = ::fdopen(fd, mode.c_str()); - if (*fp == nullptr) - { - ::close(fd); - } -# else - *fp = ::fopen((filename.c_str()), mode.c_str()); -# endif -#endif - - return *fp == nullptr; -} - -SPDLOG_INLINE int remove(const filename_t &filename) SPDLOG_NOEXCEPT -{ -#if defined(_WIN32) && defined(SPDLOG_WCHAR_FILENAMES) - return ::_wremove(filename.c_str()); -#else - return std::remove(filename.c_str()); -#endif -} - -SPDLOG_INLINE int remove_if_exists(const filename_t &filename) SPDLOG_NOEXCEPT -{ - return path_exists(filename) ? remove(filename) : 0; -} - -SPDLOG_INLINE int rename(const filename_t &filename1, const filename_t &filename2) SPDLOG_NOEXCEPT -{ -#if defined(_WIN32) && defined(SPDLOG_WCHAR_FILENAMES) - return ::_wrename(filename1.c_str(), filename2.c_str()); -#else - return std::rename(filename1.c_str(), filename2.c_str()); -#endif -} - -// Return true if path exists (file or directory) -SPDLOG_INLINE bool path_exists(const filename_t &filename) SPDLOG_NOEXCEPT -{ -#ifdef _WIN32 -# ifdef SPDLOG_WCHAR_FILENAMES - auto attribs = ::GetFileAttributesW(filename.c_str()); -# else - auto attribs = ::GetFileAttributesA(filename.c_str()); -# endif - return attribs != INVALID_FILE_ATTRIBUTES; -#else // common linux/unix all have the stat system call - struct stat buffer; - return (::stat(filename.c_str(), &buffer) == 0); -#endif -} - -#ifdef _MSC_VER -// avoid warning about unreachable statement at the end of filesize() -# pragma warning(push) -# pragma warning(disable : 4702) -#endif - -// Return file size according to open FILE* object -SPDLOG_INLINE size_t filesize(FILE *f) -{ - if (f == nullptr) - { - throw_spdlog_ex("Failed getting file size. fd is null"); - } -#if defined(_WIN32) && !defined(__CYGWIN__) - int fd = ::_fileno(f); -# if defined(_WIN64) // 64 bits - __int64 ret = ::_filelengthi64(fd); - if (ret >= 0) - { - return static_cast(ret); - } - -# else // windows 32 bits - long ret = ::_filelength(fd); - if (ret >= 0) - { - return static_cast(ret); - } -# endif - -#else // unix -// OpenBSD and AIX doesn't compile with :: before the fileno(..) -# if defined(__OpenBSD__) || defined(_AIX) - int fd = fileno(f); -# else - int fd = ::fileno(f); -# endif -// 64 bits(but not in osx, linux/musl or cygwin, where fstat64 is deprecated) -# if ((defined(__linux__) && defined(__GLIBC__)) || defined(__sun) || defined(_AIX)) && (defined(__LP64__) || defined(_LP64)) - struct stat64 st; - if (::fstat64(fd, &st) == 0) - { - return static_cast(st.st_size); - } -# else // other unix or linux 32 bits or cygwin - struct stat st; - if (::fstat(fd, &st) == 0) - { - return static_cast(st.st_size); - } -# endif -#endif - throw_spdlog_ex("Failed getting file size from fd", errno); - return 0; // will not be reached. -} - -#ifdef _MSC_VER -# pragma warning(pop) -#endif - -// Return utc offset in minutes or throw spdlog_ex on failure -SPDLOG_INLINE int utc_minutes_offset(const std::tm &tm) -{ - -#ifdef _WIN32 -# if _WIN32_WINNT < _WIN32_WINNT_WS08 - TIME_ZONE_INFORMATION tzinfo; - auto rv = ::GetTimeZoneInformation(&tzinfo); -# else - DYNAMIC_TIME_ZONE_INFORMATION tzinfo; - auto rv = ::GetDynamicTimeZoneInformation(&tzinfo); -# endif - if (rv == TIME_ZONE_ID_INVALID) - throw_spdlog_ex("Failed getting timezone info. ", errno); - - int offset = -tzinfo.Bias; - if (tm.tm_isdst) - { - offset -= tzinfo.DaylightBias; - } - else - { - offset -= tzinfo.StandardBias; - } - return offset; -#else - -# if defined(sun) || defined(__sun) || defined(_AIX) || (defined(__NEWLIB__) && !defined(__TM_GMTOFF)) || \ - (!defined(_BSD_SOURCE) && !defined(_GNU_SOURCE)) - // 'tm_gmtoff' field is BSD extension and it's missing on SunOS/Solaris - struct helper - { - static long int calculate_gmt_offset(const std::tm &localtm = details::os::localtime(), const std::tm &gmtm = details::os::gmtime()) - { - int local_year = localtm.tm_year + (1900 - 1); - int gmt_year = gmtm.tm_year + (1900 - 1); - - long int days = ( - // difference in day of year - localtm.tm_yday - - gmtm.tm_yday - - // + intervening leap days - + ((local_year >> 2) - (gmt_year >> 2)) - (local_year / 100 - gmt_year / 100) + - ((local_year / 100 >> 2) - (gmt_year / 100 >> 2)) - - // + difference in years * 365 */ - + static_cast(local_year - gmt_year) * 365); - - long int hours = (24 * days) + (localtm.tm_hour - gmtm.tm_hour); - long int mins = (60 * hours) + (localtm.tm_min - gmtm.tm_min); - long int secs = (60 * mins) + (localtm.tm_sec - gmtm.tm_sec); - - return secs; - } - }; - - auto offset_seconds = helper::calculate_gmt_offset(tm); -# else - auto offset_seconds = tm.tm_gmtoff; -# endif - - return static_cast(offset_seconds / 60); -#endif -} - -// Return current thread id as size_t -// It exists because the std::this_thread::get_id() is much slower(especially -// under VS 2013) -SPDLOG_INLINE size_t _thread_id() SPDLOG_NOEXCEPT -{ -#ifdef _WIN32 - return static_cast(::GetCurrentThreadId()); -#elif defined(__linux__) -# if defined(__ANDROID__) && defined(__ANDROID_API__) && (__ANDROID_API__ < 21) -# define SYS_gettid __NR_gettid -# endif - return static_cast(::syscall(SYS_gettid)); -#elif defined(_AIX) - struct __pthrdsinfo buf; - int reg_size = 0; - pthread_t pt = pthread_self(); - int retval = pthread_getthrds_np(&pt, PTHRDSINFO_QUERY_TID, &buf, sizeof(buf), NULL, ®_size); - int tid = (!retval) ? buf.__pi_tid : 0; - return static_cast(tid); -#elif defined(__DragonFly__) || defined(__FreeBSD__) - return static_cast(::pthread_getthreadid_np()); -#elif defined(__NetBSD__) - return static_cast(::_lwp_self()); -#elif defined(__OpenBSD__) - return static_cast(::getthrid()); -#elif defined(__sun) - return static_cast(::thr_self()); -#elif __APPLE__ - uint64_t tid; - // There is no pthread_threadid_np prior to 10.6, and it is not supported on any PPC, - // including 10.6.8 Rosetta. __POWERPC__ is Apple-specific define encompassing ppc and ppc64. -# if (MAC_OS_X_VERSION_MAX_ALLOWED < 1060) || defined(__POWERPC__) - tid = pthread_mach_thread_np(pthread_self()); -# elif MAC_OS_X_VERSION_MIN_REQUIRED < 1060 - if (&pthread_threadid_np) - { - pthread_threadid_np(nullptr, &tid); - } - else - { - tid = pthread_mach_thread_np(pthread_self()); - } -# else - pthread_threadid_np(nullptr, &tid); -# endif - return static_cast(tid); -#else // Default to standard C++11 (other Unix) - return static_cast(std::hash()(std::this_thread::get_id())); -#endif -} - -// Return current thread id as size_t (from thread local storage) -SPDLOG_INLINE size_t thread_id() SPDLOG_NOEXCEPT -{ -#if defined(SPDLOG_NO_TLS) - return _thread_id(); -#else // cache thread id in tls - static thread_local const size_t tid = _thread_id(); - return tid; -#endif -} - -// This is avoid msvc issue in sleep_for that happens if the clock changes. -// See https://github.com/gabime/spdlog/issues/609 -SPDLOG_INLINE void sleep_for_millis(unsigned int milliseconds) SPDLOG_NOEXCEPT -{ -#if defined(_WIN32) - ::Sleep(milliseconds); -#else - std::this_thread::sleep_for(std::chrono::milliseconds(milliseconds)); -#endif -} - -// wchar support for windows file names (SPDLOG_WCHAR_FILENAMES must be defined) -#if defined(_WIN32) && defined(SPDLOG_WCHAR_FILENAMES) -SPDLOG_INLINE std::string filename_to_str(const filename_t &filename) -{ - memory_buf_t buf; - wstr_to_utf8buf(filename, buf); - return SPDLOG_BUF_TO_STRING(buf); -} -#else -SPDLOG_INLINE std::string filename_to_str(const filename_t &filename) -{ - return filename; -} -#endif - -SPDLOG_INLINE int pid() SPDLOG_NOEXCEPT -{ - -#ifdef _WIN32 - return conditional_static_cast(::GetCurrentProcessId()); -#else - return conditional_static_cast(::getpid()); -#endif -} - -// Determine if the terminal supports colors -// Based on: https://github.com/agauniyal/rang/ -SPDLOG_INLINE bool is_color_terminal() SPDLOG_NOEXCEPT -{ -#ifdef _WIN32 - return true; -#else - - static const bool result = []() { - const char *env_colorterm_p = std::getenv("COLORTERM"); - if (env_colorterm_p != nullptr) - { - return true; - } - - static constexpr std::array terms = {{"ansi", "color", "console", "cygwin", "gnome", "konsole", "kterm", "linux", - "msys", "putty", "rxvt", "screen", "vt100", "xterm", "alacritty", "vt102"}}; - - const char *env_term_p = std::getenv("TERM"); - if (env_term_p == nullptr) - { - return false; - } - - return std::any_of(terms.begin(), terms.end(), [&](const char *term) { return std::strstr(env_term_p, term) != nullptr; }); - }(); - - return result; -#endif -} - -// Determine if the terminal attached -// Source: https://github.com/agauniyal/rang/ -SPDLOG_INLINE bool in_terminal(FILE *file) SPDLOG_NOEXCEPT -{ - -#ifdef _WIN32 - return ::_isatty(_fileno(file)) != 0; -#else - return ::isatty(fileno(file)) != 0; -#endif -} - -#if (defined(SPDLOG_WCHAR_TO_UTF8_SUPPORT) || defined(SPDLOG_WCHAR_FILENAMES)) && defined(_WIN32) -SPDLOG_INLINE void wstr_to_utf8buf(wstring_view_t wstr, memory_buf_t &target) -{ - if (wstr.size() > static_cast((std::numeric_limits::max)()) / 2 - 1) - { - throw_spdlog_ex("UTF-16 string is too big to be converted to UTF-8"); - } - - int wstr_size = static_cast(wstr.size()); - if (wstr_size == 0) - { - target.resize(0); - return; - } - - int result_size = static_cast(target.capacity()); - if ((wstr_size + 1) * 2 > result_size) - { - result_size = ::WideCharToMultiByte(CP_UTF8, 0, wstr.data(), wstr_size, NULL, 0, NULL, NULL); - } - - if (result_size > 0) - { - target.resize(result_size); - result_size = ::WideCharToMultiByte(CP_UTF8, 0, wstr.data(), wstr_size, target.data(), result_size, NULL, NULL); - - if (result_size > 0) - { - target.resize(result_size); - return; - } - } - - throw_spdlog_ex(fmt_lib::format("WideCharToMultiByte failed. Last error: {}", ::GetLastError())); -} - -SPDLOG_INLINE void utf8_to_wstrbuf(string_view_t str, wmemory_buf_t &target) -{ - if (str.size() > static_cast((std::numeric_limits::max)()) - 1) - { - throw_spdlog_ex("UTF-8 string is too big to be converted to UTF-16"); - } - - int str_size = static_cast(str.size()); - if (str_size == 0) - { - target.resize(0); - return; - } - - // find the size to allocate for the result buffer - int result_size = ::MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, str.data(), str_size, NULL, 0); - - if (result_size > 0) - { - target.resize(result_size); - result_size = ::MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, str.data(), str_size, target.data(), result_size); - if (result_size > 0) - { - assert(result_size == target.size()); - return; - } - } - - throw_spdlog_ex(fmt_lib::format("MultiByteToWideChar failed. Last error: {}", ::GetLastError())); -} -#endif // (defined(SPDLOG_WCHAR_TO_UTF8_SUPPORT) || defined(SPDLOG_WCHAR_FILENAMES)) && defined(_WIN32) - -// return true on success -static SPDLOG_INLINE bool mkdir_(const filename_t &path) -{ -#ifdef _WIN32 -# ifdef SPDLOG_WCHAR_FILENAMES - return ::_wmkdir(path.c_str()) == 0; -# else - return ::_mkdir(path.c_str()) == 0; -# endif -#else - return ::mkdir(path.c_str(), mode_t(0755)) == 0; -#endif -} - -// create the given directory - and all directories leading to it -// return true on success or if the directory already exists -SPDLOG_INLINE bool create_dir(const filename_t &path) -{ - if (path_exists(path)) - { - return true; - } - - if (path.empty()) - { - return false; - } - - size_t search_offset = 0; - do - { - auto token_pos = path.find_first_of(folder_seps_filename, search_offset); - // treat the entire path as a folder if no folder separator not found - if (token_pos == filename_t::npos) - { - token_pos = path.size(); - } - - auto subdir = path.substr(0, token_pos); - - if (!subdir.empty() && !path_exists(subdir) && !mkdir_(subdir)) - { - return false; // return error if failed creating dir - } - search_offset = token_pos + 1; - } while (search_offset < path.size()); - - return true; -} - -// Return directory name from given path or empty string -// "abc/file" => "abc" -// "abc/" => "abc" -// "abc" => "" -// "abc///" => "abc//" -SPDLOG_INLINE filename_t dir_name(const filename_t &path) -{ - auto pos = path.find_last_of(folder_seps_filename); - return pos != filename_t::npos ? path.substr(0, pos) : filename_t{}; -} - -std::string SPDLOG_INLINE getenv(const char *field) -{ - -#if defined(_MSC_VER) -# if defined(__cplusplus_winrt) - return std::string{}; // not supported under uwp -# else - size_t len = 0; - char buf[128]; - bool ok = ::getenv_s(&len, buf, sizeof(buf), field) == 0; - return ok ? buf : std::string{}; -# endif -#else // revert to getenv - char *buf = ::getenv(field); - return buf ? buf : std::string{}; -#endif -} - -// Do fsync by FILE handlerpointer -// Return true on success -SPDLOG_INLINE bool fsync(FILE *fp) -{ -#ifdef _WIN32 - return FlushFileBuffers(reinterpret_cast(_get_osfhandle(_fileno(fp)))) != 0; -#else - return ::fsync(fileno(fp)) == 0; -#endif -} - -} // namespace os -} // namespace details -} // namespace spdlog diff --git a/tpl/spdlog/include/spdlog/details/os.h b/tpl/spdlog/include/spdlog/details/os.h deleted file mode 100644 index 37b0087..0000000 --- a/tpl/spdlog/include/spdlog/details/os.h +++ /dev/null @@ -1,122 +0,0 @@ -// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. -// Distributed under the MIT License (http://opensource.org/licenses/MIT) - -#pragma once - -#include -#include // std::time_t - -namespace spdlog { -namespace details { -namespace os { - -SPDLOG_API spdlog::log_clock::time_point now() SPDLOG_NOEXCEPT; - -SPDLOG_API std::tm localtime(const std::time_t &time_tt) SPDLOG_NOEXCEPT; - -SPDLOG_API std::tm localtime() SPDLOG_NOEXCEPT; - -SPDLOG_API std::tm gmtime(const std::time_t &time_tt) SPDLOG_NOEXCEPT; - -SPDLOG_API std::tm gmtime() SPDLOG_NOEXCEPT; - -// eol definition -#if !defined(SPDLOG_EOL) -# ifdef _WIN32 -# define SPDLOG_EOL "\r\n" -# else -# define SPDLOG_EOL "\n" -# endif -#endif - -SPDLOG_CONSTEXPR static const char *default_eol = SPDLOG_EOL; - -// folder separator -#if !defined(SPDLOG_FOLDER_SEPS) -# ifdef _WIN32 -# define SPDLOG_FOLDER_SEPS "\\/" -# else -# define SPDLOG_FOLDER_SEPS "/" -# endif -#endif - -SPDLOG_CONSTEXPR static const char folder_seps[] = SPDLOG_FOLDER_SEPS; -SPDLOG_CONSTEXPR static const filename_t::value_type folder_seps_filename[] = SPDLOG_FILENAME_T(SPDLOG_FOLDER_SEPS); - -// fopen_s on non windows for writing -SPDLOG_API bool fopen_s(FILE **fp, const filename_t &filename, const filename_t &mode); - -// Remove filename. return 0 on success -SPDLOG_API int remove(const filename_t &filename) SPDLOG_NOEXCEPT; - -// Remove file if exists. return 0 on success -// Note: Non atomic (might return failure to delete if concurrently deleted by other process/thread) -SPDLOG_API int remove_if_exists(const filename_t &filename) SPDLOG_NOEXCEPT; - -SPDLOG_API int rename(const filename_t &filename1, const filename_t &filename2) SPDLOG_NOEXCEPT; - -// Return if file exists. -SPDLOG_API bool path_exists(const filename_t &filename) SPDLOG_NOEXCEPT; - -// Return file size according to open FILE* object -SPDLOG_API size_t filesize(FILE *f); - -// Return utc offset in minutes or throw spdlog_ex on failure -SPDLOG_API int utc_minutes_offset(const std::tm &tm = details::os::localtime()); - -// Return current thread id as size_t -// It exists because the std::this_thread::get_id() is much slower(especially -// under VS 2013) -SPDLOG_API size_t _thread_id() SPDLOG_NOEXCEPT; - -// Return current thread id as size_t (from thread local storage) -SPDLOG_API size_t thread_id() SPDLOG_NOEXCEPT; - -// This is avoid msvc issue in sleep_for that happens if the clock changes. -// See https://github.com/gabime/spdlog/issues/609 -SPDLOG_API void sleep_for_millis(unsigned int milliseconds) SPDLOG_NOEXCEPT; - -SPDLOG_API std::string filename_to_str(const filename_t &filename); - -SPDLOG_API int pid() SPDLOG_NOEXCEPT; - -// Determine if the terminal supports colors -// Source: https://github.com/agauniyal/rang/ -SPDLOG_API bool is_color_terminal() SPDLOG_NOEXCEPT; - -// Determine if the terminal attached -// Source: https://github.com/agauniyal/rang/ -SPDLOG_API bool in_terminal(FILE *file) SPDLOG_NOEXCEPT; - -#if (defined(SPDLOG_WCHAR_TO_UTF8_SUPPORT) || defined(SPDLOG_WCHAR_FILENAMES)) && defined(_WIN32) -SPDLOG_API void wstr_to_utf8buf(wstring_view_t wstr, memory_buf_t &target); - -SPDLOG_API void utf8_to_wstrbuf(string_view_t str, wmemory_buf_t &target); -#endif - -// Return directory name from given path or empty string -// "abc/file" => "abc" -// "abc/" => "abc" -// "abc" => "" -// "abc///" => "abc//" -SPDLOG_API filename_t dir_name(const filename_t &path); - -// Create a dir from the given path. -// Return true if succeeded or if this dir already exists. -SPDLOG_API bool create_dir(const filename_t &path); - -// non thread safe, cross platform getenv/getenv_s -// return empty string if field not found -SPDLOG_API std::string getenv(const char *field); - -// Do fsync by FILE objectpointer. -// Return true on success. -SPDLOG_API bool fsync(FILE *fp); - -} // namespace os -} // namespace details -} // namespace spdlog - -#ifdef SPDLOG_HEADER_ONLY -# include "os-inl.h" -#endif diff --git a/tpl/spdlog/include/spdlog/details/periodic_worker-inl.h b/tpl/spdlog/include/spdlog/details/periodic_worker-inl.h deleted file mode 100644 index 520a2b3..0000000 --- a/tpl/spdlog/include/spdlog/details/periodic_worker-inl.h +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. -// Distributed under the MIT License (http://opensource.org/licenses/MIT) - -#pragma once - -#ifndef SPDLOG_HEADER_ONLY -# include -#endif - -namespace spdlog { -namespace details { - -// stop the worker thread and join it -SPDLOG_INLINE periodic_worker::~periodic_worker() -{ - if (worker_thread_.joinable()) - { - { - std::lock_guard lock(mutex_); - active_ = false; - } - cv_.notify_one(); - worker_thread_.join(); - } -} - -} // namespace details -} // namespace spdlog diff --git a/tpl/spdlog/include/spdlog/details/periodic_worker.h b/tpl/spdlog/include/spdlog/details/periodic_worker.h deleted file mode 100644 index d7d69b2..0000000 --- a/tpl/spdlog/include/spdlog/details/periodic_worker.h +++ /dev/null @@ -1,60 +0,0 @@ -// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. -// Distributed under the MIT License (http://opensource.org/licenses/MIT) - -#pragma once - -// periodic worker thread - periodically executes the given callback function. -// -// RAII over the owned thread: -// creates the thread on construction. -// stops and joins the thread on destruction (if the thread is executing a callback, wait for it to finish first). - -#include -#include -#include -#include -#include -namespace spdlog { -namespace details { - -class SPDLOG_API periodic_worker -{ -public: - template - periodic_worker(const std::function &callback_fun, std::chrono::duration interval) - { - active_ = (interval > std::chrono::duration::zero()); - if (!active_) - { - return; - } - - worker_thread_ = std::thread([this, callback_fun, interval]() { - for (;;) - { - std::unique_lock lock(this->mutex_); - if (this->cv_.wait_for(lock, interval, [this] { return !this->active_; })) - { - return; // active_ == false, so exit this thread - } - callback_fun(); - } - }); - } - periodic_worker(const periodic_worker &) = delete; - periodic_worker &operator=(const periodic_worker &) = delete; - // stop the worker thread and join it - ~periodic_worker(); - -private: - bool active_; - std::thread worker_thread_; - std::mutex mutex_; - std::condition_variable cv_; -}; -} // namespace details -} // namespace spdlog - -#ifdef SPDLOG_HEADER_ONLY -# include "periodic_worker-inl.h" -#endif diff --git a/tpl/spdlog/include/spdlog/details/registry-inl.h b/tpl/spdlog/include/spdlog/details/registry-inl.h deleted file mode 100644 index cb1fe84..0000000 --- a/tpl/spdlog/include/spdlog/details/registry-inl.h +++ /dev/null @@ -1,315 +0,0 @@ -// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. -// Distributed under the MIT License (http://opensource.org/licenses/MIT) - -#pragma once - -#ifndef SPDLOG_HEADER_ONLY -# include -#endif - -#include -#include -#include -#include - -#ifndef SPDLOG_DISABLE_DEFAULT_LOGGER -// support for the default stdout color logger -# ifdef _WIN32 -# include -# else -# include -# endif -#endif // SPDLOG_DISABLE_DEFAULT_LOGGER - -#include -#include -#include -#include -#include - -namespace spdlog { -namespace details { - -SPDLOG_INLINE registry::registry() - : formatter_(new pattern_formatter()) -{ - -#ifndef SPDLOG_DISABLE_DEFAULT_LOGGER - // create default logger (ansicolor_stdout_sink_mt or wincolor_stdout_sink_mt in windows). -# ifdef _WIN32 - auto color_sink = std::make_shared(); -# else - auto color_sink = std::make_shared(); -# endif - - const char *default_logger_name = ""; - default_logger_ = std::make_shared(default_logger_name, std::move(color_sink)); - loggers_[default_logger_name] = default_logger_; - -#endif // SPDLOG_DISABLE_DEFAULT_LOGGER -} - -SPDLOG_INLINE registry::~registry() = default; - -SPDLOG_INLINE void registry::register_logger(std::shared_ptr new_logger) -{ - std::lock_guard lock(logger_map_mutex_); - register_logger_(std::move(new_logger)); -} - -SPDLOG_INLINE void registry::initialize_logger(std::shared_ptr new_logger) -{ - std::lock_guard lock(logger_map_mutex_); - new_logger->set_formatter(formatter_->clone()); - - if (err_handler_) - { - new_logger->set_error_handler(err_handler_); - } - - // set new level according to previously configured level or default level - auto it = log_levels_.find(new_logger->name()); - auto new_level = it != log_levels_.end() ? it->second : global_log_level_; - new_logger->set_level(new_level); - - new_logger->flush_on(flush_level_); - - if (backtrace_n_messages_ > 0) - { - new_logger->enable_backtrace(backtrace_n_messages_); - } - - if (automatic_registration_) - { - register_logger_(std::move(new_logger)); - } -} - -SPDLOG_INLINE std::shared_ptr registry::get(const std::string &logger_name) -{ - std::lock_guard lock(logger_map_mutex_); - auto found = loggers_.find(logger_name); - return found == loggers_.end() ? nullptr : found->second; -} - -SPDLOG_INLINE std::shared_ptr registry::default_logger() -{ - std::lock_guard lock(logger_map_mutex_); - return default_logger_; -} - -// Return raw ptr to the default logger. -// To be used directly by the spdlog default api (e.g. spdlog::info) -// This make the default API faster, but cannot be used concurrently with set_default_logger(). -// e.g do not call set_default_logger() from one thread while calling spdlog::info() from another. -SPDLOG_INLINE logger *registry::get_default_raw() -{ - return default_logger_.get(); -} - -// set default logger. -// default logger is stored in default_logger_ (for faster retrieval) and in the loggers_ map. -SPDLOG_INLINE void registry::set_default_logger(std::shared_ptr new_default_logger) -{ - std::lock_guard lock(logger_map_mutex_); - // remove previous default logger from the map - if (default_logger_ != nullptr) - { - loggers_.erase(default_logger_->name()); - } - if (new_default_logger != nullptr) - { - loggers_[new_default_logger->name()] = new_default_logger; - } - default_logger_ = std::move(new_default_logger); -} - -SPDLOG_INLINE void registry::set_tp(std::shared_ptr tp) -{ - std::lock_guard lock(tp_mutex_); - tp_ = std::move(tp); -} - -SPDLOG_INLINE std::shared_ptr registry::get_tp() -{ - std::lock_guard lock(tp_mutex_); - return tp_; -} - -// Set global formatter. Each sink in each logger will get a clone of this object -SPDLOG_INLINE void registry::set_formatter(std::unique_ptr formatter) -{ - std::lock_guard lock(logger_map_mutex_); - formatter_ = std::move(formatter); - for (auto &l : loggers_) - { - l.second->set_formatter(formatter_->clone()); - } -} - -SPDLOG_INLINE void registry::enable_backtrace(size_t n_messages) -{ - std::lock_guard lock(logger_map_mutex_); - backtrace_n_messages_ = n_messages; - - for (auto &l : loggers_) - { - l.second->enable_backtrace(n_messages); - } -} - -SPDLOG_INLINE void registry::disable_backtrace() -{ - std::lock_guard lock(logger_map_mutex_); - backtrace_n_messages_ = 0; - for (auto &l : loggers_) - { - l.second->disable_backtrace(); - } -} - -SPDLOG_INLINE void registry::set_level(level::level_enum log_level) -{ - std::lock_guard lock(logger_map_mutex_); - for (auto &l : loggers_) - { - l.second->set_level(log_level); - } - global_log_level_ = log_level; -} - -SPDLOG_INLINE void registry::flush_on(level::level_enum log_level) -{ - std::lock_guard lock(logger_map_mutex_); - for (auto &l : loggers_) - { - l.second->flush_on(log_level); - } - flush_level_ = log_level; -} - -SPDLOG_INLINE void registry::set_error_handler(err_handler handler) -{ - std::lock_guard lock(logger_map_mutex_); - for (auto &l : loggers_) - { - l.second->set_error_handler(handler); - } - err_handler_ = std::move(handler); -} - -SPDLOG_INLINE void registry::apply_all(const std::function)> &fun) -{ - std::lock_guard lock(logger_map_mutex_); - for (auto &l : loggers_) - { - fun(l.second); - } -} - -SPDLOG_INLINE void registry::flush_all() -{ - std::lock_guard lock(logger_map_mutex_); - for (auto &l : loggers_) - { - l.second->flush(); - } -} - -SPDLOG_INLINE void registry::drop(const std::string &logger_name) -{ - std::lock_guard lock(logger_map_mutex_); - auto is_default_logger = default_logger_ && default_logger_->name() == logger_name; - loggers_.erase(logger_name); - if (is_default_logger) - { - default_logger_.reset(); - } -} - -SPDLOG_INLINE void registry::drop_all() -{ - std::lock_guard lock(logger_map_mutex_); - loggers_.clear(); - default_logger_.reset(); -} - -// clean all resources and threads started by the registry -SPDLOG_INLINE void registry::shutdown() -{ - { - std::lock_guard lock(flusher_mutex_); - periodic_flusher_.reset(); - } - - drop_all(); - - { - std::lock_guard lock(tp_mutex_); - tp_.reset(); - } -} - -SPDLOG_INLINE std::recursive_mutex ®istry::tp_mutex() -{ - return tp_mutex_; -} - -SPDLOG_INLINE void registry::set_automatic_registration(bool automatic_registration) -{ - std::lock_guard lock(logger_map_mutex_); - automatic_registration_ = automatic_registration; -} - -SPDLOG_INLINE void registry::set_levels(log_levels levels, level::level_enum *global_level) -{ - std::lock_guard lock(logger_map_mutex_); - log_levels_ = std::move(levels); - auto global_level_requested = global_level != nullptr; - global_log_level_ = global_level_requested ? *global_level : global_log_level_; - - for (auto &logger : loggers_) - { - auto logger_entry = log_levels_.find(logger.first); - if (logger_entry != log_levels_.end()) - { - logger.second->set_level(logger_entry->second); - } - else if (global_level_requested) - { - logger.second->set_level(*global_level); - } - } -} - -SPDLOG_INLINE registry ®istry::instance() -{ - static registry s_instance; - return s_instance; -} - -SPDLOG_INLINE void registry::apply_logger_env_levels(std::shared_ptr new_logger) -{ - std::lock_guard lock(logger_map_mutex_); - auto it = log_levels_.find(new_logger->name()); - auto new_level = it != log_levels_.end() ? it->second : global_log_level_; - new_logger->set_level(new_level); -} - -SPDLOG_INLINE void registry::throw_if_exists_(const std::string &logger_name) -{ - if (loggers_.find(logger_name) != loggers_.end()) - { - throw_spdlog_ex("logger with name '" + logger_name + "' already exists"); - } -} - -SPDLOG_INLINE void registry::register_logger_(std::shared_ptr new_logger) -{ - auto logger_name = new_logger->name(); - throw_if_exists_(logger_name); - loggers_[logger_name] = std::move(new_logger); -} - -} // namespace details -} // namespace spdlog diff --git a/tpl/spdlog/include/spdlog/details/registry.h b/tpl/spdlog/include/spdlog/details/registry.h deleted file mode 100644 index 4666fa2..0000000 --- a/tpl/spdlog/include/spdlog/details/registry.h +++ /dev/null @@ -1,123 +0,0 @@ -// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. -// Distributed under the MIT License (http://opensource.org/licenses/MIT) - -#pragma once - -// Loggers registry of unique name->logger pointer -// An attempt to create a logger with an already existing name will result with spdlog_ex exception. -// If user requests a non existing logger, nullptr will be returned -// This class is thread safe - -#include -#include - -#include -#include -#include -#include -#include -#include - -namespace spdlog { -class logger; - -namespace details { -class thread_pool; - -class SPDLOG_API registry -{ -public: - using log_levels = std::unordered_map; - registry(const registry &) = delete; - registry &operator=(const registry &) = delete; - - void register_logger(std::shared_ptr new_logger); - void initialize_logger(std::shared_ptr new_logger); - std::shared_ptr get(const std::string &logger_name); - std::shared_ptr default_logger(); - - // Return raw ptr to the default logger. - // To be used directly by the spdlog default api (e.g. spdlog::info) - // This make the default API faster, but cannot be used concurrently with set_default_logger(). - // e.g do not call set_default_logger() from one thread while calling spdlog::info() from another. - logger *get_default_raw(); - - // set default logger. - // default logger is stored in default_logger_ (for faster retrieval) and in the loggers_ map. - void set_default_logger(std::shared_ptr new_default_logger); - - void set_tp(std::shared_ptr tp); - - std::shared_ptr get_tp(); - - // Set global formatter. Each sink in each logger will get a clone of this object - void set_formatter(std::unique_ptr formatter); - - void enable_backtrace(size_t n_messages); - - void disable_backtrace(); - - void set_level(level::level_enum log_level); - - void flush_on(level::level_enum log_level); - - template - void flush_every(std::chrono::duration interval) - { - std::lock_guard lock(flusher_mutex_); - auto clbk = [this]() { this->flush_all(); }; - periodic_flusher_ = details::make_unique(clbk, interval); - } - - void set_error_handler(err_handler handler); - - void apply_all(const std::function)> &fun); - - void flush_all(); - - void drop(const std::string &logger_name); - - void drop_all(); - - // clean all resources and threads started by the registry - void shutdown(); - - std::recursive_mutex &tp_mutex(); - - void set_automatic_registration(bool automatic_registration); - - // set levels for all existing/future loggers. global_level can be null if should not set. - void set_levels(log_levels levels, level::level_enum *global_level); - - static registry &instance(); - - void apply_logger_env_levels(std::shared_ptr new_logger); - -private: - registry(); - ~registry(); - - void throw_if_exists_(const std::string &logger_name); - void register_logger_(std::shared_ptr new_logger); - bool set_level_from_cfg_(logger *logger); - std::mutex logger_map_mutex_, flusher_mutex_; - std::recursive_mutex tp_mutex_; - std::unordered_map> loggers_; - log_levels log_levels_; - std::unique_ptr formatter_; - spdlog::level::level_enum global_log_level_ = level::info; - level::level_enum flush_level_ = level::off; - err_handler err_handler_; - std::shared_ptr tp_; - std::unique_ptr periodic_flusher_; - std::shared_ptr default_logger_; - bool automatic_registration_ = true; - size_t backtrace_n_messages_ = 0; -}; - -} // namespace details -} // namespace spdlog - -#ifdef SPDLOG_HEADER_ONLY -# include "registry-inl.h" -#endif diff --git a/tpl/spdlog/include/spdlog/details/synchronous_factory.h b/tpl/spdlog/include/spdlog/details/synchronous_factory.h deleted file mode 100644 index e1e4226..0000000 --- a/tpl/spdlog/include/spdlog/details/synchronous_factory.h +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. -// Distributed under the MIT License (http://opensource.org/licenses/MIT) - -#pragma once - -#include "registry.h" - -namespace spdlog { - -// Default logger factory- creates synchronous loggers -class logger; - -struct synchronous_factory -{ - template - static std::shared_ptr create(std::string logger_name, SinkArgs &&...args) - { - auto sink = std::make_shared(std::forward(args)...); - auto new_logger = std::make_shared(std::move(logger_name), std::move(sink)); - details::registry::instance().initialize_logger(new_logger); - return new_logger; - } -}; -} // namespace spdlog diff --git a/tpl/spdlog/include/spdlog/details/tcp_client-windows.h b/tpl/spdlog/include/spdlog/details/tcp_client-windows.h deleted file mode 100644 index 968b257..0000000 --- a/tpl/spdlog/include/spdlog/details/tcp_client-windows.h +++ /dev/null @@ -1,160 +0,0 @@ -// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. -// Distributed under the MIT License (http://opensource.org/licenses/MIT) - -#pragma once - -#define WIN32_LEAN_AND_MEAN -// tcp client helper -#include -#include - -#include -#include -#include -#include -#include -#include - -#pragma comment(lib, "Ws2_32.lib") -#pragma comment(lib, "Mswsock.lib") -#pragma comment(lib, "AdvApi32.lib") - -namespace spdlog { -namespace details { -class tcp_client -{ - SOCKET socket_ = INVALID_SOCKET; - - static void init_winsock_() - { - WSADATA wsaData; - auto rv = WSAStartup(MAKEWORD(2, 2), &wsaData); - if (rv != 0) - { - throw_winsock_error_("WSAStartup failed", ::WSAGetLastError()); - } - } - - static void throw_winsock_error_(const std::string &msg, int last_error) - { - char buf[512]; - ::FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, last_error, - MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), buf, (sizeof(buf) / sizeof(char)), NULL); - - throw_spdlog_ex(fmt_lib::format("tcp_sink - {}: {}", msg, buf)); - } - -public: - tcp_client() - { - init_winsock_(); - } - - ~tcp_client() - { - close(); - ::WSACleanup(); - } - - bool is_connected() const - { - return socket_ != INVALID_SOCKET; - } - - void close() - { - ::closesocket(socket_); - socket_ = INVALID_SOCKET; - } - - SOCKET fd() const - { - return socket_; - } - - // try to connect or throw on failure - void connect(const std::string &host, int port) - { - if (is_connected()) - { - close(); - } - struct addrinfo hints - {}; - ZeroMemory(&hints, sizeof(hints)); - - hints.ai_family = AF_UNSPEC; // To work with IPv4, IPv6, and so on - hints.ai_socktype = SOCK_STREAM; // TCP - hints.ai_flags = AI_NUMERICSERV; // port passed as as numeric value - hints.ai_protocol = 0; - - auto port_str = std::to_string(port); - struct addrinfo *addrinfo_result; - auto rv = ::getaddrinfo(host.c_str(), port_str.c_str(), &hints, &addrinfo_result); - int last_error = 0; - if (rv != 0) - { - last_error = ::WSAGetLastError(); - WSACleanup(); - throw_winsock_error_("getaddrinfo failed", last_error); - } - - // Try each address until we successfully connect(2). - - for (auto *rp = addrinfo_result; rp != nullptr; rp = rp->ai_next) - { - socket_ = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); - if (socket_ == INVALID_SOCKET) - { - last_error = ::WSAGetLastError(); - WSACleanup(); - continue; - } - if (::connect(socket_, rp->ai_addr, (int)rp->ai_addrlen) == 0) - { - break; - } - else - { - last_error = ::WSAGetLastError(); - close(); - } - } - ::freeaddrinfo(addrinfo_result); - if (socket_ == INVALID_SOCKET) - { - WSACleanup(); - throw_winsock_error_("connect failed", last_error); - } - - // set TCP_NODELAY - int enable_flag = 1; - ::setsockopt(socket_, IPPROTO_TCP, TCP_NODELAY, reinterpret_cast(&enable_flag), sizeof(enable_flag)); - } - - // Send exactly n_bytes of the given data. - // On error close the connection and throw. - void send(const char *data, size_t n_bytes) - { - size_t bytes_sent = 0; - while (bytes_sent < n_bytes) - { - const int send_flags = 0; - auto write_result = ::send(socket_, data + bytes_sent, (int)(n_bytes - bytes_sent), send_flags); - if (write_result == SOCKET_ERROR) - { - int last_error = ::WSAGetLastError(); - close(); - throw_winsock_error_("send failed", last_error); - } - - if (write_result == 0) // (probably should not happen but in any case..) - { - break; - } - bytes_sent += static_cast(write_result); - } - } -}; -} // namespace details -} // namespace spdlog diff --git a/tpl/spdlog/include/spdlog/details/tcp_client.h b/tpl/spdlog/include/spdlog/details/tcp_client.h deleted file mode 100644 index 8b11dfd..0000000 --- a/tpl/spdlog/include/spdlog/details/tcp_client.h +++ /dev/null @@ -1,146 +0,0 @@ -// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. -// Distributed under the MIT License (http://opensource.org/licenses/MIT) - -#pragma once - -#ifdef _WIN32 -# error include tcp_client-windows.h instead -#endif - -// tcp client helper -#include -#include - -#include -#include -#include -#include -#include -#include - -#include - -namespace spdlog { -namespace details { -class tcp_client -{ - int socket_ = -1; - -public: - bool is_connected() const - { - return socket_ != -1; - } - - void close() - { - if (is_connected()) - { - ::close(socket_); - socket_ = -1; - } - } - - int fd() const - { - return socket_; - } - - ~tcp_client() - { - close(); - } - - // try to connect or throw on failure - void connect(const std::string &host, int port) - { - close(); - struct addrinfo hints - {}; - memset(&hints, 0, sizeof(struct addrinfo)); - hints.ai_family = AF_UNSPEC; // To work with IPv4, IPv6, and so on - hints.ai_socktype = SOCK_STREAM; // TCP - hints.ai_flags = AI_NUMERICSERV; // port passed as as numeric value - hints.ai_protocol = 0; - - auto port_str = std::to_string(port); - struct addrinfo *addrinfo_result; - auto rv = ::getaddrinfo(host.c_str(), port_str.c_str(), &hints, &addrinfo_result); - if (rv != 0) - { - throw_spdlog_ex(fmt_lib::format("::getaddrinfo failed: {}", gai_strerror(rv))); - } - - // Try each address until we successfully connect(2). - int last_errno = 0; - for (auto *rp = addrinfo_result; rp != nullptr; rp = rp->ai_next) - { -#if defined(SOCK_CLOEXEC) - const int flags = SOCK_CLOEXEC; -#else - const int flags = 0; -#endif - socket_ = ::socket(rp->ai_family, rp->ai_socktype | flags, rp->ai_protocol); - if (socket_ == -1) - { - last_errno = errno; - continue; - } - rv = ::connect(socket_, rp->ai_addr, rp->ai_addrlen); - if (rv == 0) - { - break; - } - last_errno = errno; - ::close(socket_); - socket_ = -1; - } - ::freeaddrinfo(addrinfo_result); - if (socket_ == -1) - { - throw_spdlog_ex("::connect failed", last_errno); - } - - // set TCP_NODELAY - int enable_flag = 1; - ::setsockopt(socket_, IPPROTO_TCP, TCP_NODELAY, reinterpret_cast(&enable_flag), sizeof(enable_flag)); - - // prevent sigpipe on systems where MSG_NOSIGNAL is not available -#if defined(SO_NOSIGPIPE) && !defined(MSG_NOSIGNAL) - ::setsockopt(socket_, SOL_SOCKET, SO_NOSIGPIPE, reinterpret_cast(&enable_flag), sizeof(enable_flag)); -#endif - -#if !defined(SO_NOSIGPIPE) && !defined(MSG_NOSIGNAL) -# error "tcp_sink would raise SIGPIPE since neither SO_NOSIGPIPE nor MSG_NOSIGNAL are available" -#endif - } - - // Send exactly n_bytes of the given data. - // On error close the connection and throw. - void send(const char *data, size_t n_bytes) - { - size_t bytes_sent = 0; - while (bytes_sent < n_bytes) - { -#if defined(MSG_NOSIGNAL) - const int send_flags = MSG_NOSIGNAL; -#else - const int send_flags = 0; -#endif - auto write_result = ::send(socket_, data + bytes_sent, n_bytes - bytes_sent, send_flags); - if (write_result < 0) - { - close(); - throw_spdlog_ex("write(2) failed", errno); - } - - if (write_result == 0) // (probably should not happen but in any case..) - { - break; - } - bytes_sent += static_cast(write_result); - } - } -}; -} // namespace details -} // namespace spdlog diff --git a/tpl/spdlog/include/spdlog/details/thread_pool-inl.h b/tpl/spdlog/include/spdlog/details/thread_pool-inl.h deleted file mode 100644 index dbd424f..0000000 --- a/tpl/spdlog/include/spdlog/details/thread_pool-inl.h +++ /dev/null @@ -1,137 +0,0 @@ -// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. -// Distributed under the MIT License (http://opensource.org/licenses/MIT) - -#pragma once - -#ifndef SPDLOG_HEADER_ONLY -# include -#endif - -#include -#include - -namespace spdlog { -namespace details { - -SPDLOG_INLINE thread_pool::thread_pool( - size_t q_max_items, size_t threads_n, std::function on_thread_start, std::function on_thread_stop) - : q_(q_max_items) -{ - if (threads_n == 0 || threads_n > 1000) - { - throw_spdlog_ex("spdlog::thread_pool(): invalid threads_n param (valid " - "range is 1-1000)"); - } - for (size_t i = 0; i < threads_n; i++) - { - threads_.emplace_back([this, on_thread_start, on_thread_stop] { - on_thread_start(); - this->thread_pool::worker_loop_(); - on_thread_stop(); - }); - } -} - -SPDLOG_INLINE thread_pool::thread_pool(size_t q_max_items, size_t threads_n, std::function on_thread_start) - : thread_pool(q_max_items, threads_n, on_thread_start, [] {}) -{} - -SPDLOG_INLINE thread_pool::thread_pool(size_t q_max_items, size_t threads_n) - : thread_pool( - q_max_items, threads_n, [] {}, [] {}) -{} - -// message all threads to terminate gracefully join them -SPDLOG_INLINE thread_pool::~thread_pool() -{ - SPDLOG_TRY - { - for (size_t i = 0; i < threads_.size(); i++) - { - post_async_msg_(async_msg(async_msg_type::terminate), async_overflow_policy::block); - } - - for (auto &t : threads_) - { - t.join(); - } - } - SPDLOG_CATCH_STD -} - -void SPDLOG_INLINE thread_pool::post_log(async_logger_ptr &&worker_ptr, const details::log_msg &msg, async_overflow_policy overflow_policy) -{ - async_msg async_m(std::move(worker_ptr), async_msg_type::log, msg); - post_async_msg_(std::move(async_m), overflow_policy); -} - -void SPDLOG_INLINE thread_pool::post_flush(async_logger_ptr &&worker_ptr, async_overflow_policy overflow_policy) -{ - post_async_msg_(async_msg(std::move(worker_ptr), async_msg_type::flush), overflow_policy); -} - -size_t SPDLOG_INLINE thread_pool::overrun_counter() -{ - return q_.overrun_counter(); -} - -void SPDLOG_INLINE thread_pool::reset_overrun_counter() -{ - q_.reset_overrun_counter(); -} - -size_t SPDLOG_INLINE thread_pool::queue_size() -{ - return q_.size(); -} - -void SPDLOG_INLINE thread_pool::post_async_msg_(async_msg &&new_msg, async_overflow_policy overflow_policy) -{ - if (overflow_policy == async_overflow_policy::block) - { - q_.enqueue(std::move(new_msg)); - } - else - { - q_.enqueue_nowait(std::move(new_msg)); - } -} - -void SPDLOG_INLINE thread_pool::worker_loop_() -{ - while (process_next_msg_()) {} -} - -// process next message in the queue -// return true if this thread should still be active (while no terminate msg -// was received) -bool SPDLOG_INLINE thread_pool::process_next_msg_() -{ - async_msg incoming_async_msg; - q_.dequeue(incoming_async_msg); - - switch (incoming_async_msg.msg_type) - { - case async_msg_type::log: { - incoming_async_msg.worker_ptr->backend_sink_it_(incoming_async_msg); - return true; - } - case async_msg_type::flush: { - incoming_async_msg.worker_ptr->backend_flush_(); - return true; - } - - case async_msg_type::terminate: { - return false; - } - - default: { - assert(false); - } - } - - return true; -} - -} // namespace details -} // namespace spdlog diff --git a/tpl/spdlog/include/spdlog/details/thread_pool.h b/tpl/spdlog/include/spdlog/details/thread_pool.h deleted file mode 100644 index 52c569b..0000000 --- a/tpl/spdlog/include/spdlog/details/thread_pool.h +++ /dev/null @@ -1,122 +0,0 @@ -// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. -// Distributed under the MIT License (http://opensource.org/licenses/MIT) - -#pragma once - -#include -#include -#include - -#include -#include -#include -#include -#include - -namespace spdlog { -class async_logger; - -namespace details { - -using async_logger_ptr = std::shared_ptr; - -enum class async_msg_type -{ - log, - flush, - terminate -}; - -// Async msg to move to/from the queue -// Movable only. should never be copied -struct async_msg : log_msg_buffer -{ - async_msg_type msg_type{async_msg_type::log}; - async_logger_ptr worker_ptr; - - async_msg() = default; - ~async_msg() = default; - - // should only be moved in or out of the queue.. - async_msg(const async_msg &) = delete; - -// support for vs2013 move -#if defined(_MSC_VER) && _MSC_VER <= 1800 - async_msg(async_msg &&other) - : log_msg_buffer(std::move(other)) - , msg_type(other.msg_type) - , worker_ptr(std::move(other.worker_ptr)) - {} - - async_msg &operator=(async_msg &&other) - { - *static_cast(this) = std::move(other); - msg_type = other.msg_type; - worker_ptr = std::move(other.worker_ptr); - return *this; - } -#else // (_MSC_VER) && _MSC_VER <= 1800 - async_msg(async_msg &&) = default; - async_msg &operator=(async_msg &&) = default; -#endif - - // construct from log_msg with given type - async_msg(async_logger_ptr &&worker, async_msg_type the_type, const details::log_msg &m) - : log_msg_buffer{m} - , msg_type{the_type} - , worker_ptr{std::move(worker)} - {} - - async_msg(async_logger_ptr &&worker, async_msg_type the_type) - : log_msg_buffer{} - , msg_type{the_type} - , worker_ptr{std::move(worker)} - {} - - explicit async_msg(async_msg_type the_type) - : async_msg{nullptr, the_type} - {} -}; - -class SPDLOG_API thread_pool -{ -public: - using item_type = async_msg; - using q_type = details::mpmc_blocking_queue; - - thread_pool(size_t q_max_items, size_t threads_n, std::function on_thread_start, std::function on_thread_stop); - thread_pool(size_t q_max_items, size_t threads_n, std::function on_thread_start); - thread_pool(size_t q_max_items, size_t threads_n); - - // message all threads to terminate gracefully and join them - ~thread_pool(); - - thread_pool(const thread_pool &) = delete; - thread_pool &operator=(thread_pool &&) = delete; - - void post_log(async_logger_ptr &&worker_ptr, const details::log_msg &msg, async_overflow_policy overflow_policy); - void post_flush(async_logger_ptr &&worker_ptr, async_overflow_policy overflow_policy); - size_t overrun_counter(); - void reset_overrun_counter(); - size_t queue_size(); - -private: - q_type q_; - - std::vector threads_; - - void post_async_msg_(async_msg &&new_msg, async_overflow_policy overflow_policy); - void worker_loop_(); - - // process next message in the queue - // return true if this thread should still be active (while no terminate msg - // was received) - bool process_next_msg_(); -}; - -} // namespace details -} // namespace spdlog - -#ifdef SPDLOG_HEADER_ONLY -# include "thread_pool-inl.h" -#endif diff --git a/tpl/spdlog/include/spdlog/details/udp_client-windows.h b/tpl/spdlog/include/spdlog/details/udp_client-windows.h deleted file mode 100644 index 10894ee..0000000 --- a/tpl/spdlog/include/spdlog/details/udp_client-windows.h +++ /dev/null @@ -1,113 +0,0 @@ -// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. -// Distributed under the MIT License (http://opensource.org/licenses/MIT) - -#pragma once - -// Helper RAII over winsock udp client socket. -// Will throw on construction if socket creation failed. - -#include -#include -#include -#include -#include -#include -#include -#include - -#if defined(_MSC_VER) -# pragma comment(lib, "Ws2_32.lib") -# pragma comment(lib, "Mswsock.lib") -# pragma comment(lib, "AdvApi32.lib") -#endif - -namespace spdlog { -namespace details { -class udp_client -{ - static constexpr int TX_BUFFER_SIZE = 1024 * 10; - SOCKET socket_ = INVALID_SOCKET; - sockaddr_in addr_ = {}; - - static void init_winsock_() - { - WSADATA wsaData; - auto rv = ::WSAStartup(MAKEWORD(2, 2), &wsaData); - if (rv != 0) - { - throw_winsock_error_("WSAStartup failed", ::WSAGetLastError()); - } - } - - static void throw_winsock_error_(const std::string &msg, int last_error) - { - char buf[512]; - ::FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, last_error, - MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), buf, (sizeof(buf) / sizeof(char)), NULL); - - throw_spdlog_ex(fmt_lib::format("udp_sink - {}: {}", msg, buf)); - } - - void cleanup_() - { - if (socket_ != INVALID_SOCKET) - { - ::closesocket(socket_); - } - socket_ = INVALID_SOCKET; - ::WSACleanup(); - } - -public: - udp_client(const std::string &host, uint16_t port) - { - init_winsock_(); - - addr_.sin_family = PF_INET; - addr_.sin_port = htons(port); - addr_.sin_addr.s_addr = INADDR_ANY; - if (InetPtonA(PF_INET, host.c_str(), &addr_.sin_addr.s_addr) != 1) - { - int last_error = ::WSAGetLastError(); - ::WSACleanup(); - throw_winsock_error_("error: Invalid address!", last_error); - } - - socket_ = ::socket(PF_INET, SOCK_DGRAM, 0); - if (socket_ == INVALID_SOCKET) - { - int last_error = ::WSAGetLastError(); - ::WSACleanup(); - throw_winsock_error_("error: Create Socket failed", last_error); - } - - int option_value = TX_BUFFER_SIZE; - if (::setsockopt(socket_, SOL_SOCKET, SO_SNDBUF, reinterpret_cast(&option_value), sizeof(option_value)) < 0) - { - int last_error = ::WSAGetLastError(); - cleanup_(); - throw_winsock_error_("error: setsockopt(SO_SNDBUF) Failed!", last_error); - } - } - - ~udp_client() - { - cleanup_(); - } - - SOCKET fd() const - { - return socket_; - } - - void send(const char *data, size_t n_bytes) - { - socklen_t tolen = sizeof(struct sockaddr); - if (::sendto(socket_, data, static_cast(n_bytes), 0, (struct sockaddr *)&addr_, tolen) == -1) - { - throw_spdlog_ex("sendto(2) failed", errno); - } - } -}; -} // namespace details -} // namespace spdlog diff --git a/tpl/spdlog/include/spdlog/details/udp_client.h b/tpl/spdlog/include/spdlog/details/udp_client.h deleted file mode 100644 index e8c2ccc..0000000 --- a/tpl/spdlog/include/spdlog/details/udp_client.h +++ /dev/null @@ -1,94 +0,0 @@ -// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. -// Distributed under the MIT License (http://opensource.org/licenses/MIT) - -#pragma once - -// Helper RAII over unix udp client socket. -// Will throw on construction if the socket creation failed. - -#ifdef _WIN32 -# error "include udp_client-windows.h instead" -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -namespace spdlog { -namespace details { - -class udp_client -{ - static constexpr int TX_BUFFER_SIZE = 1024 * 10; - int socket_ = -1; - struct sockaddr_in sockAddr_; - - void cleanup_() - { - if (socket_ != -1) - { - ::close(socket_); - socket_ = -1; - } - } - -public: - udp_client(const std::string &host, uint16_t port) - { - socket_ = ::socket(PF_INET, SOCK_DGRAM, 0); - if (socket_ < 0) - { - throw_spdlog_ex("error: Create Socket Failed!"); - } - - int option_value = TX_BUFFER_SIZE; - if (::setsockopt(socket_, SOL_SOCKET, SO_SNDBUF, reinterpret_cast(&option_value), sizeof(option_value)) < 0) - { - cleanup_(); - throw_spdlog_ex("error: setsockopt(SO_SNDBUF) Failed!"); - } - - sockAddr_.sin_family = AF_INET; - sockAddr_.sin_port = htons(port); - - if (::inet_aton(host.c_str(), &sockAddr_.sin_addr) == 0) - { - cleanup_(); - throw_spdlog_ex("error: Invalid address!"); - } - - ::memset(sockAddr_.sin_zero, 0x00, sizeof(sockAddr_.sin_zero)); - } - - ~udp_client() - { - cleanup_(); - } - - int fd() const - { - return socket_; - } - - // Send exactly n_bytes of the given data. - // On error close the connection and throw. - void send(const char *data, size_t n_bytes) - { - ssize_t toslen = 0; - socklen_t tolen = sizeof(struct sockaddr); - if ((toslen = ::sendto(socket_, data, n_bytes, 0, (struct sockaddr *)&sockAddr_, tolen)) == -1) - { - throw_spdlog_ex("sendto(2) failed", errno); - } - } -}; -} // namespace details -} // namespace spdlog diff --git a/tpl/spdlog/include/spdlog/details/windows_include.h b/tpl/spdlog/include/spdlog/details/windows_include.h deleted file mode 100644 index a92390b..0000000 --- a/tpl/spdlog/include/spdlog/details/windows_include.h +++ /dev/null @@ -1,11 +0,0 @@ -#pragma once - -#ifndef NOMINMAX -# define NOMINMAX // prevent windows redefining min/max -#endif - -#ifndef WIN32_LEAN_AND_MEAN -# define WIN32_LEAN_AND_MEAN -#endif - -#include diff --git a/tpl/spdlog/include/spdlog/fmt/bin_to_hex.h b/tpl/spdlog/include/spdlog/fmt/bin_to_hex.h deleted file mode 100644 index 3bf003d..0000000 --- a/tpl/spdlog/include/spdlog/fmt/bin_to_hex.h +++ /dev/null @@ -1,248 +0,0 @@ -// -// Copyright(c) 2015 Gabi Melman. -// Distributed under the MIT License (http://opensource.org/licenses/MIT) -// - -#pragma once - -#include -#include - -#if defined(__has_include) -# if __has_include() -# include -# endif -#endif - -#if __cpp_lib_span >= 202002L -# include -#endif - -// -// Support for logging binary data as hex -// format flags, any combination of the following: -// {:X} - print in uppercase. -// {:s} - don't separate each byte with space. -// {:p} - don't print the position on each line start. -// {:n} - don't split the output to lines. -// {:a} - show ASCII if :n is not set - -// -// Examples: -// -// std::vector v(200, 0x0b); -// logger->info("Some buffer {}", spdlog::to_hex(v)); -// char buf[128]; -// logger->info("Some buffer {:X}", spdlog::to_hex(std::begin(buf), std::end(buf))); -// logger->info("Some buffer {:X}", spdlog::to_hex(std::begin(buf), std::end(buf), 16)); - -namespace spdlog { -namespace details { - -template -class dump_info -{ -public: - dump_info(It range_begin, It range_end, size_t size_per_line) - : begin_(range_begin) - , end_(range_end) - , size_per_line_(size_per_line) - {} - - // do not use begin() and end() to avoid collision with fmt/ranges - It get_begin() const - { - return begin_; - } - It get_end() const - { - return end_; - } - size_t size_per_line() const - { - return size_per_line_; - } - -private: - It begin_, end_; - size_t size_per_line_; -}; -} // namespace details - -// create a dump_info that wraps the given container -template -inline details::dump_info to_hex(const Container &container, size_t size_per_line = 32) -{ - static_assert(sizeof(typename Container::value_type) == 1, "sizeof(Container::value_type) != 1"); - using Iter = typename Container::const_iterator; - return details::dump_info(std::begin(container), std::end(container), size_per_line); -} - -#if __cpp_lib_span >= 202002L - -template -inline details::dump_info::iterator> to_hex( - const std::span &container, size_t size_per_line = 32) -{ - using Container = std::span; - static_assert(sizeof(typename Container::value_type) == 1, "sizeof(Container::value_type) != 1"); - using Iter = typename Container::iterator; - return details::dump_info(std::begin(container), std::end(container), size_per_line); -} - -#endif - -// create dump_info from ranges -template -inline details::dump_info to_hex(const It range_begin, const It range_end, size_t size_per_line = 32) -{ - return details::dump_info(range_begin, range_end, size_per_line); -} - -} // namespace spdlog - -namespace -#ifdef SPDLOG_USE_STD_FORMAT - std -#else - fmt -#endif -{ - -template -struct formatter, char> -{ - const char delimiter = ' '; - bool put_newlines = true; - bool put_delimiters = true; - bool use_uppercase = false; - bool put_positions = true; // position on start of each line - bool show_ascii = false; - - // parse the format string flags - template - SPDLOG_CONSTEXPR_FUNC auto parse(ParseContext &ctx) -> decltype(ctx.begin()) - { - auto it = ctx.begin(); - while (it != ctx.end() && *it != '}') - { - switch (*it) - { - case 'X': - use_uppercase = true; - break; - case 's': - put_delimiters = false; - break; - case 'p': - put_positions = false; - break; - case 'n': - put_newlines = false; - show_ascii = false; - break; - case 'a': - if (put_newlines) - { - show_ascii = true; - } - break; - } - - ++it; - } - return it; - } - - // format the given bytes range as hex - template - auto format(const spdlog::details::dump_info &the_range, FormatContext &ctx) const -> decltype(ctx.out()) - { - SPDLOG_CONSTEXPR const char *hex_upper = "0123456789ABCDEF"; - SPDLOG_CONSTEXPR const char *hex_lower = "0123456789abcdef"; - const char *hex_chars = use_uppercase ? hex_upper : hex_lower; - -#if !defined(SPDLOG_USE_STD_FORMAT) && FMT_VERSION < 60000 - auto inserter = ctx.begin(); -#else - auto inserter = ctx.out(); -#endif - - int size_per_line = static_cast(the_range.size_per_line()); - auto start_of_line = the_range.get_begin(); - for (auto i = the_range.get_begin(); i != the_range.get_end(); i++) - { - auto ch = static_cast(*i); - - if (put_newlines && (i == the_range.get_begin() || i - start_of_line >= size_per_line)) - { - if (show_ascii && i != the_range.get_begin()) - { - *inserter++ = delimiter; - *inserter++ = delimiter; - for (auto j = start_of_line; j < i; j++) - { - auto pc = static_cast(*j); - *inserter++ = std::isprint(pc) ? static_cast(*j) : '.'; - } - } - - put_newline(inserter, static_cast(i - the_range.get_begin())); - - // put first byte without delimiter in front of it - *inserter++ = hex_chars[(ch >> 4) & 0x0f]; - *inserter++ = hex_chars[ch & 0x0f]; - start_of_line = i; - continue; - } - - if (put_delimiters && i != the_range.get_begin()) - { - *inserter++ = delimiter; - } - - *inserter++ = hex_chars[(ch >> 4) & 0x0f]; - *inserter++ = hex_chars[ch & 0x0f]; - } - if (show_ascii) // add ascii to last line - { - if (the_range.get_end() - the_range.get_begin() > size_per_line) - { - auto blank_num = size_per_line - (the_range.get_end() - start_of_line); - while (blank_num-- > 0) - { - *inserter++ = delimiter; - *inserter++ = delimiter; - if (put_delimiters) - { - *inserter++ = delimiter; - } - } - } - *inserter++ = delimiter; - *inserter++ = delimiter; - for (auto j = start_of_line; j != the_range.get_end(); j++) - { - auto pc = static_cast(*j); - *inserter++ = std::isprint(pc) ? static_cast(*j) : '.'; - } - } - return inserter; - } - - // put newline(and position header) - template - void put_newline(It inserter, std::size_t pos) const - { -#ifdef _WIN32 - *inserter++ = '\r'; -#endif - *inserter++ = '\n'; - - if (put_positions) - { - spdlog::fmt_lib::format_to(inserter, SPDLOG_FMT_STRING("{:04X}: "), pos); - } - } -}; -} // namespace std diff --git a/tpl/spdlog/include/spdlog/fmt/chrono.h b/tpl/spdlog/include/spdlog/fmt/chrono.h deleted file mode 100644 index 83fad2f..0000000 --- a/tpl/spdlog/include/spdlog/fmt/chrono.h +++ /dev/null @@ -1,22 +0,0 @@ -// -// Copyright(c) 2016 Gabi Melman. -// Distributed under the MIT License (http://opensource.org/licenses/MIT) -// - -#pragma once -// -// include bundled or external copy of fmtlib's chrono support -// - -#if !defined(SPDLOG_USE_STD_FORMAT) -# if !defined(SPDLOG_FMT_EXTERNAL) -# ifdef SPDLOG_HEADER_ONLY -# ifndef FMT_HEADER_ONLY -# define FMT_HEADER_ONLY -# endif -# endif -# include -# else -# include -# endif -#endif diff --git a/tpl/spdlog/include/spdlog/fmt/compile.h b/tpl/spdlog/include/spdlog/fmt/compile.h deleted file mode 100644 index 906e9f5..0000000 --- a/tpl/spdlog/include/spdlog/fmt/compile.h +++ /dev/null @@ -1,22 +0,0 @@ -// -// Copyright(c) 2016 Gabi Melman. -// Distributed under the MIT License (http://opensource.org/licenses/MIT) -// - -#pragma once -// -// include bundled or external copy of fmtlib's compile-time support -// - -#if !defined(SPDLOG_USE_STD_FORMAT) -# if !defined(SPDLOG_FMT_EXTERNAL) -# ifdef SPDLOG_HEADER_ONLY -# ifndef FMT_HEADER_ONLY -# define FMT_HEADER_ONLY -# endif -# endif -# include -# else -# include -# endif -#endif diff --git a/tpl/spdlog/include/spdlog/fmt/fmt.h b/tpl/spdlog/include/spdlog/fmt/fmt.h deleted file mode 100644 index a1a8f1c..0000000 --- a/tpl/spdlog/include/spdlog/fmt/fmt.h +++ /dev/null @@ -1,33 +0,0 @@ -// -// Copyright(c) 2016-2018 Gabi Melman. -// Distributed under the MIT License (http://opensource.org/licenses/MIT) -// - -#pragma once - -// -// Include a bundled header-only copy of fmtlib or an external one. -// By default spdlog include its own copy. -// - -#if defined(SPDLOG_USE_STD_FORMAT) // SPDLOG_USE_STD_FORMAT is defined - use std::format -# include -#elif !defined(SPDLOG_FMT_EXTERNAL) -# if !defined(SPDLOG_COMPILED_LIB) && !defined(FMT_HEADER_ONLY) -# define FMT_HEADER_ONLY -# endif -# ifndef FMT_USE_WINDOWS_H -# define FMT_USE_WINDOWS_H 0 -# endif -// enable the 'n' flag in for backward compatibility with fmt 6.x -# define FMT_DEPRECATED_N_SPECIFIER -// enable ostream formatting for backward compatibility with fmt 8.x -# define FMT_DEPRECATED_OSTREAM - -# include -# include - -#else // SPDLOG_FMT_EXTERNAL is defined - use external fmtlib -# include -# include -#endif diff --git a/tpl/spdlog/include/spdlog/fmt/ostr.h b/tpl/spdlog/include/spdlog/fmt/ostr.h deleted file mode 100644 index 7588034..0000000 --- a/tpl/spdlog/include/spdlog/fmt/ostr.h +++ /dev/null @@ -1,22 +0,0 @@ -// -// Copyright(c) 2016 Gabi Melman. -// Distributed under the MIT License (http://opensource.org/licenses/MIT) -// - -#pragma once -// -// include bundled or external copy of fmtlib's ostream support -// - -#if !defined(SPDLOG_USE_STD_FORMAT) -# if !defined(SPDLOG_FMT_EXTERNAL) -# ifdef SPDLOG_HEADER_ONLY -# ifndef FMT_HEADER_ONLY -# define FMT_HEADER_ONLY -# endif -# endif -# include -# else -# include -# endif -#endif diff --git a/tpl/spdlog/include/spdlog/fmt/ranges.h b/tpl/spdlog/include/spdlog/fmt/ranges.h deleted file mode 100644 index 9103a5f..0000000 --- a/tpl/spdlog/include/spdlog/fmt/ranges.h +++ /dev/null @@ -1,22 +0,0 @@ -// -// Copyright(c) 2016 Gabi Melman. -// Distributed under the MIT License (http://opensource.org/licenses/MIT) -// - -#pragma once -// -// include bundled or external copy of fmtlib's ranges support -// - -#if !defined(SPDLOG_USE_STD_FORMAT) -# if !defined(SPDLOG_FMT_EXTERNAL) -# ifdef SPDLOG_HEADER_ONLY -# ifndef FMT_HEADER_ONLY -# define FMT_HEADER_ONLY -# endif -# endif -# include -# else -# include -# endif -#endif diff --git a/tpl/spdlog/include/spdlog/fmt/std.h b/tpl/spdlog/include/spdlog/fmt/std.h deleted file mode 100644 index 0490cab..0000000 --- a/tpl/spdlog/include/spdlog/fmt/std.h +++ /dev/null @@ -1,23 +0,0 @@ -// -// Copyright(c) 2016 Gabi Melman. -// Distributed under the MIT License (http://opensource.org/licenses/MIT) -// - -#pragma once -// -// include bundled or external copy of fmtlib's std support (for formatting e.g. std::filesystem::path, std::thread::id, std::monostate, -// std::variant, ...) -// - -#if !defined(SPDLOG_USE_STD_FORMAT) -# if !defined(SPDLOG_FMT_EXTERNAL) -# ifdef SPDLOG_HEADER_ONLY -# ifndef FMT_HEADER_ONLY -# define FMT_HEADER_ONLY -# endif -# endif -# include -# else -# include -# endif -#endif diff --git a/tpl/spdlog/include/spdlog/fmt/xchar.h b/tpl/spdlog/include/spdlog/fmt/xchar.h deleted file mode 100644 index 9a766e5..0000000 --- a/tpl/spdlog/include/spdlog/fmt/xchar.h +++ /dev/null @@ -1,22 +0,0 @@ -// -// Copyright(c) 2016 Gabi Melman. -// Distributed under the MIT License (http://opensource.org/licenses/MIT) -// - -#pragma once -// -// include bundled or external copy of fmtlib's xchar support -// - -#if !defined(SPDLOG_USE_STD_FORMAT) -# if !defined(SPDLOG_FMT_EXTERNAL) -# ifdef SPDLOG_HEADER_ONLY -# ifndef FMT_HEADER_ONLY -# define FMT_HEADER_ONLY -# endif -# endif -# include -# else -# include -# endif -#endif diff --git a/tpl/spdlog/include/spdlog/formatter.h b/tpl/spdlog/include/spdlog/formatter.h deleted file mode 100644 index 5086fb2..0000000 --- a/tpl/spdlog/include/spdlog/formatter.h +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. -// Distributed under the MIT License (http://opensource.org/licenses/MIT) - -#pragma once - -#include -#include - -namespace spdlog { - -class formatter -{ -public: - virtual ~formatter() = default; - virtual void format(const details::log_msg &msg, memory_buf_t &dest) = 0; - virtual std::unique_ptr clone() const = 0; -}; -} // namespace spdlog diff --git a/tpl/spdlog/include/spdlog/fwd.h b/tpl/spdlog/include/spdlog/fwd.h deleted file mode 100644 index d258825..0000000 --- a/tpl/spdlog/include/spdlog/fwd.h +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. -// Distributed under the MIT License (http://opensource.org/licenses/MIT) - -#pragma once - -namespace spdlog { -class logger; -class formatter; - -namespace sinks { -class sink; -} - -namespace level { -enum level_enum : int; -} - -} // namespace spdlog diff --git a/tpl/spdlog/include/spdlog/logger-inl.h b/tpl/spdlog/include/spdlog/logger-inl.h deleted file mode 100644 index 227cec4..0000000 --- a/tpl/spdlog/include/spdlog/logger-inl.h +++ /dev/null @@ -1,257 +0,0 @@ -// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. -// Distributed under the MIT License (http://opensource.org/licenses/MIT) - -#pragma once - -#ifndef SPDLOG_HEADER_ONLY -# include -#endif - -#include -#include -#include - -#include - -namespace spdlog { - -// public methods -SPDLOG_INLINE logger::logger(const logger &other) - : name_(other.name_) - , sinks_(other.sinks_) - , level_(other.level_.load(std::memory_order_relaxed)) - , flush_level_(other.flush_level_.load(std::memory_order_relaxed)) - , custom_err_handler_(other.custom_err_handler_) - , tracer_(other.tracer_) -{} - -SPDLOG_INLINE logger::logger(logger &&other) SPDLOG_NOEXCEPT : name_(std::move(other.name_)), - sinks_(std::move(other.sinks_)), - level_(other.level_.load(std::memory_order_relaxed)), - flush_level_(other.flush_level_.load(std::memory_order_relaxed)), - custom_err_handler_(std::move(other.custom_err_handler_)), - tracer_(std::move(other.tracer_)) - -{} - -SPDLOG_INLINE logger &logger::operator=(logger other) SPDLOG_NOEXCEPT -{ - this->swap(other); - return *this; -} - -SPDLOG_INLINE void logger::swap(spdlog::logger &other) SPDLOG_NOEXCEPT -{ - name_.swap(other.name_); - sinks_.swap(other.sinks_); - - // swap level_ - auto other_level = other.level_.load(); - auto my_level = level_.exchange(other_level); - other.level_.store(my_level); - - // swap flush level_ - other_level = other.flush_level_.load(); - my_level = flush_level_.exchange(other_level); - other.flush_level_.store(my_level); - - custom_err_handler_.swap(other.custom_err_handler_); - std::swap(tracer_, other.tracer_); -} - -SPDLOG_INLINE void swap(logger &a, logger &b) -{ - a.swap(b); -} - -SPDLOG_INLINE void logger::set_level(level::level_enum log_level) -{ - level_.store(log_level); -} - -SPDLOG_INLINE level::level_enum logger::level() const -{ - return static_cast(level_.load(std::memory_order_relaxed)); -} - -SPDLOG_INLINE const std::string &logger::name() const -{ - return name_; -} - -// set formatting for the sinks in this logger. -// each sink will get a separate instance of the formatter object. -SPDLOG_INLINE void logger::set_formatter(std::unique_ptr f) -{ - for (auto it = sinks_.begin(); it != sinks_.end(); ++it) - { - if (std::next(it) == sinks_.end()) - { - // last element - we can be move it. - (*it)->set_formatter(std::move(f)); - break; // to prevent clang-tidy warning - } - else - { - (*it)->set_formatter(f->clone()); - } - } -} - -SPDLOG_INLINE void logger::set_pattern(std::string pattern, pattern_time_type time_type) -{ - auto new_formatter = details::make_unique(std::move(pattern), time_type); - set_formatter(std::move(new_formatter)); -} - -// create new backtrace sink and move to it all our child sinks -SPDLOG_INLINE void logger::enable_backtrace(size_t n_messages) -{ - tracer_.enable(n_messages); -} - -// restore orig sinks and level and delete the backtrace sink -SPDLOG_INLINE void logger::disable_backtrace() -{ - tracer_.disable(); -} - -SPDLOG_INLINE void logger::dump_backtrace() -{ - dump_backtrace_(); -} - -// flush functions -SPDLOG_INLINE void logger::flush() -{ - flush_(); -} - -SPDLOG_INLINE void logger::flush_on(level::level_enum log_level) -{ - flush_level_.store(log_level); -} - -SPDLOG_INLINE level::level_enum logger::flush_level() const -{ - return static_cast(flush_level_.load(std::memory_order_relaxed)); -} - -// sinks -SPDLOG_INLINE const std::vector &logger::sinks() const -{ - return sinks_; -} - -SPDLOG_INLINE std::vector &logger::sinks() -{ - return sinks_; -} - -// error handler -SPDLOG_INLINE void logger::set_error_handler(err_handler handler) -{ - custom_err_handler_ = std::move(handler); -} - -// create new logger with same sinks and configuration. -SPDLOG_INLINE std::shared_ptr logger::clone(std::string logger_name) -{ - auto cloned = std::make_shared(*this); - cloned->name_ = std::move(logger_name); - return cloned; -} - -// protected methods -SPDLOG_INLINE void logger::log_it_(const spdlog::details::log_msg &log_msg, bool log_enabled, bool traceback_enabled) -{ - if (log_enabled) - { - sink_it_(log_msg); - } - if (traceback_enabled) - { - tracer_.push_back(log_msg); - } -} - -SPDLOG_INLINE void logger::sink_it_(const details::log_msg &msg) -{ - for (auto &sink : sinks_) - { - if (sink->should_log(msg.level)) - { - SPDLOG_TRY - { - sink->log(msg); - } - SPDLOG_LOGGER_CATCH(msg.source) - } - } - - if (should_flush_(msg)) - { - flush_(); - } -} - -SPDLOG_INLINE void logger::flush_() -{ - for (auto &sink : sinks_) - { - SPDLOG_TRY - { - sink->flush(); - } - SPDLOG_LOGGER_CATCH(source_loc()) - } -} - -SPDLOG_INLINE void logger::dump_backtrace_() -{ - using details::log_msg; - if (tracer_.enabled() && !tracer_.empty()) - { - sink_it_(log_msg{name(), level::info, "****************** Backtrace Start ******************"}); - tracer_.foreach_pop([this](const log_msg &msg) { this->sink_it_(msg); }); - sink_it_(log_msg{name(), level::info, "****************** Backtrace End ********************"}); - } -} - -SPDLOG_INLINE bool logger::should_flush_(const details::log_msg &msg) -{ - auto flush_level = flush_level_.load(std::memory_order_relaxed); - return (msg.level >= flush_level) && (msg.level != level::off); -} - -SPDLOG_INLINE void logger::err_handler_(const std::string &msg) -{ - if (custom_err_handler_) - { - custom_err_handler_(msg); - } - else - { - using std::chrono::system_clock; - static std::mutex mutex; - static std::chrono::system_clock::time_point last_report_time; - static size_t err_counter = 0; - std::lock_guard lk{mutex}; - auto now = system_clock::now(); - err_counter++; - if (now - last_report_time < std::chrono::seconds(1)) - { - return; - } - last_report_time = now; - auto tm_time = details::os::localtime(system_clock::to_time_t(now)); - char date_buf[64]; - std::strftime(date_buf, sizeof(date_buf), "%Y-%m-%d %H:%M:%S", &tm_time); -#if defined(USING_R) && defined(R_R_H) // if in R environment - REprintf("[*** LOG ERROR #%04zu ***] [%s] [%s] %s\n", err_counter, date_buf, name().c_str(), msg.c_str()); -#else - std::fprintf(stderr, "[*** LOG ERROR #%04zu ***] [%s] [%s] %s\n", err_counter, date_buf, name().c_str(), msg.c_str()); -#endif - } -} -} // namespace spdlog diff --git a/tpl/spdlog/include/spdlog/logger.h b/tpl/spdlog/include/spdlog/logger.h deleted file mode 100644 index d37af17..0000000 --- a/tpl/spdlog/include/spdlog/logger.h +++ /dev/null @@ -1,427 +0,0 @@ -// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. -// Distributed under the MIT License (http://opensource.org/licenses/MIT) - -#pragma once - -// Thread safe logger (except for set_error_handler()) -// 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 and if yes: -// 2. Call the underlying sinks to do the job. -// 3. Each sink use its own private copy of a formatter to format the message -// and send to its destination. -// -// The use of private formatter per sink provides the opportunity to cache some -// formatted data, and support for different format per sink. - -#include -#include -#include - -#ifdef SPDLOG_WCHAR_TO_UTF8_SUPPORT -# ifndef _WIN32 -# error SPDLOG_WCHAR_TO_UTF8_SUPPORT only supported on windows -# endif -# include -#endif - -#include - -#ifndef SPDLOG_NO_EXCEPTIONS -# define SPDLOG_LOGGER_CATCH(location) \ - catch (const std::exception &ex) \ - { \ - if (location.filename) \ - { \ - err_handler_(fmt_lib::format(SPDLOG_FMT_STRING("{} [{}({})]"), ex.what(), location.filename, location.line)); \ - } \ - else \ - { \ - err_handler_(ex.what()); \ - } \ - } \ - catch (...) \ - { \ - err_handler_("Rethrowing unknown exception in logger"); \ - throw; \ - } -#else -# define SPDLOG_LOGGER_CATCH(location) -#endif - -namespace spdlog { - -class SPDLOG_API logger -{ -public: - // Empty logger - explicit logger(std::string name) - : name_(std::move(name)) - , sinks_() - {} - - // Logger with range on sinks - template - logger(std::string name, It begin, It end) - : name_(std::move(name)) - , sinks_(begin, end) - {} - - // Logger with single sink - logger(std::string name, sink_ptr single_sink) - : logger(std::move(name), {std::move(single_sink)}) - {} - - // Logger with sinks init list - logger(std::string name, sinks_init_list sinks) - : logger(std::move(name), sinks.begin(), sinks.end()) - {} - - virtual ~logger() = default; - - logger(const logger &other); - logger(logger &&other) SPDLOG_NOEXCEPT; - logger &operator=(logger other) SPDLOG_NOEXCEPT; - void swap(spdlog::logger &other) SPDLOG_NOEXCEPT; - - template - void log(source_loc loc, level::level_enum lvl, format_string_t fmt, Args &&...args) - { - log_(loc, lvl, details::to_string_view(fmt), std::forward(args)...); - } - - template - void log(level::level_enum lvl, format_string_t fmt, Args &&...args) - { - log(source_loc{}, lvl, fmt, std::forward(args)...); - } - - template - void log(level::level_enum lvl, const T &msg) - { - log(source_loc{}, lvl, msg); - } - - // T cannot be statically converted to format string (including string_view/wstring_view) - template::value, int>::type = 0> - void log(source_loc loc, level::level_enum lvl, const T &msg) - { - log(loc, lvl, "{}", msg); - } - - void log(log_clock::time_point log_time, source_loc loc, level::level_enum lvl, string_view_t msg) - { - bool log_enabled = should_log(lvl); - bool traceback_enabled = tracer_.enabled(); - if (!log_enabled && !traceback_enabled) - { - return; - } - - details::log_msg log_msg(log_time, loc, name_, lvl, msg); - log_it_(log_msg, log_enabled, traceback_enabled); - } - - void log(source_loc loc, level::level_enum lvl, string_view_t msg) - { - bool log_enabled = should_log(lvl); - bool traceback_enabled = tracer_.enabled(); - if (!log_enabled && !traceback_enabled) - { - return; - } - - details::log_msg log_msg(loc, name_, lvl, msg); - log_it_(log_msg, log_enabled, traceback_enabled); - } - - void log(level::level_enum lvl, string_view_t msg) - { - log(source_loc{}, lvl, msg); - } - - template - void trace(format_string_t fmt, Args &&...args) - { - log(level::trace, fmt, std::forward(args)...); - } - - template - void debug(format_string_t fmt, Args &&...args) - { - log(level::debug, fmt, std::forward(args)...); - } - - template - void info(format_string_t fmt, Args &&...args) - { - log(level::info, fmt, std::forward(args)...); - } - - template - void warn(format_string_t fmt, Args &&...args) - { - log(level::warn, fmt, std::forward(args)...); - } - - template - void error(format_string_t fmt, Args &&...args) - { - log(level::err, fmt, std::forward(args)...); - } - - template - void critical(format_string_t fmt, Args &&...args) - { - log(level::critical, fmt, std::forward(args)...); - } - -#ifdef SPDLOG_WCHAR_TO_UTF8_SUPPORT - template - void log(source_loc loc, level::level_enum lvl, wformat_string_t fmt, Args &&...args) - { - log_(loc, lvl, details::to_string_view(fmt), std::forward(args)...); - } - - template - void log(level::level_enum lvl, wformat_string_t fmt, Args &&...args) - { - log(source_loc{}, lvl, fmt, std::forward(args)...); - } - - void log(log_clock::time_point log_time, source_loc loc, level::level_enum lvl, wstring_view_t msg) - { - bool log_enabled = should_log(lvl); - bool traceback_enabled = tracer_.enabled(); - if (!log_enabled && !traceback_enabled) - { - return; - } - - memory_buf_t buf; - details::os::wstr_to_utf8buf(wstring_view_t(msg.data(), msg.size()), buf); - details::log_msg log_msg(log_time, loc, name_, lvl, string_view_t(buf.data(), buf.size())); - log_it_(log_msg, log_enabled, traceback_enabled); - } - - void log(source_loc loc, level::level_enum lvl, wstring_view_t msg) - { - bool log_enabled = should_log(lvl); - bool traceback_enabled = tracer_.enabled(); - if (!log_enabled && !traceback_enabled) - { - return; - } - - memory_buf_t buf; - details::os::wstr_to_utf8buf(wstring_view_t(msg.data(), msg.size()), buf); - details::log_msg log_msg(loc, name_, lvl, string_view_t(buf.data(), buf.size())); - log_it_(log_msg, log_enabled, traceback_enabled); - } - - void log(level::level_enum lvl, wstring_view_t msg) - { - log(source_loc{}, lvl, msg); - } - - template - void trace(wformat_string_t fmt, Args &&...args) - { - log(level::trace, fmt, std::forward(args)...); - } - - template - void debug(wformat_string_t fmt, Args &&...args) - { - log(level::debug, fmt, std::forward(args)...); - } - - template - void info(wformat_string_t fmt, Args &&...args) - { - log(level::info, fmt, std::forward(args)...); - } - - template - void warn(wformat_string_t fmt, Args &&...args) - { - log(level::warn, fmt, std::forward(args)...); - } - - template - void error(wformat_string_t fmt, Args &&...args) - { - log(level::err, fmt, std::forward(args)...); - } - - template - void critical(wformat_string_t fmt, Args &&...args) - { - log(level::critical, fmt, std::forward(args)...); - } -#endif - - template - void trace(const T &msg) - { - log(level::trace, msg); - } - - template - void debug(const T &msg) - { - log(level::debug, msg); - } - - template - void info(const T &msg) - { - log(level::info, msg); - } - - template - void warn(const T &msg) - { - log(level::warn, msg); - } - - template - void error(const T &msg) - { - log(level::err, msg); - } - - template - void critical(const T &msg) - { - log(level::critical, msg); - } - - // return true logging is enabled for the given level. - bool should_log(level::level_enum msg_level) const - { - return msg_level >= level_.load(std::memory_order_relaxed); - } - - // return true if backtrace logging is enabled. - bool should_backtrace() const - { - return tracer_.enabled(); - } - - void set_level(level::level_enum log_level); - - level::level_enum level() const; - - const std::string &name() const; - - // set formatting for the sinks in this logger. - // each sink will get a separate instance of the formatter object. - void set_formatter(std::unique_ptr f); - - // set formatting for the sinks in this logger. - // equivalent to - // set_formatter(make_unique(pattern, time_type)) - // Note: each sink will get a new instance of a formatter object, replacing the old one. - void set_pattern(std::string pattern, pattern_time_type time_type = pattern_time_type::local); - - // backtrace support. - // efficiently store all debug/trace messages in a circular buffer until needed for debugging. - void enable_backtrace(size_t n_messages); - void disable_backtrace(); - void dump_backtrace(); - - // flush functions - void flush(); - void flush_on(level::level_enum log_level); - level::level_enum flush_level() const; - - // sinks - const std::vector &sinks() const; - - std::vector &sinks(); - - // error handler - void set_error_handler(err_handler); - - // create new logger with same sinks and configuration. - virtual std::shared_ptr clone(std::string logger_name); - -protected: - std::string name_; - std::vector sinks_; - spdlog::level_t level_{level::info}; - spdlog::level_t flush_level_{level::off}; - err_handler custom_err_handler_{nullptr}; - details::backtracer tracer_; - - // common implementation for after templated public api has been resolved - template - void log_(source_loc loc, level::level_enum lvl, string_view_t fmt, Args &&...args) - { - bool log_enabled = should_log(lvl); - bool traceback_enabled = tracer_.enabled(); - if (!log_enabled && !traceback_enabled) - { - return; - } - SPDLOG_TRY - { - memory_buf_t buf; -#ifdef SPDLOG_USE_STD_FORMAT - fmt_lib::vformat_to(std::back_inserter(buf), fmt, fmt_lib::make_format_args(args...)); -#else - fmt::vformat_to(std::back_inserter(buf), fmt, fmt::make_format_args(args...)); -#endif - - details::log_msg log_msg(loc, name_, lvl, string_view_t(buf.data(), buf.size())); - log_it_(log_msg, log_enabled, traceback_enabled); - } - SPDLOG_LOGGER_CATCH(loc) - } - -#ifdef SPDLOG_WCHAR_TO_UTF8_SUPPORT - template - void log_(source_loc loc, level::level_enum lvl, wstring_view_t fmt, Args &&...args) - { - bool log_enabled = should_log(lvl); - bool traceback_enabled = tracer_.enabled(); - if (!log_enabled && !traceback_enabled) - { - return; - } - SPDLOG_TRY - { - // format to wmemory_buffer and convert to utf8 - wmemory_buf_t wbuf; - fmt_lib::vformat_to(std::back_inserter(wbuf), fmt, fmt_lib::make_format_args(args...)); - - memory_buf_t buf; - details::os::wstr_to_utf8buf(wstring_view_t(wbuf.data(), wbuf.size()), buf); - details::log_msg log_msg(loc, name_, lvl, string_view_t(buf.data(), buf.size())); - log_it_(log_msg, log_enabled, traceback_enabled); - } - SPDLOG_LOGGER_CATCH(loc) - } -#endif // SPDLOG_WCHAR_TO_UTF8_SUPPORT - - // log the given message (if the given log level is high enough), - // and save backtrace (if backtrace is enabled). - void log_it_(const details::log_msg &log_msg, bool log_enabled, bool traceback_enabled); - virtual void sink_it_(const details::log_msg &msg); - virtual void flush_(); - void dump_backtrace_(); - bool should_flush_(const details::log_msg &msg); - - // handle errors during logging. - // default handler prints the error to stderr at max rate of 1 message/sec. - void err_handler_(const std::string &msg); -}; - -void swap(logger &a, logger &b); - -} // namespace spdlog - -#ifdef SPDLOG_HEADER_ONLY -# include "logger-inl.h" -#endif diff --git a/tpl/spdlog/include/spdlog/pattern_formatter-inl.h b/tpl/spdlog/include/spdlog/pattern_formatter-inl.h deleted file mode 100644 index 01afbe6..0000000 --- a/tpl/spdlog/include/spdlog/pattern_formatter-inl.h +++ /dev/null @@ -1,1436 +0,0 @@ -// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. -// Distributed under the MIT License (http://opensource.org/licenses/MIT) - -#pragma once - -#ifndef SPDLOG_HEADER_ONLY -# include -#endif - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace spdlog { -namespace details { - -/////////////////////////////////////////////////////////////////////// -// name & level pattern appender -/////////////////////////////////////////////////////////////////////// - -class scoped_padder -{ -public: - scoped_padder(size_t wrapped_size, const padding_info &padinfo, memory_buf_t &dest) - : padinfo_(padinfo) - , dest_(dest) - { - remaining_pad_ = static_cast(padinfo.width_) - static_cast(wrapped_size); - if (remaining_pad_ <= 0) - { - return; - } - - if (padinfo_.side_ == padding_info::pad_side::left) - { - pad_it(remaining_pad_); - remaining_pad_ = 0; - } - else if (padinfo_.side_ == padding_info::pad_side::center) - { - auto half_pad = remaining_pad_ / 2; - auto reminder = remaining_pad_ & 1; - pad_it(half_pad); - remaining_pad_ = half_pad + reminder; // for the right side - } - } - - template - static unsigned int count_digits(T n) - { - return fmt_helper::count_digits(n); - } - - ~scoped_padder() - { - if (remaining_pad_ >= 0) - { - pad_it(remaining_pad_); - } - else if (padinfo_.truncate_) - { - long new_size = static_cast(dest_.size()) + remaining_pad_; - dest_.resize(static_cast(new_size)); - } - } - -private: - void pad_it(long count) - { - fmt_helper::append_string_view(string_view_t(spaces_.data(), static_cast(count)), dest_); - } - - const padding_info &padinfo_; - memory_buf_t &dest_; - long remaining_pad_; - string_view_t spaces_{" ", 64}; -}; - -struct null_scoped_padder -{ - null_scoped_padder(size_t /*wrapped_size*/, const padding_info & /*padinfo*/, memory_buf_t & /*dest*/) {} - - template - static unsigned int count_digits(T /* number */) - { - return 0; - } -}; - -template -class name_formatter final : public flag_formatter -{ -public: - explicit name_formatter(padding_info padinfo) - : flag_formatter(padinfo) - {} - - void format(const details::log_msg &msg, const std::tm &, memory_buf_t &dest) override - { - ScopedPadder p(msg.logger_name.size(), padinfo_, dest); - fmt_helper::append_string_view(msg.logger_name, dest); - } -}; - -// log level appender -template -class level_formatter final : public flag_formatter -{ -public: - explicit level_formatter(padding_info padinfo) - : flag_formatter(padinfo) - {} - - void format(const details::log_msg &msg, const std::tm &, memory_buf_t &dest) override - { - const string_view_t &level_name = level::to_string_view(msg.level); - ScopedPadder p(level_name.size(), padinfo_, dest); - fmt_helper::append_string_view(level_name, dest); - } -}; - -// short log level appender -template -class short_level_formatter final : public flag_formatter -{ -public: - explicit short_level_formatter(padding_info padinfo) - : flag_formatter(padinfo) - {} - - void format(const details::log_msg &msg, const std::tm &, memory_buf_t &dest) override - { - string_view_t level_name{level::to_short_c_str(msg.level)}; - ScopedPadder p(level_name.size(), padinfo_, dest); - fmt_helper::append_string_view(level_name, dest); - } -}; - -/////////////////////////////////////////////////////////////////////// -// 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 std::array days{{"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"}}; - -template -class a_formatter final : public flag_formatter -{ -public: - explicit a_formatter(padding_info padinfo) - : flag_formatter(padinfo) - {} - - void format(const details::log_msg &, const std::tm &tm_time, memory_buf_t &dest) override - { - string_view_t field_value{days[static_cast(tm_time.tm_wday)]}; - ScopedPadder p(field_value.size(), padinfo_, dest); - fmt_helper::append_string_view(field_value, dest); - } -}; - -// Full weekday name -static std::array full_days{{"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"}}; - -template -class A_formatter : public flag_formatter -{ -public: - explicit A_formatter(padding_info padinfo) - : flag_formatter(padinfo) - {} - - void format(const details::log_msg &, const std::tm &tm_time, memory_buf_t &dest) override - { - string_view_t field_value{full_days[static_cast(tm_time.tm_wday)]}; - ScopedPadder p(field_value.size(), padinfo_, dest); - fmt_helper::append_string_view(field_value, dest); - } -}; - -// Abbreviated month -static const std::array months{{"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sept", "Oct", "Nov", "Dec"}}; - -template -class b_formatter final : public flag_formatter -{ -public: - explicit b_formatter(padding_info padinfo) - : flag_formatter(padinfo) - {} - - void format(const details::log_msg &, const std::tm &tm_time, memory_buf_t &dest) override - { - string_view_t field_value{months[static_cast(tm_time.tm_mon)]}; - ScopedPadder p(field_value.size(), padinfo_, dest); - fmt_helper::append_string_view(field_value, dest); - } -}; - -// Full month name -static const std::array full_months{ - {"January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"}}; - -template -class B_formatter final : public flag_formatter -{ -public: - explicit B_formatter(padding_info padinfo) - : flag_formatter(padinfo) - {} - - void format(const details::log_msg &, const std::tm &tm_time, memory_buf_t &dest) override - { - string_view_t field_value{full_months[static_cast(tm_time.tm_mon)]}; - ScopedPadder p(field_value.size(), padinfo_, dest); - fmt_helper::append_string_view(field_value, dest); - } -}; - -// Date and time representation (Thu Aug 23 15:35:46 2014) -template -class c_formatter final : public flag_formatter -{ -public: - explicit c_formatter(padding_info padinfo) - : flag_formatter(padinfo) - {} - - void format(const details::log_msg &, const std::tm &tm_time, memory_buf_t &dest) override - { - const size_t field_size = 24; - ScopedPadder p(field_size, padinfo_, dest); - - fmt_helper::append_string_view(days[static_cast(tm_time.tm_wday)], dest); - dest.push_back(' '); - fmt_helper::append_string_view(months[static_cast(tm_time.tm_mon)], dest); - dest.push_back(' '); - fmt_helper::append_int(tm_time.tm_mday, dest); - dest.push_back(' '); - // time - - fmt_helper::pad2(tm_time.tm_hour, dest); - dest.push_back(':'); - fmt_helper::pad2(tm_time.tm_min, dest); - dest.push_back(':'); - fmt_helper::pad2(tm_time.tm_sec, dest); - dest.push_back(' '); - fmt_helper::append_int(tm_time.tm_year + 1900, dest); - } -}; - -// year - 2 digit -template -class C_formatter final : public flag_formatter -{ -public: - explicit C_formatter(padding_info padinfo) - : flag_formatter(padinfo) - {} - - void format(const details::log_msg &, const std::tm &tm_time, memory_buf_t &dest) override - { - const size_t field_size = 2; - ScopedPadder p(field_size, padinfo_, dest); - fmt_helper::pad2(tm_time.tm_year % 100, dest); - } -}; - -// Short MM/DD/YY date, equivalent to %m/%d/%y 08/23/01 -template -class D_formatter final : public flag_formatter -{ -public: - explicit D_formatter(padding_info padinfo) - : flag_formatter(padinfo) - {} - - void format(const details::log_msg &, const std::tm &tm_time, memory_buf_t &dest) override - { - const size_t field_size = 10; - ScopedPadder p(field_size, padinfo_, dest); - - fmt_helper::pad2(tm_time.tm_mon + 1, dest); - dest.push_back('/'); - fmt_helper::pad2(tm_time.tm_mday, dest); - dest.push_back('/'); - fmt_helper::pad2(tm_time.tm_year % 100, dest); - } -}; - -// year - 4 digit -template -class Y_formatter final : public flag_formatter -{ -public: - explicit Y_formatter(padding_info padinfo) - : flag_formatter(padinfo) - {} - - void format(const details::log_msg &, const std::tm &tm_time, memory_buf_t &dest) override - { - const size_t field_size = 4; - ScopedPadder p(field_size, padinfo_, dest); - fmt_helper::append_int(tm_time.tm_year + 1900, dest); - } -}; - -// month 1-12 -template -class m_formatter final : public flag_formatter -{ -public: - explicit m_formatter(padding_info padinfo) - : flag_formatter(padinfo) - {} - - void format(const details::log_msg &, const std::tm &tm_time, memory_buf_t &dest) override - { - const size_t field_size = 2; - ScopedPadder p(field_size, padinfo_, dest); - fmt_helper::pad2(tm_time.tm_mon + 1, dest); - } -}; - -// day of month 1-31 -template -class d_formatter final : public flag_formatter -{ -public: - explicit d_formatter(padding_info padinfo) - : flag_formatter(padinfo) - {} - - void format(const details::log_msg &, const std::tm &tm_time, memory_buf_t &dest) override - { - const size_t field_size = 2; - ScopedPadder p(field_size, padinfo_, dest); - fmt_helper::pad2(tm_time.tm_mday, dest); - } -}; - -// hours in 24 format 0-23 -template -class H_formatter final : public flag_formatter -{ -public: - explicit H_formatter(padding_info padinfo) - : flag_formatter(padinfo) - {} - - void format(const details::log_msg &, const std::tm &tm_time, memory_buf_t &dest) override - { - const size_t field_size = 2; - ScopedPadder p(field_size, padinfo_, dest); - fmt_helper::pad2(tm_time.tm_hour, dest); - } -}; - -// hours in 12 format 1-12 -template -class I_formatter final : public flag_formatter -{ -public: - explicit I_formatter(padding_info padinfo) - : flag_formatter(padinfo) - {} - - void format(const details::log_msg &, const std::tm &tm_time, memory_buf_t &dest) override - { - const size_t field_size = 2; - ScopedPadder p(field_size, padinfo_, dest); - fmt_helper::pad2(to12h(tm_time), dest); - } -}; - -// minutes 0-59 -template -class M_formatter final : public flag_formatter -{ -public: - explicit M_formatter(padding_info padinfo) - : flag_formatter(padinfo) - {} - - void format(const details::log_msg &, const std::tm &tm_time, memory_buf_t &dest) override - { - const size_t field_size = 2; - ScopedPadder p(field_size, padinfo_, dest); - fmt_helper::pad2(tm_time.tm_min, dest); - } -}; - -// seconds 0-59 -template -class S_formatter final : public flag_formatter -{ -public: - explicit S_formatter(padding_info padinfo) - : flag_formatter(padinfo) - {} - - void format(const details::log_msg &, const std::tm &tm_time, memory_buf_t &dest) override - { - const size_t field_size = 2; - ScopedPadder p(field_size, padinfo_, dest); - fmt_helper::pad2(tm_time.tm_sec, dest); - } -}; - -// milliseconds -template -class e_formatter final : public flag_formatter -{ -public: - explicit e_formatter(padding_info padinfo) - : flag_formatter(padinfo) - {} - - void format(const details::log_msg &msg, const std::tm &, memory_buf_t &dest) override - { - auto millis = fmt_helper::time_fraction(msg.time); - const size_t field_size = 3; - ScopedPadder p(field_size, padinfo_, dest); - fmt_helper::pad3(static_cast(millis.count()), dest); - } -}; - -// microseconds -template -class f_formatter final : public flag_formatter -{ -public: - explicit f_formatter(padding_info padinfo) - : flag_formatter(padinfo) - {} - - void format(const details::log_msg &msg, const std::tm &, memory_buf_t &dest) override - { - auto micros = fmt_helper::time_fraction(msg.time); - - const size_t field_size = 6; - ScopedPadder p(field_size, padinfo_, dest); - fmt_helper::pad6(static_cast(micros.count()), dest); - } -}; - -// nanoseconds -template -class F_formatter final : public flag_formatter -{ -public: - explicit F_formatter(padding_info padinfo) - : flag_formatter(padinfo) - {} - - void format(const details::log_msg &msg, const std::tm &, memory_buf_t &dest) override - { - auto ns = fmt_helper::time_fraction(msg.time); - const size_t field_size = 9; - ScopedPadder p(field_size, padinfo_, dest); - fmt_helper::pad9(static_cast(ns.count()), dest); - } -}; - -// seconds since epoch -template -class E_formatter final : public flag_formatter -{ -public: - explicit E_formatter(padding_info padinfo) - : flag_formatter(padinfo) - {} - - void format(const details::log_msg &msg, const std::tm &, memory_buf_t &dest) override - { - const size_t field_size = 10; - ScopedPadder p(field_size, padinfo_, dest); - auto duration = msg.time.time_since_epoch(); - auto seconds = std::chrono::duration_cast(duration).count(); - fmt_helper::append_int(seconds, dest); - } -}; - -// AM/PM -template -class p_formatter final : public flag_formatter -{ -public: - explicit p_formatter(padding_info padinfo) - : flag_formatter(padinfo) - {} - - void format(const details::log_msg &, const std::tm &tm_time, memory_buf_t &dest) override - { - const size_t field_size = 2; - ScopedPadder p(field_size, padinfo_, dest); - fmt_helper::append_string_view(ampm(tm_time), dest); - } -}; - -// 12 hour clock 02:55:02 pm -template -class r_formatter final : public flag_formatter -{ -public: - explicit r_formatter(padding_info padinfo) - : flag_formatter(padinfo) - {} - - void format(const details::log_msg &, const std::tm &tm_time, memory_buf_t &dest) override - { - const size_t field_size = 11; - ScopedPadder p(field_size, padinfo_, dest); - - fmt_helper::pad2(to12h(tm_time), dest); - dest.push_back(':'); - fmt_helper::pad2(tm_time.tm_min, dest); - dest.push_back(':'); - fmt_helper::pad2(tm_time.tm_sec, dest); - dest.push_back(' '); - fmt_helper::append_string_view(ampm(tm_time), dest); - } -}; - -// 24-hour HH:MM time, equivalent to %H:%M -template -class R_formatter final : public flag_formatter -{ -public: - explicit R_formatter(padding_info padinfo) - : flag_formatter(padinfo) - {} - - void format(const details::log_msg &, const std::tm &tm_time, memory_buf_t &dest) override - { - const size_t field_size = 5; - ScopedPadder p(field_size, padinfo_, dest); - - fmt_helper::pad2(tm_time.tm_hour, dest); - dest.push_back(':'); - fmt_helper::pad2(tm_time.tm_min, dest); - } -}; - -// ISO 8601 time format (HH:MM:SS), equivalent to %H:%M:%S -template -class T_formatter final : public flag_formatter -{ -public: - explicit T_formatter(padding_info padinfo) - : flag_formatter(padinfo) - {} - - void format(const details::log_msg &, const std::tm &tm_time, memory_buf_t &dest) override - { - const size_t field_size = 8; - ScopedPadder p(field_size, padinfo_, dest); - - fmt_helper::pad2(tm_time.tm_hour, dest); - dest.push_back(':'); - fmt_helper::pad2(tm_time.tm_min, dest); - dest.push_back(':'); - fmt_helper::pad2(tm_time.tm_sec, dest); - } -}; - -// ISO 8601 offset from UTC in timezone (+-HH:MM) -template -class z_formatter final : public flag_formatter -{ -public: - explicit z_formatter(padding_info padinfo) - : flag_formatter(padinfo) - {} - - z_formatter() = default; - z_formatter(const z_formatter &) = delete; - z_formatter &operator=(const z_formatter &) = delete; - - void format(const details::log_msg &msg, const std::tm &tm_time, memory_buf_t &dest) override - { - const size_t field_size = 6; - ScopedPadder p(field_size, padinfo_, dest); - - auto total_minutes = get_cached_offset(msg, tm_time); - bool is_negative = total_minutes < 0; - if (is_negative) - { - total_minutes = -total_minutes; - dest.push_back('-'); - } - else - { - dest.push_back('+'); - } - - fmt_helper::pad2(total_minutes / 60, dest); // hours - dest.push_back(':'); - fmt_helper::pad2(total_minutes % 60, dest); // minutes - } - -private: - log_clock::time_point last_update_{std::chrono::seconds(0)}; - int offset_minutes_{0}; - - int get_cached_offset(const log_msg &msg, const std::tm &tm_time) - { - // refresh every 10 seconds - if (msg.time - last_update_ >= std::chrono::seconds(10)) - { - offset_minutes_ = os::utc_minutes_offset(tm_time); - last_update_ = msg.time; - } - return offset_minutes_; - } -}; - -// Thread id -template -class t_formatter final : public flag_formatter -{ -public: - explicit t_formatter(padding_info padinfo) - : flag_formatter(padinfo) - {} - - void format(const details::log_msg &msg, const std::tm &, memory_buf_t &dest) override - { - const auto field_size = ScopedPadder::count_digits(msg.thread_id); - ScopedPadder p(field_size, padinfo_, dest); - fmt_helper::append_int(msg.thread_id, dest); - } -}; - -// Current pid -template -class pid_formatter final : public flag_formatter -{ -public: - explicit pid_formatter(padding_info padinfo) - : flag_formatter(padinfo) - {} - - void format(const details::log_msg &, const std::tm &, memory_buf_t &dest) override - { - const auto pid = static_cast(details::os::pid()); - auto field_size = ScopedPadder::count_digits(pid); - ScopedPadder p(field_size, padinfo_, dest); - fmt_helper::append_int(pid, dest); - } -}; - -template -class v_formatter final : public flag_formatter -{ -public: - explicit v_formatter(padding_info padinfo) - : flag_formatter(padinfo) - {} - - void format(const details::log_msg &msg, const std::tm &, memory_buf_t &dest) override - { - ScopedPadder p(msg.payload.size(), padinfo_, dest); - fmt_helper::append_string_view(msg.payload, dest); - } -}; - -class ch_formatter final : public flag_formatter -{ -public: - explicit ch_formatter(char ch) - : ch_(ch) - {} - - void format(const details::log_msg &, const std::tm &, memory_buf_t &dest) override - { - dest.push_back(ch_); - } - -private: - char ch_; -}; - -// aggregate user chars to display as is -class aggregate_formatter final : public flag_formatter -{ -public: - aggregate_formatter() = default; - - void add_ch(char ch) - { - str_ += ch; - } - void format(const details::log_msg &, const std::tm &, memory_buf_t &dest) override - { - fmt_helper::append_string_view(str_, dest); - } - -private: - std::string str_; -}; - -// mark the color range. expect it to be in the form of "%^colored text%$" -class color_start_formatter final : public flag_formatter -{ -public: - explicit color_start_formatter(padding_info padinfo) - : flag_formatter(padinfo) - {} - - void format(const details::log_msg &msg, const std::tm &, memory_buf_t &dest) override - { - msg.color_range_start = dest.size(); - } -}; - -class color_stop_formatter final : public flag_formatter -{ -public: - explicit color_stop_formatter(padding_info padinfo) - : flag_formatter(padinfo) - {} - - void format(const details::log_msg &msg, const std::tm &, memory_buf_t &dest) override - { - msg.color_range_end = dest.size(); - } -}; - -// print source location -template -class source_location_formatter final : public flag_formatter -{ -public: - explicit source_location_formatter(padding_info padinfo) - : flag_formatter(padinfo) - {} - - void format(const details::log_msg &msg, const std::tm &, memory_buf_t &dest) override - { - if (msg.source.empty()) - { - ScopedPadder p(0, padinfo_, dest); - return; - } - - size_t text_size; - if (padinfo_.enabled()) - { - // calc text size for padding based on "filename:line" - text_size = std::char_traits::length(msg.source.filename) + ScopedPadder::count_digits(msg.source.line) + 1; - } - else - { - text_size = 0; - } - - ScopedPadder p(text_size, padinfo_, dest); - fmt_helper::append_string_view(msg.source.filename, dest); - dest.push_back(':'); - fmt_helper::append_int(msg.source.line, dest); - } -}; - -// print source filename -template -class source_filename_formatter final : public flag_formatter -{ -public: - explicit source_filename_formatter(padding_info padinfo) - : flag_formatter(padinfo) - {} - - void format(const details::log_msg &msg, const std::tm &, memory_buf_t &dest) override - { - if (msg.source.empty()) - { - ScopedPadder p(0, padinfo_, dest); - return; - } - size_t text_size = padinfo_.enabled() ? std::char_traits::length(msg.source.filename) : 0; - ScopedPadder p(text_size, padinfo_, dest); - fmt_helper::append_string_view(msg.source.filename, dest); - } -}; - -template -class short_filename_formatter final : public flag_formatter -{ -public: - explicit short_filename_formatter(padding_info padinfo) - : flag_formatter(padinfo) - {} - -#ifdef _MSC_VER -# pragma warning(push) -# pragma warning(disable : 4127) // consider using 'if constexpr' instead -#endif // _MSC_VER - static const char *basename(const char *filename) - { - // if the size is 2 (1 character + null terminator) we can use the more efficient strrchr - // the branch will be elided by optimizations - if (sizeof(os::folder_seps) == 2) - { - const char *rv = std::strrchr(filename, os::folder_seps[0]); - return rv != nullptr ? rv + 1 : filename; - } - else - { - const std::reverse_iterator begin(filename + std::strlen(filename)); - const std::reverse_iterator end(filename); - - const auto it = std::find_first_of(begin, end, std::begin(os::folder_seps), std::end(os::folder_seps) - 1); - return it != end ? it.base() : filename; - } - } -#ifdef _MSC_VER -# pragma warning(pop) -#endif // _MSC_VER - - void format(const details::log_msg &msg, const std::tm &, memory_buf_t &dest) override - { - if (msg.source.empty()) - { - ScopedPadder p(0, padinfo_, dest); - return; - } - auto filename = basename(msg.source.filename); - size_t text_size = padinfo_.enabled() ? std::char_traits::length(filename) : 0; - ScopedPadder p(text_size, padinfo_, dest); - fmt_helper::append_string_view(filename, dest); - } -}; - -template -class source_linenum_formatter final : public flag_formatter -{ -public: - explicit source_linenum_formatter(padding_info padinfo) - : flag_formatter(padinfo) - {} - - void format(const details::log_msg &msg, const std::tm &, memory_buf_t &dest) override - { - if (msg.source.empty()) - { - ScopedPadder p(0, padinfo_, dest); - return; - } - - auto field_size = ScopedPadder::count_digits(msg.source.line); - ScopedPadder p(field_size, padinfo_, dest); - fmt_helper::append_int(msg.source.line, dest); - } -}; - -// print source funcname -template -class source_funcname_formatter final : public flag_formatter -{ -public: - explicit source_funcname_formatter(padding_info padinfo) - : flag_formatter(padinfo) - {} - - void format(const details::log_msg &msg, const std::tm &, memory_buf_t &dest) override - { - if (msg.source.empty()) - { - ScopedPadder p(0, padinfo_, dest); - return; - } - size_t text_size = padinfo_.enabled() ? std::char_traits::length(msg.source.funcname) : 0; - ScopedPadder p(text_size, padinfo_, dest); - fmt_helper::append_string_view(msg.source.funcname, dest); - } -}; - -// print elapsed time since last message -template -class elapsed_formatter final : public flag_formatter -{ -public: - using DurationUnits = Units; - - explicit elapsed_formatter(padding_info padinfo) - : flag_formatter(padinfo) - , last_message_time_(log_clock::now()) - {} - - void format(const details::log_msg &msg, const std::tm &, memory_buf_t &dest) override - { - auto delta = (std::max)(msg.time - last_message_time_, log_clock::duration::zero()); - auto delta_units = std::chrono::duration_cast(delta); - last_message_time_ = msg.time; - auto delta_count = static_cast(delta_units.count()); - auto n_digits = static_cast(ScopedPadder::count_digits(delta_count)); - ScopedPadder p(n_digits, padinfo_, dest); - fmt_helper::append_int(delta_count, dest); - } - -private: - log_clock::time_point last_message_time_; -}; - -// Full info formatter -// pattern: [%Y-%m-%d %H:%M:%S.%e] [%n] [%l] [%s:%#] %v -class full_formatter final : public flag_formatter -{ -public: - explicit full_formatter(padding_info padinfo) - : flag_formatter(padinfo) - {} - - void format(const details::log_msg &msg, const std::tm &tm_time, memory_buf_t &dest) override - { - using std::chrono::duration_cast; - using std::chrono::milliseconds; - using std::chrono::seconds; - - // cache the date/time part for the next second. - auto duration = msg.time.time_since_epoch(); - auto secs = duration_cast(duration); - - if (cache_timestamp_ != secs || cached_datetime_.size() == 0) - { - cached_datetime_.clear(); - cached_datetime_.push_back('['); - fmt_helper::append_int(tm_time.tm_year + 1900, cached_datetime_); - cached_datetime_.push_back('-'); - - fmt_helper::pad2(tm_time.tm_mon + 1, cached_datetime_); - cached_datetime_.push_back('-'); - - fmt_helper::pad2(tm_time.tm_mday, cached_datetime_); - cached_datetime_.push_back(' '); - - fmt_helper::pad2(tm_time.tm_hour, cached_datetime_); - cached_datetime_.push_back(':'); - - fmt_helper::pad2(tm_time.tm_min, cached_datetime_); - cached_datetime_.push_back(':'); - - fmt_helper::pad2(tm_time.tm_sec, cached_datetime_); - cached_datetime_.push_back('.'); - - cache_timestamp_ = secs; - } - dest.append(cached_datetime_.begin(), cached_datetime_.end()); - - auto millis = fmt_helper::time_fraction(msg.time); - fmt_helper::pad3(static_cast(millis.count()), dest); - dest.push_back(']'); - dest.push_back(' '); - - // append logger name if exists - if (msg.logger_name.size() > 0) - { - dest.push_back('['); - fmt_helper::append_string_view(msg.logger_name, dest); - dest.push_back(']'); - dest.push_back(' '); - } - - dest.push_back('['); - // wrap the level name with color - msg.color_range_start = dest.size(); - // fmt_helper::append_string_view(level::to_c_str(msg.level), dest); - fmt_helper::append_string_view(level::to_string_view(msg.level), dest); - msg.color_range_end = dest.size(); - dest.push_back(']'); - dest.push_back(' '); - - // add source location if present - if (!msg.source.empty()) - { - dest.push_back('['); - const char *filename = details::short_filename_formatter::basename(msg.source.filename); - fmt_helper::append_string_view(filename, dest); - dest.push_back(':'); - fmt_helper::append_int(msg.source.line, dest); - dest.push_back(']'); - dest.push_back(' '); - } - // fmt_helper::append_string_view(msg.msg(), dest); - fmt_helper::append_string_view(msg.payload, dest); - } - -private: - std::chrono::seconds cache_timestamp_{0}; - memory_buf_t cached_datetime_; -}; - -} // namespace details - -SPDLOG_INLINE pattern_formatter::pattern_formatter( - std::string pattern, pattern_time_type time_type, std::string eol, custom_flags custom_user_flags) - : pattern_(std::move(pattern)) - , eol_(std::move(eol)) - , pattern_time_type_(time_type) - , need_localtime_(false) - , last_log_secs_(0) - , custom_handlers_(std::move(custom_user_flags)) -{ - std::memset(&cached_tm_, 0, sizeof(cached_tm_)); - compile_pattern_(pattern_); -} - -// use by default full formatter for if pattern is not given -SPDLOG_INLINE pattern_formatter::pattern_formatter(pattern_time_type time_type, std::string eol) - : pattern_("%+") - , eol_(std::move(eol)) - , pattern_time_type_(time_type) - , need_localtime_(true) - , last_log_secs_(0) -{ - std::memset(&cached_tm_, 0, sizeof(cached_tm_)); - formatters_.push_back(details::make_unique(details::padding_info{})); -} - -SPDLOG_INLINE std::unique_ptr pattern_formatter::clone() const -{ - custom_flags cloned_custom_formatters; - for (auto &it : custom_handlers_) - { - cloned_custom_formatters[it.first] = it.second->clone(); - } - auto cloned = details::make_unique(pattern_, pattern_time_type_, eol_, std::move(cloned_custom_formatters)); - cloned->need_localtime(need_localtime_); -#if defined(__GNUC__) && __GNUC__ < 5 - return std::move(cloned); -#else - return cloned; -#endif -} - -SPDLOG_INLINE void pattern_formatter::format(const details::log_msg &msg, memory_buf_t &dest) -{ - if (need_localtime_) - { - const auto secs = std::chrono::duration_cast(msg.time.time_since_epoch()); - if (secs != last_log_secs_) - { - cached_tm_ = get_time_(msg); - last_log_secs_ = secs; - } - } - - for (auto &f : formatters_) - { - f->format(msg, cached_tm_, dest); - } - // write eol - details::fmt_helper::append_string_view(eol_, dest); -} - -SPDLOG_INLINE void pattern_formatter::set_pattern(std::string pattern) -{ - pattern_ = std::move(pattern); - need_localtime_ = false; - compile_pattern_(pattern_); -} - -SPDLOG_INLINE void pattern_formatter::need_localtime(bool need) -{ - need_localtime_ = need; -} - -SPDLOG_INLINE std::tm pattern_formatter::get_time_(const details::log_msg &msg) -{ - if (pattern_time_type_ == pattern_time_type::local) - { - return details::os::localtime(log_clock::to_time_t(msg.time)); - } - return details::os::gmtime(log_clock::to_time_t(msg.time)); -} - -template -SPDLOG_INLINE void pattern_formatter::handle_flag_(char flag, details::padding_info padding) -{ - // process custom flags - auto it = custom_handlers_.find(flag); - if (it != custom_handlers_.end()) - { - auto custom_handler = it->second->clone(); - custom_handler->set_padding_info(padding); - formatters_.push_back(std::move(custom_handler)); - return; - } - - // process built-in flags - switch (flag) - { - case ('+'): // default formatter - formatters_.push_back(details::make_unique(padding)); - need_localtime_ = true; - break; - - case 'n': // logger name - formatters_.push_back(details::make_unique>(padding)); - break; - - case 'l': // level - formatters_.push_back(details::make_unique>(padding)); - break; - - case 'L': // short level - formatters_.push_back(details::make_unique>(padding)); - break; - - case ('t'): // thread id - formatters_.push_back(details::make_unique>(padding)); - break; - - case ('v'): // the message text - formatters_.push_back(details::make_unique>(padding)); - break; - - case ('a'): // weekday - formatters_.push_back(details::make_unique>(padding)); - need_localtime_ = true; - break; - - case ('A'): // short weekday - formatters_.push_back(details::make_unique>(padding)); - need_localtime_ = true; - break; - - case ('b'): - case ('h'): // month - formatters_.push_back(details::make_unique>(padding)); - need_localtime_ = true; - break; - - case ('B'): // short month - formatters_.push_back(details::make_unique>(padding)); - need_localtime_ = true; - break; - - case ('c'): // datetime - formatters_.push_back(details::make_unique>(padding)); - need_localtime_ = true; - break; - - case ('C'): // year 2 digits - formatters_.push_back(details::make_unique>(padding)); - need_localtime_ = true; - break; - - case ('Y'): // year 4 digits - formatters_.push_back(details::make_unique>(padding)); - need_localtime_ = true; - break; - - case ('D'): - case ('x'): // datetime MM/DD/YY - formatters_.push_back(details::make_unique>(padding)); - need_localtime_ = true; - break; - - case ('m'): // month 1-12 - formatters_.push_back(details::make_unique>(padding)); - need_localtime_ = true; - break; - - case ('d'): // day of month 1-31 - formatters_.push_back(details::make_unique>(padding)); - need_localtime_ = true; - break; - - case ('H'): // hours 24 - formatters_.push_back(details::make_unique>(padding)); - need_localtime_ = true; - break; - - case ('I'): // hours 12 - formatters_.push_back(details::make_unique>(padding)); - need_localtime_ = true; - break; - - case ('M'): // minutes - formatters_.push_back(details::make_unique>(padding)); - need_localtime_ = true; - break; - - case ('S'): // seconds - formatters_.push_back(details::make_unique>(padding)); - need_localtime_ = true; - break; - - case ('e'): // milliseconds - formatters_.push_back(details::make_unique>(padding)); - break; - - case ('f'): // microseconds - formatters_.push_back(details::make_unique>(padding)); - break; - - case ('F'): // nanoseconds - formatters_.push_back(details::make_unique>(padding)); - break; - - case ('E'): // seconds since epoch - formatters_.push_back(details::make_unique>(padding)); - break; - - case ('p'): // am/pm - formatters_.push_back(details::make_unique>(padding)); - need_localtime_ = true; - break; - - case ('r'): // 12 hour clock 02:55:02 pm - formatters_.push_back(details::make_unique>(padding)); - need_localtime_ = true; - break; - - case ('R'): // 24-hour HH:MM time - formatters_.push_back(details::make_unique>(padding)); - need_localtime_ = true; - break; - - case ('T'): - case ('X'): // ISO 8601 time format (HH:MM:SS) - formatters_.push_back(details::make_unique>(padding)); - need_localtime_ = true; - break; - - case ('z'): // timezone - formatters_.push_back(details::make_unique>(padding)); - need_localtime_ = true; - break; - - case ('P'): // pid - formatters_.push_back(details::make_unique>(padding)); - break; - - case ('^'): // color range start - formatters_.push_back(details::make_unique(padding)); - break; - - case ('$'): // color range end - formatters_.push_back(details::make_unique(padding)); - break; - - case ('@'): // source location (filename:filenumber) - formatters_.push_back(details::make_unique>(padding)); - break; - - case ('s'): // short source filename - without directory name - formatters_.push_back(details::make_unique>(padding)); - break; - - case ('g'): // full source filename - formatters_.push_back(details::make_unique>(padding)); - break; - - case ('#'): // source line number - formatters_.push_back(details::make_unique>(padding)); - break; - - case ('!'): // source funcname - formatters_.push_back(details::make_unique>(padding)); - break; - - case ('%'): // % char - formatters_.push_back(details::make_unique('%')); - break; - - case ('u'): // elapsed time since last log message in nanos - formatters_.push_back(details::make_unique>(padding)); - break; - - case ('i'): // elapsed time since last log message in micros - formatters_.push_back(details::make_unique>(padding)); - break; - - case ('o'): // elapsed time since last log message in millis - formatters_.push_back(details::make_unique>(padding)); - break; - - case ('O'): // elapsed time since last log message in seconds - formatters_.push_back(details::make_unique>(padding)); - break; - - default: // Unknown flag appears as is - auto unknown_flag = details::make_unique(); - - if (!padding.truncate_) - { - unknown_flag->add_ch('%'); - unknown_flag->add_ch(flag); - formatters_.push_back((std::move(unknown_flag))); - } - // fix issue #1617 (prev char was '!' and should have been treated as funcname flag instead of truncating flag) - // spdlog::set_pattern("[%10!] %v") => "[ main] some message" - // spdlog::set_pattern("[%3!!] %v") => "[mai] some message" - else - { - padding.truncate_ = false; - formatters_.push_back(details::make_unique>(padding)); - unknown_flag->add_ch(flag); - formatters_.push_back((std::move(unknown_flag))); - } - - break; - } -} - -// Extract given pad spec (e.g. %8X, %=8X, %-8!X, %8!X, %=8!X, %-8!X, %+8!X) -// Advance the given it pass the end of the padding spec found (if any) -// Return padding. -SPDLOG_INLINE details::padding_info pattern_formatter::handle_padspec_(std::string::const_iterator &it, std::string::const_iterator end) -{ - using details::padding_info; - using details::scoped_padder; - const size_t max_width = 64; - if (it == end) - { - return padding_info{}; - } - - padding_info::pad_side side; - switch (*it) - { - case '-': - side = padding_info::pad_side::right; - ++it; - break; - case '=': - side = padding_info::pad_side::center; - ++it; - break; - default: - side = details::padding_info::pad_side::left; - break; - } - - if (it == end || !std::isdigit(static_cast(*it))) - { - return padding_info{}; // no padding if no digit found here - } - - auto width = static_cast(*it) - '0'; - for (++it; it != end && std::isdigit(static_cast(*it)); ++it) - { - auto digit = static_cast(*it) - '0'; - width = width * 10 + digit; - } - - // search for the optional truncate marker '!' - bool truncate; - if (it != end && *it == '!') - { - truncate = true; - ++it; - } - else - { - truncate = false; - } - return details::padding_info{std::min(width, max_width), side, truncate}; -} - -SPDLOG_INLINE void pattern_formatter::compile_pattern_(const std::string &pattern) -{ - auto end = pattern.end(); - std::unique_ptr user_chars; - formatters_.clear(); - 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)); - } - - auto padding = handle_padspec_(++it, end); - - if (it != end) - { - if (padding.enabled()) - { - handle_flag_(*it, padding); - } - else - { - handle_flag_(*it, padding); - } - } - else - { - break; - } - } - else // chars not following the % sign should be displayed as is - { - if (!user_chars) - { - user_chars = details::make_unique(); - } - user_chars->add_ch(*it); - } - } - if (user_chars) // append raw chars found so far - { - formatters_.push_back(std::move(user_chars)); - } -} -} // namespace spdlog diff --git a/tpl/spdlog/include/spdlog/pattern_formatter.h b/tpl/spdlog/include/spdlog/pattern_formatter.h deleted file mode 100644 index 4c87b21..0000000 --- a/tpl/spdlog/include/spdlog/pattern_formatter.h +++ /dev/null @@ -1,128 +0,0 @@ -// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. -// Distributed under the MIT License (http://opensource.org/licenses/MIT) - -#pragma once - -#include -#include -#include -#include - -#include -#include -#include - -#include -#include -#include - -namespace spdlog { -namespace details { - -// padding information. -struct padding_info -{ - enum class pad_side - { - left, - right, - center - }; - - padding_info() = default; - padding_info(size_t width, padding_info::pad_side side, bool truncate) - : width_(width) - , side_(side) - , truncate_(truncate) - , enabled_(true) - {} - - bool enabled() const - { - return enabled_; - } - size_t width_ = 0; - pad_side side_ = pad_side::left; - bool truncate_ = false; - bool enabled_ = false; -}; - -class SPDLOG_API flag_formatter -{ -public: - explicit flag_formatter(padding_info padinfo) - : padinfo_(padinfo) - {} - flag_formatter() = default; - virtual ~flag_formatter() = default; - virtual void format(const details::log_msg &msg, const std::tm &tm_time, memory_buf_t &dest) = 0; - -protected: - padding_info padinfo_; -}; - -} // namespace details - -class SPDLOG_API custom_flag_formatter : public details::flag_formatter -{ -public: - virtual std::unique_ptr clone() const = 0; - - void set_padding_info(const details::padding_info &padding) - { - flag_formatter::padinfo_ = padding; - } -}; - -class SPDLOG_API pattern_formatter final : public formatter -{ -public: - using custom_flags = std::unordered_map>; - - explicit pattern_formatter(std::string pattern, pattern_time_type time_type = pattern_time_type::local, - std::string eol = spdlog::details::os::default_eol, custom_flags custom_user_flags = custom_flags()); - - // use default pattern is not given - explicit pattern_formatter(pattern_time_type time_type = pattern_time_type::local, std::string eol = spdlog::details::os::default_eol); - - pattern_formatter(const pattern_formatter &other) = delete; - pattern_formatter &operator=(const pattern_formatter &other) = delete; - - std::unique_ptr clone() const override; - void format(const details::log_msg &msg, memory_buf_t &dest) override; - - template - pattern_formatter &add_flag(char flag, Args &&...args) - { - custom_handlers_[flag] = details::make_unique(std::forward(args)...); - return *this; - } - void set_pattern(std::string pattern); - void need_localtime(bool need = true); - -private: - std::string pattern_; - std::string eol_; - pattern_time_type pattern_time_type_; - bool need_localtime_; - std::tm cached_tm_; - std::chrono::seconds last_log_secs_; - std::vector> formatters_; - custom_flags custom_handlers_; - - std::tm get_time_(const details::log_msg &msg); - template - void handle_flag_(char flag, details::padding_info padding); - - // Extract given pad spec (e.g. %8X) - // Advance the given it pass the end of the padding spec found (if any) - // Return padding. - static details::padding_info handle_padspec_(std::string::const_iterator &it, std::string::const_iterator end); - - void compile_pattern_(const std::string &pattern); -}; -} // namespace spdlog - -#ifdef SPDLOG_HEADER_ONLY -# include "pattern_formatter-inl.h" -#endif diff --git a/tpl/spdlog/include/spdlog/sinks/android_sink.h b/tpl/spdlog/include/spdlog/sinks/android_sink.h deleted file mode 100644 index 0087e95..0000000 --- a/tpl/spdlog/include/spdlog/sinks/android_sink.h +++ /dev/null @@ -1,146 +0,0 @@ -// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. -// Distributed under the MIT License (http://opensource.org/licenses/MIT) - -#pragma once - -#ifdef __ANDROID__ - -# include -# include -# include -# include -# include - -# include -# include -# include -# include -# include -# include - -# if !defined(SPDLOG_ANDROID_RETRIES) -# define SPDLOG_ANDROID_RETRIES 2 -# endif - -namespace spdlog { -namespace sinks { - -/* - * Android sink - * (logging using __android_log_write or __android_log_buf_write depending on the specified BufferID) - */ -template -class android_sink final : public base_sink -{ -public: - explicit android_sink(std::string tag = "spdlog", bool use_raw_msg = false) - : tag_(std::move(tag)) - , use_raw_msg_(use_raw_msg) - {} - -protected: - void sink_it_(const details::log_msg &msg) override - { - const android_LogPriority priority = convert_to_android_(msg.level); - memory_buf_t formatted; - if (use_raw_msg_) - { - details::fmt_helper::append_string_view(msg.payload, formatted); - } - else - { - base_sink::formatter_->format(msg, formatted); - } - formatted.push_back('\0'); - const char *msg_output = formatted.data(); - - // See system/core/liblog/logger_write.c for explanation of return value - int ret = android_log(priority, tag_.c_str(), msg_output); - if (ret == -EPERM) - { - return; // !__android_log_is_loggable - } - int retry_count = 0; - while ((ret == -11 /*EAGAIN*/) && (retry_count < SPDLOG_ANDROID_RETRIES)) - { - details::os::sleep_for_millis(5); - ret = android_log(priority, tag_.c_str(), msg_output); - retry_count++; - } - - if (ret < 0) - { - throw_spdlog_ex("logging to Android failed", ret); - } - } - - void flush_() override {} - -private: - // There might be liblog versions used, that do not support __android_log_buf_write. So we only compile and link against - // __android_log_buf_write, if user explicitly provides a non-default log buffer. Otherwise, when using the default log buffer, always - // log via __android_log_write. - template - typename std::enable_if(log_id::LOG_ID_MAIN), int>::type android_log(int prio, const char *tag, const char *text) - { - return __android_log_write(prio, tag, text); - } - - template - typename std::enable_if(log_id::LOG_ID_MAIN), int>::type android_log(int prio, const char *tag, const char *text) - { - return __android_log_buf_write(ID, prio, tag, text); - } - - static android_LogPriority convert_to_android_(spdlog::level::level_enum level) - { - switch (level) - { - case spdlog::level::trace: - return ANDROID_LOG_VERBOSE; - case spdlog::level::debug: - return ANDROID_LOG_DEBUG; - case spdlog::level::info: - return ANDROID_LOG_INFO; - case spdlog::level::warn: - return ANDROID_LOG_WARN; - case spdlog::level::err: - return ANDROID_LOG_ERROR; - case spdlog::level::critical: - return ANDROID_LOG_FATAL; - default: - return ANDROID_LOG_DEFAULT; - } - } - - std::string tag_; - bool use_raw_msg_; -}; - -using android_sink_mt = android_sink; -using android_sink_st = android_sink; - -template -using android_sink_buf_mt = android_sink; -template -using android_sink_buf_st = android_sink; - -} // namespace sinks - -// Create and register android syslog logger - -template -inline std::shared_ptr android_logger_mt(const std::string &logger_name, const std::string &tag = "spdlog") -{ - return Factory::template create(logger_name, tag); -} - -template -inline std::shared_ptr android_logger_st(const std::string &logger_name, const std::string &tag = "spdlog") -{ - return Factory::template create(logger_name, tag); -} - -} // namespace spdlog - -#endif // __ANDROID__ diff --git a/tpl/spdlog/include/spdlog/sinks/ansicolor_sink-inl.h b/tpl/spdlog/include/spdlog/sinks/ansicolor_sink-inl.h deleted file mode 100644 index c924fc5..0000000 --- a/tpl/spdlog/include/spdlog/sinks/ansicolor_sink-inl.h +++ /dev/null @@ -1,145 +0,0 @@ -// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. -// Distributed under the MIT License (http://opensource.org/licenses/MIT) - -#pragma once - -#ifndef SPDLOG_HEADER_ONLY -# include -#endif - -#include -#include - -namespace spdlog { -namespace sinks { - -template -SPDLOG_INLINE ansicolor_sink::ansicolor_sink(FILE *target_file, color_mode mode) - : target_file_(target_file) - , mutex_(ConsoleMutex::mutex()) - , formatter_(details::make_unique()) - -{ - set_color_mode(mode); - colors_.at(level::trace) = to_string_(white); - colors_.at(level::debug) = to_string_(cyan); - colors_.at(level::info) = to_string_(green); - colors_.at(level::warn) = to_string_(yellow_bold); - colors_.at(level::err) = to_string_(red_bold); - colors_.at(level::critical) = to_string_(bold_on_red); - colors_.at(level::off) = to_string_(reset); -} - -template -SPDLOG_INLINE void ansicolor_sink::set_color(level::level_enum color_level, string_view_t color) -{ - std::lock_guard lock(mutex_); - colors_.at(static_cast(color_level)) = to_string_(color); -} - -template -SPDLOG_INLINE void ansicolor_sink::log(const details::log_msg &msg) -{ - // Wrap the originally formatted message in color codes. - // If color is not supported in the terminal, log as is instead. - std::lock_guard lock(mutex_); - msg.color_range_start = 0; - msg.color_range_end = 0; - memory_buf_t formatted; - formatter_->format(msg, formatted); - if (should_do_colors_ && msg.color_range_end > msg.color_range_start) - { - // before color range - print_range_(formatted, 0, msg.color_range_start); - // in color range - print_ccode_(colors_.at(static_cast(msg.level))); - print_range_(formatted, msg.color_range_start, msg.color_range_end); - print_ccode_(reset); - // after color range - print_range_(formatted, msg.color_range_end, formatted.size()); - } - else // no color - { - print_range_(formatted, 0, formatted.size()); - } - fflush(target_file_); -} - -template -SPDLOG_INLINE void ansicolor_sink::flush() -{ - std::lock_guard lock(mutex_); - fflush(target_file_); -} - -template -SPDLOG_INLINE void ansicolor_sink::set_pattern(const std::string &pattern) -{ - std::lock_guard lock(mutex_); - formatter_ = std::unique_ptr(new pattern_formatter(pattern)); -} - -template -SPDLOG_INLINE void ansicolor_sink::set_formatter(std::unique_ptr sink_formatter) -{ - std::lock_guard lock(mutex_); - formatter_ = std::move(sink_formatter); -} - -template -SPDLOG_INLINE bool ansicolor_sink::should_color() -{ - return should_do_colors_; -} - -template -SPDLOG_INLINE void ansicolor_sink::set_color_mode(color_mode mode) -{ - switch (mode) - { - case color_mode::always: - should_do_colors_ = true; - return; - case color_mode::automatic: - should_do_colors_ = details::os::in_terminal(target_file_) && details::os::is_color_terminal(); - return; - case color_mode::never: - should_do_colors_ = false; - return; - default: - should_do_colors_ = false; - } -} - -template -SPDLOG_INLINE void ansicolor_sink::print_ccode_(const string_view_t &color_code) -{ - fwrite(color_code.data(), sizeof(char), color_code.size(), target_file_); -} - -template -SPDLOG_INLINE void ansicolor_sink::print_range_(const memory_buf_t &formatted, size_t start, size_t end) -{ - fwrite(formatted.data() + start, sizeof(char), end - start, target_file_); -} - -template -SPDLOG_INLINE std::string ansicolor_sink::to_string_(const string_view_t &sv) -{ - return std::string(sv.data(), sv.size()); -} - -// ansicolor_stdout_sink -template -SPDLOG_INLINE ansicolor_stdout_sink::ansicolor_stdout_sink(color_mode mode) - : ansicolor_sink(stdout, mode) -{} - -// ansicolor_stderr_sink -template -SPDLOG_INLINE ansicolor_stderr_sink::ansicolor_stderr_sink(color_mode mode) - : ansicolor_sink(stderr, mode) -{} - -} // namespace sinks -} // namespace spdlog diff --git a/tpl/spdlog/include/spdlog/sinks/ansicolor_sink.h b/tpl/spdlog/include/spdlog/sinks/ansicolor_sink.h deleted file mode 100644 index 39d966b..0000000 --- a/tpl/spdlog/include/spdlog/sinks/ansicolor_sink.h +++ /dev/null @@ -1,118 +0,0 @@ -// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. -// Distributed under the MIT License (http://opensource.org/licenses/MIT) - -#pragma once - -#include -#include -#include -#include -#include -#include -#include - -namespace spdlog { -namespace sinks { - -/** - * This sink prefixes the output with an ANSI escape sequence color code - * depending on the severity - * of the message. - * If no color terminal detected, omit the escape codes. - */ - -template -class ansicolor_sink : public sink -{ -public: - using mutex_t = typename ConsoleMutex::mutex_t; - ansicolor_sink(FILE *target_file, color_mode mode); - ~ansicolor_sink() override = default; - - ansicolor_sink(const ansicolor_sink &other) = delete; - ansicolor_sink(ansicolor_sink &&other) = delete; - - ansicolor_sink &operator=(const ansicolor_sink &other) = delete; - ansicolor_sink &operator=(ansicolor_sink &&other) = delete; - - void set_color(level::level_enum color_level, string_view_t color); - void set_color_mode(color_mode mode); - bool should_color(); - - void log(const details::log_msg &msg) override; - void flush() override; - void set_pattern(const std::string &pattern) final; - void set_formatter(std::unique_ptr sink_formatter) override; - - // Formatting codes - const string_view_t reset = "\033[m"; - const string_view_t bold = "\033[1m"; - const string_view_t dark = "\033[2m"; - const string_view_t underline = "\033[4m"; - const string_view_t blink = "\033[5m"; - const string_view_t reverse = "\033[7m"; - const string_view_t concealed = "\033[8m"; - const string_view_t clear_line = "\033[K"; - - // Foreground colors - const string_view_t black = "\033[30m"; - const string_view_t red = "\033[31m"; - const string_view_t green = "\033[32m"; - const string_view_t yellow = "\033[33m"; - const string_view_t blue = "\033[34m"; - const string_view_t magenta = "\033[35m"; - const string_view_t cyan = "\033[36m"; - const string_view_t white = "\033[37m"; - - /// Background colors - const string_view_t on_black = "\033[40m"; - const string_view_t on_red = "\033[41m"; - const string_view_t on_green = "\033[42m"; - const string_view_t on_yellow = "\033[43m"; - const string_view_t on_blue = "\033[44m"; - const string_view_t on_magenta = "\033[45m"; - const string_view_t on_cyan = "\033[46m"; - const string_view_t on_white = "\033[47m"; - - /// Bold colors - const string_view_t yellow_bold = "\033[33m\033[1m"; - const string_view_t red_bold = "\033[31m\033[1m"; - const string_view_t bold_on_red = "\033[1m\033[41m"; - -private: - FILE *target_file_; - mutex_t &mutex_; - bool should_do_colors_; - std::unique_ptr formatter_; - std::array colors_; - void print_ccode_(const string_view_t &color_code); - void print_range_(const memory_buf_t &formatted, size_t start, size_t end); - static std::string to_string_(const string_view_t &sv); -}; - -template -class ansicolor_stdout_sink : public ansicolor_sink -{ -public: - explicit ansicolor_stdout_sink(color_mode mode = color_mode::automatic); -}; - -template -class ansicolor_stderr_sink : public ansicolor_sink -{ -public: - explicit ansicolor_stderr_sink(color_mode mode = color_mode::automatic); -}; - -using ansicolor_stdout_sink_mt = ansicolor_stdout_sink; -using ansicolor_stdout_sink_st = ansicolor_stdout_sink; - -using ansicolor_stderr_sink_mt = ansicolor_stderr_sink; -using ansicolor_stderr_sink_st = ansicolor_stderr_sink; - -} // namespace sinks -} // namespace spdlog - -#ifdef SPDLOG_HEADER_ONLY -# include "ansicolor_sink-inl.h" -#endif diff --git a/tpl/spdlog/include/spdlog/sinks/base_sink-inl.h b/tpl/spdlog/include/spdlog/sinks/base_sink-inl.h deleted file mode 100644 index 421fdf9..0000000 --- a/tpl/spdlog/include/spdlog/sinks/base_sink-inl.h +++ /dev/null @@ -1,63 +0,0 @@ -// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. -// Distributed under the MIT License (http://opensource.org/licenses/MIT) - -#pragma once - -#ifndef SPDLOG_HEADER_ONLY -# include -#endif - -#include -#include - -#include - -template -SPDLOG_INLINE spdlog::sinks::base_sink::base_sink() - : formatter_{details::make_unique()} -{} - -template -SPDLOG_INLINE spdlog::sinks::base_sink::base_sink(std::unique_ptr formatter) - : formatter_{std::move(formatter)} -{} - -template -void SPDLOG_INLINE spdlog::sinks::base_sink::log(const details::log_msg &msg) -{ - std::lock_guard lock(mutex_); - sink_it_(msg); -} - -template -void SPDLOG_INLINE spdlog::sinks::base_sink::flush() -{ - std::lock_guard lock(mutex_); - flush_(); -} - -template -void SPDLOG_INLINE spdlog::sinks::base_sink::set_pattern(const std::string &pattern) -{ - std::lock_guard lock(mutex_); - set_pattern_(pattern); -} - -template -void SPDLOG_INLINE spdlog::sinks::base_sink::set_formatter(std::unique_ptr sink_formatter) -{ - std::lock_guard lock(mutex_); - set_formatter_(std::move(sink_formatter)); -} - -template -void SPDLOG_INLINE spdlog::sinks::base_sink::set_pattern_(const std::string &pattern) -{ - set_formatter_(details::make_unique(pattern)); -} - -template -void SPDLOG_INLINE spdlog::sinks::base_sink::set_formatter_(std::unique_ptr sink_formatter) -{ - formatter_ = std::move(sink_formatter); -} diff --git a/tpl/spdlog/include/spdlog/sinks/base_sink.h b/tpl/spdlog/include/spdlog/sinks/base_sink.h deleted file mode 100644 index 2e795f5..0000000 --- a/tpl/spdlog/include/spdlog/sinks/base_sink.h +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. -// Distributed under the MIT License (http://opensource.org/licenses/MIT) - -#pragma once -// -// base sink templated over a mutex (either dummy or real) -// concrete implementation should override the sink_it_() and flush_() methods. -// locking is taken care of in this class - no locking needed by the -// implementers.. -// - -#include -#include -#include - -namespace spdlog { -namespace sinks { -template -class SPDLOG_API base_sink : public sink -{ -public: - base_sink(); - explicit base_sink(std::unique_ptr formatter); - ~base_sink() override = default; - - base_sink(const base_sink &) = delete; - base_sink(base_sink &&) = delete; - - base_sink &operator=(const base_sink &) = delete; - base_sink &operator=(base_sink &&) = delete; - - void log(const details::log_msg &msg) final; - void flush() final; - void set_pattern(const std::string &pattern) final; - void set_formatter(std::unique_ptr sink_formatter) final; - -protected: - // sink formatter - std::unique_ptr formatter_; - Mutex mutex_; - - virtual void sink_it_(const details::log_msg &msg) = 0; - virtual void flush_() = 0; - virtual void set_pattern_(const std::string &pattern); - virtual void set_formatter_(std::unique_ptr sink_formatter); -}; -} // namespace sinks -} // namespace spdlog - -#ifdef SPDLOG_HEADER_ONLY -# include "base_sink-inl.h" -#endif diff --git a/tpl/spdlog/include/spdlog/sinks/basic_file_sink-inl.h b/tpl/spdlog/include/spdlog/sinks/basic_file_sink-inl.h deleted file mode 100644 index 8d23f96..0000000 --- a/tpl/spdlog/include/spdlog/sinks/basic_file_sink-inl.h +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. -// Distributed under the MIT License (http://opensource.org/licenses/MIT) - -#pragma once - -#ifndef SPDLOG_HEADER_ONLY -# include -#endif - -#include -#include - -namespace spdlog { -namespace sinks { - -template -SPDLOG_INLINE basic_file_sink::basic_file_sink(const filename_t &filename, bool truncate, const file_event_handlers &event_handlers) - : file_helper_{event_handlers} -{ - file_helper_.open(filename, truncate); -} - -template -SPDLOG_INLINE const filename_t &basic_file_sink::filename() const -{ - return file_helper_.filename(); -} - -template -SPDLOG_INLINE void basic_file_sink::sink_it_(const details::log_msg &msg) -{ - memory_buf_t formatted; - base_sink::formatter_->format(msg, formatted); - file_helper_.write(formatted); -} - -template -SPDLOG_INLINE void basic_file_sink::flush_() -{ - file_helper_.flush(); -} - -} // namespace sinks -} // namespace spdlog diff --git a/tpl/spdlog/include/spdlog/sinks/basic_file_sink.h b/tpl/spdlog/include/spdlog/sinks/basic_file_sink.h deleted file mode 100644 index aacc993..0000000 --- a/tpl/spdlog/include/spdlog/sinks/basic_file_sink.h +++ /dev/null @@ -1,60 +0,0 @@ -// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. -// Distributed under the MIT License (http://opensource.org/licenses/MIT) - -#pragma once - -#include -#include -#include -#include - -#include -#include - -namespace spdlog { -namespace sinks { -/* - * Trivial file sink with single file as target - */ -template -class basic_file_sink final : public base_sink -{ -public: - explicit basic_file_sink(const filename_t &filename, bool truncate = false, const file_event_handlers &event_handlers = {}); - const filename_t &filename() const; - -protected: - void sink_it_(const details::log_msg &msg) override; - void flush_() override; - -private: - details::file_helper file_helper_; -}; - -using basic_file_sink_mt = basic_file_sink; -using basic_file_sink_st = basic_file_sink; - -} // namespace sinks - -// -// factory functions -// -template -inline std::shared_ptr basic_logger_mt( - const std::string &logger_name, const filename_t &filename, bool truncate = false, const file_event_handlers &event_handlers = {}) -{ - return Factory::template create(logger_name, filename, truncate, event_handlers); -} - -template -inline std::shared_ptr basic_logger_st( - const std::string &logger_name, const filename_t &filename, bool truncate = false, const file_event_handlers &event_handlers = {}) -{ - return Factory::template create(logger_name, filename, truncate, event_handlers); -} - -} // namespace spdlog - -#ifdef SPDLOG_HEADER_ONLY -# include "basic_file_sink-inl.h" -#endif diff --git a/tpl/spdlog/include/spdlog/sinks/callback_sink.h b/tpl/spdlog/include/spdlog/sinks/callback_sink.h deleted file mode 100644 index bcd3138..0000000 --- a/tpl/spdlog/include/spdlog/sinks/callback_sink.h +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. -// Distributed under the MIT License (http://opensource.org/licenses/MIT) - -#pragma once - -#include -#include -#include - -#include -#include - -namespace spdlog { - -// callbacks type -typedef std::function custom_log_callback; - -namespace sinks { -/* - * Trivial callback sink, gets a callback function and calls it on each log - */ -template -class callback_sink final : public base_sink -{ -public: - explicit callback_sink(const custom_log_callback &callback) - : callback_{callback} - {} - -protected: - void sink_it_(const details::log_msg &msg) override - { - callback_(msg); - } - void flush_() override{}; - -private: - custom_log_callback callback_; -}; - -using callback_sink_mt = callback_sink; -using callback_sink_st = callback_sink; - -} // namespace sinks - -// -// factory functions -// -template -inline std::shared_ptr callback_logger_mt(const std::string &logger_name, const custom_log_callback &callback) -{ - return Factory::template create(logger_name, callback); -} - -template -inline std::shared_ptr callback_logger_st(const std::string &logger_name, const custom_log_callback &callback) -{ - return Factory::template create(logger_name, callback); -} - -} // namespace spdlog diff --git a/tpl/spdlog/include/spdlog/sinks/daily_file_sink.h b/tpl/spdlog/include/spdlog/sinks/daily_file_sink.h deleted file mode 100644 index 0770380..0000000 --- a/tpl/spdlog/include/spdlog/sinks/daily_file_sink.h +++ /dev/null @@ -1,247 +0,0 @@ -// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. -// Distributed under the MIT License (http://opensource.org/licenses/MIT) - -#pragma once - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -namespace spdlog { -namespace sinks { - -/* - * Generator of daily log file names in format basename.YYYY-MM-DD.ext - */ -struct daily_filename_calculator -{ - // Create filename for the form basename.YYYY-MM-DD - static filename_t calc_filename(const filename_t &filename, const tm &now_tm) - { - filename_t basename, ext; - std::tie(basename, ext) = details::file_helper::split_by_extension(filename); - return fmt_lib::format(SPDLOG_FMT_STRING(SPDLOG_FILENAME_T("{}_{:04d}-{:02d}-{:02d}{}")), basename, now_tm.tm_year + 1900, - now_tm.tm_mon + 1, now_tm.tm_mday, ext); - } -}; - -/* - * Generator of daily log file names with strftime format. - * Usages: - * auto sink = std::make_shared("myapp-%Y-%m-%d:%H:%M:%S.log", hour, minute);" - * auto logger = spdlog::daily_logger_format_mt("loggername, "myapp-%Y-%m-%d:%X.log", hour, minute)" - * - */ -struct daily_filename_format_calculator -{ - static filename_t calc_filename(const filename_t &file_path, const tm &now_tm) - { -#if defined(_WIN32) && defined(SPDLOG_WCHAR_FILENAMES) - std::wstringstream stream; -#else - std::stringstream stream; -#endif - stream << std::put_time(&now_tm, file_path.c_str()); - return stream.str(); - } -}; - -/* - * Rotating file sink based on date. - * If truncate != false , the created file will be truncated. - * If max_files > 0, retain only the last max_files and delete previous. - */ -template -class daily_file_sink final : public base_sink -{ -public: - // create daily file sink which rotates on given time - daily_file_sink(filename_t base_filename, int rotation_hour, int rotation_minute, bool truncate = false, uint16_t max_files = 0, - const file_event_handlers &event_handlers = {}) - : base_filename_(std::move(base_filename)) - , rotation_h_(rotation_hour) - , rotation_m_(rotation_minute) - , file_helper_{event_handlers} - , truncate_(truncate) - , max_files_(max_files) - , filenames_q_() - { - if (rotation_hour < 0 || rotation_hour > 23 || rotation_minute < 0 || rotation_minute > 59) - { - throw_spdlog_ex("daily_file_sink: Invalid rotation time in ctor"); - } - - auto now = log_clock::now(); - auto filename = FileNameCalc::calc_filename(base_filename_, now_tm(now)); - file_helper_.open(filename, truncate_); - rotation_tp_ = next_rotation_tp_(); - - if (max_files_ > 0) - { - init_filenames_q_(); - } - } - - filename_t filename() - { - std::lock_guard lock(base_sink::mutex_); - return file_helper_.filename(); - } - -protected: - void sink_it_(const details::log_msg &msg) override - { - auto time = msg.time; - bool should_rotate = time >= rotation_tp_; - if (should_rotate) - { - auto filename = FileNameCalc::calc_filename(base_filename_, now_tm(time)); - file_helper_.open(filename, truncate_); - rotation_tp_ = next_rotation_tp_(); - } - memory_buf_t formatted; - base_sink::formatter_->format(msg, formatted); - file_helper_.write(formatted); - - // Do the cleaning only at the end because it might throw on failure. - if (should_rotate && max_files_ > 0) - { - delete_old_(); - } - } - - void flush_() override - { - file_helper_.flush(); - } - -private: - void init_filenames_q_() - { - using details::os::path_exists; - - filenames_q_ = details::circular_q(static_cast(max_files_)); - std::vector filenames; - auto now = log_clock::now(); - while (filenames.size() < max_files_) - { - auto filename = FileNameCalc::calc_filename(base_filename_, now_tm(now)); - if (!path_exists(filename)) - { - break; - } - filenames.emplace_back(filename); - now -= std::chrono::hours(24); - } - for (auto iter = filenames.rbegin(); iter != filenames.rend(); ++iter) - { - filenames_q_.push_back(std::move(*iter)); - } - } - - tm now_tm(log_clock::time_point tp) - { - time_t tnow = log_clock::to_time_t(tp); - return spdlog::details::os::localtime(tnow); - } - - log_clock::time_point next_rotation_tp_() - { - auto now = log_clock::now(); - tm date = now_tm(now); - date.tm_hour = rotation_h_; - date.tm_min = rotation_m_; - date.tm_sec = 0; - auto rotation_time = log_clock::from_time_t(std::mktime(&date)); - if (rotation_time > now) - { - return rotation_time; - } - return {rotation_time + std::chrono::hours(24)}; - } - - // Delete the file N rotations ago. - // Throw spdlog_ex on failure to delete the old file. - void delete_old_() - { - using details::os::filename_to_str; - using details::os::remove_if_exists; - - filename_t current_file = file_helper_.filename(); - if (filenames_q_.full()) - { - auto old_filename = std::move(filenames_q_.front()); - filenames_q_.pop_front(); - bool ok = remove_if_exists(old_filename) == 0; - if (!ok) - { - filenames_q_.push_back(std::move(current_file)); - throw_spdlog_ex("Failed removing daily file " + filename_to_str(old_filename), errno); - } - } - filenames_q_.push_back(std::move(current_file)); - } - - filename_t base_filename_; - int rotation_h_; - int rotation_m_; - log_clock::time_point rotation_tp_; - details::file_helper file_helper_; - bool truncate_; - uint16_t max_files_; - details::circular_q filenames_q_; -}; - -using daily_file_sink_mt = daily_file_sink; -using daily_file_sink_st = daily_file_sink; -using daily_file_format_sink_mt = daily_file_sink; -using daily_file_format_sink_st = daily_file_sink; - -} // namespace sinks - -// -// factory functions -// -template -inline std::shared_ptr daily_logger_mt(const std::string &logger_name, const filename_t &filename, int hour = 0, int minute = 0, - bool truncate = false, uint16_t max_files = 0, const file_event_handlers &event_handlers = {}) -{ - return Factory::template create(logger_name, filename, hour, minute, truncate, max_files, event_handlers); -} - -template -inline std::shared_ptr daily_logger_format_mt(const std::string &logger_name, const filename_t &filename, int hour = 0, - int minute = 0, bool truncate = false, uint16_t max_files = 0, const file_event_handlers &event_handlers = {}) -{ - return Factory::template create( - logger_name, filename, hour, minute, truncate, max_files, event_handlers); -} - -template -inline std::shared_ptr daily_logger_st(const std::string &logger_name, const filename_t &filename, int hour = 0, int minute = 0, - bool truncate = false, uint16_t max_files = 0, const file_event_handlers &event_handlers = {}) -{ - return Factory::template create(logger_name, filename, hour, minute, truncate, max_files, event_handlers); -} - -template -inline std::shared_ptr daily_logger_format_st(const std::string &logger_name, const filename_t &filename, int hour = 0, - int minute = 0, bool truncate = false, uint16_t max_files = 0, const file_event_handlers &event_handlers = {}) -{ - return Factory::template create( - logger_name, filename, hour, minute, truncate, max_files, event_handlers); -} -} // namespace spdlog diff --git a/tpl/spdlog/include/spdlog/sinks/dist_sink.h b/tpl/spdlog/include/spdlog/sinks/dist_sink.h deleted file mode 100644 index 7ec3a2e..0000000 --- a/tpl/spdlog/include/spdlog/sinks/dist_sink.h +++ /dev/null @@ -1,97 +0,0 @@ -// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. -// Distributed under the MIT License (http://opensource.org/licenses/MIT) - -#pragma once - -#include "base_sink.h" -#include -#include -#include - -#include -#include -#include -#include - -// Distribution sink (mux). Stores a vector of sinks which get called when log -// is called - -namespace spdlog { -namespace sinks { - -template -class dist_sink : public base_sink -{ -public: - dist_sink() = default; - explicit dist_sink(std::vector> sinks) - : sinks_(sinks) - {} - - dist_sink(const dist_sink &) = delete; - dist_sink &operator=(const dist_sink &) = delete; - - void add_sink(std::shared_ptr sub_sink) - { - std::lock_guard lock(base_sink::mutex_); - sinks_.push_back(sub_sink); - } - - void remove_sink(std::shared_ptr sub_sink) - { - std::lock_guard lock(base_sink::mutex_); - sinks_.erase(std::remove(sinks_.begin(), sinks_.end(), sub_sink), sinks_.end()); - } - - void set_sinks(std::vector> sinks) - { - std::lock_guard lock(base_sink::mutex_); - sinks_ = std::move(sinks); - } - - std::vector> &sinks() - { - return sinks_; - } - -protected: - void sink_it_(const details::log_msg &msg) override - { - for (auto &sub_sink : sinks_) - { - if (sub_sink->should_log(msg.level)) - { - sub_sink->log(msg); - } - } - } - - void flush_() override - { - for (auto &sub_sink : sinks_) - { - sub_sink->flush(); - } - } - - void set_pattern_(const std::string &pattern) override - { - set_formatter_(details::make_unique(pattern)); - } - - void set_formatter_(std::unique_ptr sink_formatter) override - { - base_sink::formatter_ = std::move(sink_formatter); - for (auto &sub_sink : sinks_) - { - sub_sink->set_formatter(base_sink::formatter_->clone()); - } - } - std::vector> sinks_; -}; - -using dist_sink_mt = dist_sink; -using dist_sink_st = dist_sink; - -} // namespace sinks -} // namespace spdlog diff --git a/tpl/spdlog/include/spdlog/sinks/dup_filter_sink.h b/tpl/spdlog/include/spdlog/sinks/dup_filter_sink.h deleted file mode 100644 index 3c96549..0000000 --- a/tpl/spdlog/include/spdlog/sinks/dup_filter_sink.h +++ /dev/null @@ -1,96 +0,0 @@ -// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. -// Distributed under the MIT License (http://opensource.org/licenses/MIT) - -#pragma once - -#include "dist_sink.h" -#include -#include - -#include -#include -#include -#include - -// Duplicate message removal sink. -// Skip the message if previous one is identical and less than "max_skip_duration" have passed -// -// Example: -// -// #include -// -// int main() { -// auto dup_filter = std::make_shared(std::chrono::seconds(5), level::info); -// dup_filter->add_sink(std::make_shared()); -// spdlog::logger l("logger", dup_filter); -// l.info("Hello"); -// l.info("Hello"); -// l.info("Hello"); -// l.info("Different Hello"); -// } -// -// Will produce: -// [2019-06-25 17:50:56.511] [logger] [info] Hello -// [2019-06-25 17:50:56.512] [logger] [info] Skipped 3 duplicate messages.. -// [2019-06-25 17:50:56.512] [logger] [info] Different Hello - -namespace spdlog { -namespace sinks { -template -class dup_filter_sink : public dist_sink -{ -public: - template - explicit dup_filter_sink(std::chrono::duration max_skip_duration, level::level_enum notification_level = level::info) - : max_skip_duration_{max_skip_duration} - , log_level_{notification_level} - {} - -protected: - std::chrono::microseconds max_skip_duration_; - log_clock::time_point last_msg_time_; - std::string last_msg_payload_; - size_t skip_counter_ = 0; - level::level_enum log_level_; - - void sink_it_(const details::log_msg &msg) override - { - bool filtered = filter_(msg); - if (!filtered) - { - skip_counter_ += 1; - return; - } - - // log the "skipped.." message - if (skip_counter_ > 0) - { - char buf[64]; - auto msg_size = ::snprintf(buf, sizeof(buf), "Skipped %u duplicate messages..", static_cast(skip_counter_)); - if (msg_size > 0 && static_cast(msg_size) < sizeof(buf)) - { - details::log_msg skipped_msg{msg.source, msg.logger_name, log_level_, string_view_t{buf, static_cast(msg_size)}}; - dist_sink::sink_it_(skipped_msg); - } - } - - // log current message - dist_sink::sink_it_(msg); - last_msg_time_ = msg.time; - skip_counter_ = 0; - last_msg_payload_.assign(msg.payload.data(), msg.payload.data() + msg.payload.size()); - } - - // return whether the log msg should be displayed (true) or skipped (false) - bool filter_(const details::log_msg &msg) - { - auto filter_duration = msg.time - last_msg_time_; - return (filter_duration > max_skip_duration_) || (msg.payload != last_msg_payload_); - } -}; - -using dup_filter_sink_mt = dup_filter_sink; -using dup_filter_sink_st = dup_filter_sink; - -} // namespace sinks -} // namespace spdlog diff --git a/tpl/spdlog/include/spdlog/sinks/hourly_file_sink.h b/tpl/spdlog/include/spdlog/sinks/hourly_file_sink.h deleted file mode 100644 index 33dd894..0000000 --- a/tpl/spdlog/include/spdlog/sinks/hourly_file_sink.h +++ /dev/null @@ -1,204 +0,0 @@ -// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. -// Distributed under the MIT License (http://opensource.org/licenses/MIT) - -#pragma once - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -namespace spdlog { -namespace sinks { - -/* - * Generator of Hourly log file names in format basename.YYYY-MM-DD-HH.ext - */ -struct hourly_filename_calculator -{ - // Create filename for the form basename.YYYY-MM-DD-H - static filename_t calc_filename(const filename_t &filename, const tm &now_tm) - { - filename_t basename, ext; - std::tie(basename, ext) = details::file_helper::split_by_extension(filename); - return fmt_lib::format(SPDLOG_FILENAME_T("{}_{:04d}-{:02d}-{:02d}_{:02d}{}"), basename, now_tm.tm_year + 1900, now_tm.tm_mon + 1, - now_tm.tm_mday, now_tm.tm_hour, ext); - } -}; - -/* - * Rotating file sink based on time. - * If truncate != false , the created file will be truncated. - * If max_files > 0, retain only the last max_files and delete previous. - */ -template -class hourly_file_sink final : public base_sink -{ -public: - // create hourly file sink which rotates on given time - hourly_file_sink( - filename_t base_filename, bool truncate = false, uint16_t max_files = 0, const file_event_handlers &event_handlers = {}) - : base_filename_(std::move(base_filename)) - , file_helper_{event_handlers} - , truncate_(truncate) - , max_files_(max_files) - , filenames_q_() - { - auto now = log_clock::now(); - auto filename = FileNameCalc::calc_filename(base_filename_, now_tm(now)); - file_helper_.open(filename, truncate_); - remove_init_file_ = file_helper_.size() == 0; - rotation_tp_ = next_rotation_tp_(); - - if (max_files_ > 0) - { - init_filenames_q_(); - } - } - - filename_t filename() - { - std::lock_guard lock(base_sink::mutex_); - return file_helper_.filename(); - } - -protected: - void sink_it_(const details::log_msg &msg) override - { - auto time = msg.time; - bool should_rotate = time >= rotation_tp_; - if (should_rotate) - { - if (remove_init_file_) - { - file_helper_.close(); - details::os::remove(file_helper_.filename()); - } - auto filename = FileNameCalc::calc_filename(base_filename_, now_tm(time)); - file_helper_.open(filename, truncate_); - rotation_tp_ = next_rotation_tp_(); - } - remove_init_file_ = false; - memory_buf_t formatted; - base_sink::formatter_->format(msg, formatted); - file_helper_.write(formatted); - - // Do the cleaning only at the end because it might throw on failure. - if (should_rotate && max_files_ > 0) - { - delete_old_(); - } - } - - void flush_() override - { - file_helper_.flush(); - } - -private: - void init_filenames_q_() - { - using details::os::path_exists; - - filenames_q_ = details::circular_q(static_cast(max_files_)); - std::vector filenames; - auto now = log_clock::now(); - while (filenames.size() < max_files_) - { - auto filename = FileNameCalc::calc_filename(base_filename_, now_tm(now)); - if (!path_exists(filename)) - { - break; - } - filenames.emplace_back(filename); - now -= std::chrono::hours(1); - } - for (auto iter = filenames.rbegin(); iter != filenames.rend(); ++iter) - { - filenames_q_.push_back(std::move(*iter)); - } - } - - tm now_tm(log_clock::time_point tp) - { - time_t tnow = log_clock::to_time_t(tp); - return spdlog::details::os::localtime(tnow); - } - - log_clock::time_point next_rotation_tp_() - { - auto now = log_clock::now(); - tm date = now_tm(now); - date.tm_min = 0; - date.tm_sec = 0; - auto rotation_time = log_clock::from_time_t(std::mktime(&date)); - if (rotation_time > now) - { - return rotation_time; - } - return {rotation_time + std::chrono::hours(1)}; - } - - // Delete the file N rotations ago. - // Throw spdlog_ex on failure to delete the old file. - void delete_old_() - { - using details::os::filename_to_str; - using details::os::remove_if_exists; - - filename_t current_file = file_helper_.filename(); - if (filenames_q_.full()) - { - auto old_filename = std::move(filenames_q_.front()); - filenames_q_.pop_front(); - bool ok = remove_if_exists(old_filename) == 0; - if (!ok) - { - filenames_q_.push_back(std::move(current_file)); - SPDLOG_THROW(spdlog_ex("Failed removing hourly file " + filename_to_str(old_filename), errno)); - } - } - filenames_q_.push_back(std::move(current_file)); - } - - filename_t base_filename_; - log_clock::time_point rotation_tp_; - details::file_helper file_helper_; - bool truncate_; - uint16_t max_files_; - details::circular_q filenames_q_; - bool remove_init_file_; -}; - -using hourly_file_sink_mt = hourly_file_sink; -using hourly_file_sink_st = hourly_file_sink; - -} // namespace sinks - -// -// factory functions -// -template -inline std::shared_ptr hourly_logger_mt(const std::string &logger_name, const filename_t &filename, bool truncate = false, - uint16_t max_files = 0, const file_event_handlers &event_handlers = {}) -{ - return Factory::template create(logger_name, filename, truncate, max_files, event_handlers); -} - -template -inline std::shared_ptr hourly_logger_st(const std::string &logger_name, const filename_t &filename, bool truncate = false, - uint16_t max_files = 0, const file_event_handlers &event_handlers = {}) -{ - return Factory::template create(logger_name, filename, truncate, max_files, event_handlers); -} -} // namespace spdlog diff --git a/tpl/spdlog/include/spdlog/sinks/kafka_sink.h b/tpl/spdlog/include/spdlog/sinks/kafka_sink.h deleted file mode 100644 index ce740ef..0000000 --- a/tpl/spdlog/include/spdlog/sinks/kafka_sink.h +++ /dev/null @@ -1,133 +0,0 @@ -// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. -// Distributed under the MIT License (http://opensource.org/licenses/MIT) - -#pragma once - -// -// Custom sink for kafka -// Building and using requires librdkafka library. -// For building librdkafka library check the url below -// https://github.com/confluentinc/librdkafka -// - -#include -#include "spdlog/details/log_msg.h" -#include "spdlog/sinks/base_sink.h" -#include "spdlog/details/synchronous_factory.h" -#include "spdlog/details/null_mutex.h" -#include "spdlog/async.h" -#include - -// kafka header -#include - -namespace spdlog { -namespace sinks { - -struct kafka_sink_config -{ - std::string server_addr; - std::string produce_topic; - int32_t flush_timeout_ms = 1000; - - kafka_sink_config(std::string addr, std::string topic, int flush_timeout_ms = 1000) - : server_addr{std::move(addr)} - , produce_topic{std::move(topic)} - , flush_timeout_ms(flush_timeout_ms) - {} -}; - -template -class kafka_sink : public base_sink -{ -public: - kafka_sink(kafka_sink_config config) - : config_{std::move(config)} - { - try - { - std::string errstr; - conf_.reset(RdKafka::Conf::create(RdKafka::Conf::CONF_GLOBAL)); - RdKafka::Conf::ConfResult confRes = conf_->set("bootstrap.servers", config_.server_addr, errstr); - if (confRes != RdKafka::Conf::CONF_OK) - { - throw_spdlog_ex(fmt_lib::format("conf set bootstrap.servers failed err:{}", errstr)); - } - - tconf_.reset(RdKafka::Conf::create(RdKafka::Conf::CONF_TOPIC)); - if (tconf_ == nullptr) - { - throw_spdlog_ex(fmt_lib::format("create topic config failed")); - } - - producer_.reset(RdKafka::Producer::create(conf_.get(), errstr)); - if (producer_ == nullptr) - { - throw_spdlog_ex(fmt_lib::format("create producer failed err:{}", errstr)); - } - topic_.reset(RdKafka::Topic::create(producer_.get(), config_.produce_topic, tconf_.get(), errstr)); - if (topic_ == nullptr) - { - throw_spdlog_ex(fmt_lib::format("create topic failed err:{}", errstr)); - } - } - catch (const std::exception &e) - { - throw_spdlog_ex(fmt_lib::format("error create kafka instance: {}", e.what())); - } - } - - ~kafka_sink() - { - producer_->flush(config_.flush_timeout_ms); - } - -protected: - void sink_it_(const details::log_msg &msg) override - { - producer_->produce(topic_.get(), 0, RdKafka::Producer::RK_MSG_COPY, (void *)msg.payload.data(), msg.payload.size(), NULL, NULL); - } - - void flush_() override - { - producer_->flush(config_.flush_timeout_ms); - } - -private: - kafka_sink_config config_; - std::unique_ptr producer_ = nullptr; - std::unique_ptr conf_ = nullptr; - std::unique_ptr tconf_ = nullptr; - std::unique_ptr topic_ = nullptr; -}; - -using kafka_sink_mt = kafka_sink; -using kafka_sink_st = kafka_sink; - -} // namespace sinks - -template -inline std::shared_ptr kafka_logger_mt(const std::string &logger_name, spdlog::sinks::kafka_sink_config config) -{ - return Factory::template create(logger_name, config); -} - -template -inline std::shared_ptr kafka_logger_st(const std::string &logger_name, spdlog::sinks::kafka_sink_config config) -{ - return Factory::template create(logger_name, config); -} - -template -inline std::shared_ptr kafka_logger_async_mt(std::string logger_name, spdlog::sinks::kafka_sink_config config) -{ - return Factory::template create(logger_name, config); -} - -template -inline std::shared_ptr kafka_logger_async_st(std::string logger_name, spdlog::sinks::kafka_sink_config config) -{ - return Factory::template create(logger_name, config); -} - -} // namespace spdlog diff --git a/tpl/spdlog/include/spdlog/sinks/mongo_sink.h b/tpl/spdlog/include/spdlog/sinks/mongo_sink.h deleted file mode 100644 index 6a8927f..0000000 --- a/tpl/spdlog/include/spdlog/sinks/mongo_sink.h +++ /dev/null @@ -1,107 +0,0 @@ -// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. -// Distributed under the MIT License (http://opensource.org/licenses/MIT) - -#pragma once - -// -// Custom sink for mongodb -// Building and using requires mongocxx library. -// For building mongocxx library check the url below -// http://mongocxx.org/mongocxx-v3/installation/ -// - -#include "spdlog/common.h" -#include "spdlog/details/log_msg.h" -#include "spdlog/sinks/base_sink.h" -#include - -#include -#include -#include - -#include -#include -#include - -namespace spdlog { -namespace sinks { -template -class mongo_sink : public base_sink -{ -public: - mongo_sink(const std::string &db_name, const std::string &collection_name, const std::string &uri = "mongodb://localhost:27017") - try : mongo_sink(std::make_shared(), db_name, collection_name, uri) - {} - catch (const std::exception &e) - { - throw_spdlog_ex(fmt_lib::format("Error opening database: {}", e.what())); - } - - mongo_sink(std::shared_ptr instance, const std::string &db_name, const std::string &collection_name, - const std::string &uri = "mongodb://localhost:27017") - : instance_(std::move(instance)) - , db_name_(db_name) - , coll_name_(collection_name) - { - try - { - client_ = spdlog::details::make_unique(mongocxx::uri{uri}); - } - catch (const std::exception &e) - { - throw_spdlog_ex(fmt_lib::format("Error opening database: {}", e.what())); - } - } - - ~mongo_sink() - { - flush_(); - } - -protected: - void sink_it_(const details::log_msg &msg) override - { - using bsoncxx::builder::stream::document; - using bsoncxx::builder::stream::finalize; - - if (client_ != nullptr) - { - auto doc = document{} << "timestamp" << bsoncxx::types::b_date(msg.time) << "level" << level::to_string_view(msg.level).data() - << "level_num" << msg.level << "message" << std::string(msg.payload.begin(), msg.payload.end()) - << "logger_name" << std::string(msg.logger_name.begin(), msg.logger_name.end()) << "thread_id" - << static_cast(msg.thread_id) << finalize; - client_->database(db_name_).collection(coll_name_).insert_one(doc.view()); - } - } - - void flush_() override {} - -private: - std::shared_ptr instance_; - std::string db_name_; - std::string coll_name_; - std::unique_ptr client_ = nullptr; -}; - -#include "spdlog/details/null_mutex.h" -#include -using mongo_sink_mt = mongo_sink; -using mongo_sink_st = mongo_sink; - -} // namespace sinks - -template -inline std::shared_ptr mongo_logger_mt(const std::string &logger_name, const std::string &db_name, - const std::string &collection_name, const std::string &uri = "mongodb://localhost:27017") -{ - return Factory::template create(logger_name, db_name, collection_name, uri); -} - -template -inline std::shared_ptr mongo_logger_st(const std::string &logger_name, const std::string &db_name, - const std::string &collection_name, const std::string &uri = "mongodb://localhost:27017") -{ - return Factory::template create(logger_name, db_name, collection_name, uri); -} - -} // namespace spdlog diff --git a/tpl/spdlog/include/spdlog/sinks/msvc_sink.h b/tpl/spdlog/include/spdlog/sinks/msvc_sink.h deleted file mode 100644 index bf68ae8..0000000 --- a/tpl/spdlog/include/spdlog/sinks/msvc_sink.h +++ /dev/null @@ -1,71 +0,0 @@ -// Copyright(c) 2016 Alexander Dalshov & spdlog contributors. -// Distributed under the MIT License (http://opensource.org/licenses/MIT) - -#pragma once - -#if defined(_WIN32) - -# include -# if defined(SPDLOG_WCHAR_TO_UTF8_SUPPORT) -# include -# endif -# include - -# include -# include - -// Avoid including windows.h (https://stackoverflow.com/a/30741042) -# if defined(SPDLOG_WCHAR_TO_UTF8_SUPPORT) -extern "C" __declspec(dllimport) void __stdcall OutputDebugStringW(const wchar_t *lpOutputString); -# else -extern "C" __declspec(dllimport) void __stdcall OutputDebugStringA(const char *lpOutputString); -# endif -extern "C" __declspec(dllimport) int __stdcall IsDebuggerPresent(); - -namespace spdlog { -namespace sinks { -/* - * MSVC sink (logging using OutputDebugStringA) - */ -template -class msvc_sink : public base_sink -{ -public: - msvc_sink() = default; - msvc_sink(bool check_debugger_present) - : check_debugger_present_{check_debugger_present} {}; - -protected: - void sink_it_(const details::log_msg &msg) override - { - if (check_debugger_present_ && !IsDebuggerPresent()) - { - return; - } - memory_buf_t formatted; - base_sink::formatter_->format(msg, formatted); - formatted.push_back('\0'); // add a null terminator for OutputDebugString -# if defined(SPDLOG_WCHAR_TO_UTF8_SUPPORT) - wmemory_buf_t wformatted; - details::os::utf8_to_wstrbuf(string_view_t(formatted.data(), formatted.size()), wformatted); - OutputDebugStringW(wformatted.data()); -# else - OutputDebugStringA(formatted.data()); -# endif - } - - void flush_() override {} - - bool check_debugger_present_ = true; -}; - -using msvc_sink_mt = msvc_sink; -using msvc_sink_st = msvc_sink; - -using windebug_sink_mt = msvc_sink_mt; -using windebug_sink_st = msvc_sink_st; - -} // namespace sinks -} // namespace spdlog - -#endif diff --git a/tpl/spdlog/include/spdlog/sinks/null_sink.h b/tpl/spdlog/include/spdlog/sinks/null_sink.h deleted file mode 100644 index eb83280..0000000 --- a/tpl/spdlog/include/spdlog/sinks/null_sink.h +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. -// Distributed under the MIT License (http://opensource.org/licenses/MIT) - -#pragma once - -#include -#include -#include - -#include - -namespace spdlog { -namespace sinks { - -template -class null_sink : public base_sink -{ -protected: - void sink_it_(const details::log_msg &) override {} - void flush_() override {} -}; - -using null_sink_mt = null_sink; -using null_sink_st = null_sink; - -} // namespace sinks - -template -inline std::shared_ptr null_logger_mt(const std::string &logger_name) -{ - auto null_logger = Factory::template create(logger_name); - null_logger->set_level(level::off); - return null_logger; -} - -template -inline std::shared_ptr null_logger_st(const std::string &logger_name) -{ - auto null_logger = Factory::template create(logger_name); - null_logger->set_level(level::off); - return null_logger; -} - -} // namespace spdlog diff --git a/tpl/spdlog/include/spdlog/sinks/ostream_sink.h b/tpl/spdlog/include/spdlog/sinks/ostream_sink.h deleted file mode 100644 index 95c1e96..0000000 --- a/tpl/spdlog/include/spdlog/sinks/ostream_sink.h +++ /dev/null @@ -1,50 +0,0 @@ -// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. -// Distributed under the MIT License (http://opensource.org/licenses/MIT) - -#pragma once - -#include -#include - -#include -#include - -namespace spdlog { -namespace sinks { -template -class ostream_sink final : public base_sink -{ -public: - explicit ostream_sink(std::ostream &os, bool force_flush = false) - : ostream_(os) - , force_flush_(force_flush) - {} - ostream_sink(const ostream_sink &) = delete; - ostream_sink &operator=(const ostream_sink &) = delete; - -protected: - void sink_it_(const details::log_msg &msg) override - { - memory_buf_t formatted; - base_sink::formatter_->format(msg, formatted); - ostream_.write(formatted.data(), static_cast(formatted.size())); - if (force_flush_) - { - ostream_.flush(); - } - } - - void flush_() override - { - ostream_.flush(); - } - - std::ostream &ostream_; - bool force_flush_; -}; - -using ostream_sink_mt = ostream_sink; -using ostream_sink_st = ostream_sink; - -} // namespace sinks -} // namespace spdlog diff --git a/tpl/spdlog/include/spdlog/sinks/qt_sinks.h b/tpl/spdlog/include/spdlog/sinks/qt_sinks.h deleted file mode 100644 index f801ac3..0000000 --- a/tpl/spdlog/include/spdlog/sinks/qt_sinks.h +++ /dev/null @@ -1,292 +0,0 @@ -// Copyright(c) 2015-present, Gabi Melman, mguludag and spdlog contributors. -// Distributed under the MIT License (http://opensource.org/licenses/MIT) - -#pragma once - -// -// Custom sink for QPlainTextEdit or QTextEdit and its childs(QTextBrowser... -// etc) Building and using requires Qt library. -// -// Warning: the qt_sink won't be notified if the target widget is destroyed. -// If the widget's lifetime can be shorter than the logger's one, you should provide some permanent QObject, -// and then use a standard signal/slot. -// - -#include "spdlog/common.h" -#include "spdlog/details/log_msg.h" -#include "spdlog/details/synchronous_factory.h" -#include "spdlog/sinks/base_sink.h" -#include - -#include -#include - -// -// qt_sink class -// -namespace spdlog { -namespace sinks { -template -class qt_sink : public base_sink -{ -public: - qt_sink(QObject *qt_object, std::string meta_method) - : qt_object_(qt_object) - , meta_method_(std::move(meta_method)) - { - if (!qt_object_) - { - throw_spdlog_ex("qt_sink: qt_object is null"); - } - } - - ~qt_sink() - { - flush_(); - } - -protected: - void sink_it_(const details::log_msg &msg) override - { - memory_buf_t formatted; - base_sink::formatter_->format(msg, formatted); - const string_view_t str = string_view_t(formatted.data(), formatted.size()); - QMetaObject::invokeMethod(qt_object_, meta_method_.c_str(), Qt::AutoConnection, - Q_ARG(QString, QString::fromUtf8(str.data(), static_cast(str.size())).trimmed())); - } - - void flush_() override {} - -private: - QObject *qt_object_ = nullptr; - std::string meta_method_; -}; - -// QT color sink to QTextEdit. -// Color location is determined by the sink log pattern like in the rest of spdlog sinks. -// Colors can be modified if needed using sink->set_color(level, qtTextCharFormat). -// max_lines is the maximum number of lines that the sink will hold before removing the oldest lines. -// Note: Only ascii (latin1) is supported by this sink. -template -class qt_color_sink : public base_sink -{ -public: - qt_color_sink(QTextEdit *qt_text_edit, int max_lines) - : qt_text_edit_(qt_text_edit) - , max_lines_(max_lines) - { - if (!qt_text_edit_) - { - throw_spdlog_ex("qt_color_text_sink: text_edit is null"); - } - - default_color_ = qt_text_edit_->currentCharFormat(); - // set colors - QTextCharFormat format; - // trace - format.setForeground(Qt::gray); - colors_.at(level::trace) = format; - // debug - format.setForeground(Qt::cyan); - colors_.at(level::debug) = format; - // info - format.setForeground(Qt::green); - colors_.at(level::info) = format; - // warn - format.setForeground(Qt::yellow); - colors_.at(level::warn) = format; - // err - format.setForeground(Qt::red); - colors_.at(level::err) = format; - // critical - format.setForeground(Qt::white); - format.setBackground(Qt::red); - colors_.at(level::critical) = format; - } - - ~qt_color_sink() - { - flush_(); - } - - void set_default_color(QTextCharFormat format) - { - // std::lock_guard lock(base_sink::mutex_); - default_color_ = format; - } - - void set_level_color(level::level_enum color_level, QTextCharFormat format) - { - // std::lock_guard lock(base_sink::mutex_); - colors_.at(static_cast(color_level)) = format; - } - - QTextCharFormat &get_level_color(level::level_enum color_level) - { - std::lock_guard lock(base_sink::mutex_); - return colors_.at(static_cast(color_level)); - } - - QTextCharFormat &get_default_color() - { - std::lock_guard lock(base_sink::mutex_); - return default_color_; - } - -protected: - struct invoke_params - { - invoke_params(int max_lines, QTextEdit *q_text_edit, QString payload, QTextCharFormat default_color, QTextCharFormat level_color, - int color_range_start, int color_range_end) - : max_lines(max_lines) - , q_text_edit(q_text_edit) - , payload(std::move(payload)) - , default_color(default_color) - , level_color(level_color) - , color_range_start(color_range_start) - , color_range_end(color_range_end) - {} - int max_lines; - QTextEdit *q_text_edit; - QString payload; - QTextCharFormat default_color; - QTextCharFormat level_color; - int color_range_start; - int color_range_end; - }; - - void sink_it_(const details::log_msg &msg) override - { - memory_buf_t formatted; - base_sink::formatter_->format(msg, formatted); - - const string_view_t str = string_view_t(formatted.data(), formatted.size()); - // apply the color to the color range in the formatted message. - auto payload = QString::fromLatin1(str.data(), static_cast(str.size())); - - invoke_params params{max_lines_, // max lines - qt_text_edit_, // text edit to append to - std::move(payload), // text to append - default_color_, // default color - colors_.at(msg.level), // color to apply - static_cast(msg.color_range_start), // color range start - static_cast(msg.color_range_end)}; // color range end - - QMetaObject::invokeMethod( - qt_text_edit_, [params]() { invoke_method_(params); }, Qt::AutoConnection); - } - - void flush_() override {} - - // Add colored text to the text edit widget. This method is invoked in the GUI thread. - // It is a static method to ensure that it is handled correctly even if the sink is destroyed prematurely - // before it is invoked. - - static void invoke_method_(invoke_params params) - { - auto *document = params.q_text_edit->document(); - QTextCursor cursor(document); - - // remove first blocks if number of blocks exceeds max_lines - while (document->blockCount() > params.max_lines) - { - cursor.select(QTextCursor::BlockUnderCursor); - cursor.removeSelectedText(); - cursor.deleteChar(); // delete the newline after the block - } - - cursor.movePosition(QTextCursor::End); - cursor.setCharFormat(params.default_color); - - // if color range not specified or not not valid, just append the text with default color - if (params.color_range_end <= params.color_range_start) - { - cursor.insertText(params.payload); - return; - } - - // insert the text before the color range - cursor.insertText(params.payload.left(params.color_range_start)); - - // insert the colorized text - cursor.setCharFormat(params.level_color); - cursor.insertText(params.payload.mid(params.color_range_start, params.color_range_end - params.color_range_start)); - - // insert the text after the color range with default format - cursor.setCharFormat(params.default_color); - cursor.insertText(params.payload.mid(params.color_range_end)); - } - - QTextEdit *qt_text_edit_; - int max_lines_; - QTextCharFormat default_color_; - std::array colors_; -}; - -#include "spdlog/details/null_mutex.h" -#include - -using qt_sink_mt = qt_sink; -using qt_sink_st = qt_sink; -using qt_color_sink_mt = qt_color_sink; -using qt_color_sink_st = qt_color_sink; -} // namespace sinks - -// -// Factory functions -// - -// log to QTextEdit -template -inline std::shared_ptr qt_logger_mt(const std::string &logger_name, QTextEdit *qt_object, const std::string &meta_method = "append") -{ - return Factory::template create(logger_name, qt_object, meta_method); -} - -template -inline std::shared_ptr qt_logger_st(const std::string &logger_name, QTextEdit *qt_object, const std::string &meta_method = "append") -{ - return Factory::template create(logger_name, qt_object, meta_method); -} - -// log to QPlainTextEdit -template -inline std::shared_ptr qt_logger_mt( - const std::string &logger_name, QPlainTextEdit *qt_object, const std::string &meta_method = "appendPlainText") -{ - return Factory::template create(logger_name, qt_object, meta_method); -} - -template -inline std::shared_ptr qt_logger_st( - const std::string &logger_name, QPlainTextEdit *qt_object, const std::string &meta_method = "appendPlainText") -{ - return Factory::template create(logger_name, qt_object, meta_method); -} -// log to QObject -template -inline std::shared_ptr qt_logger_mt(const std::string &logger_name, QObject *qt_object, const std::string &meta_method) -{ - return Factory::template create(logger_name, qt_object, meta_method); -} - -template -inline std::shared_ptr qt_logger_st(const std::string &logger_name, QObject *qt_object, const std::string &meta_method) -{ - return Factory::template create(logger_name, qt_object, meta_method); -} - -// log to QTextEdit with colorize output -template -inline std::shared_ptr qt_color_logger_mt(const std::string &logger_name, QTextEdit *qt_text_edit, int max_lines) -{ - return Factory::template create(logger_name, qt_text_edit, max_lines); -} - -template -inline std::shared_ptr qt_color_logger_st(const std::string &logger_name, QTextEdit *qt_text_edit, int max_lines) -{ - return Factory::template create(logger_name, qt_text_edit, max_lines); -} - -} // namespace spdlog diff --git a/tpl/spdlog/include/spdlog/sinks/ringbuffer_sink.h b/tpl/spdlog/include/spdlog/sinks/ringbuffer_sink.h deleted file mode 100644 index 3ca47c6..0000000 --- a/tpl/spdlog/include/spdlog/sinks/ringbuffer_sink.h +++ /dev/null @@ -1,74 +0,0 @@ -// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. -// Distributed under the MIT License (http://opensource.org/licenses/MIT) - -#pragma once - -#include "spdlog/sinks/base_sink.h" -#include "spdlog/details/circular_q.h" -#include "spdlog/details/log_msg_buffer.h" -#include "spdlog/details/null_mutex.h" - -#include -#include -#include - -namespace spdlog { -namespace sinks { -/* - * Ring buffer sink - */ -template -class ringbuffer_sink final : public base_sink -{ -public: - explicit ringbuffer_sink(size_t n_items) - : q_{n_items} - {} - - std::vector last_raw(size_t lim = 0) - { - std::lock_guard lock(base_sink::mutex_); - auto items_available = q_.size(); - auto n_items = lim > 0 ? (std::min)(lim, items_available) : items_available; - std::vector ret; - ret.reserve(n_items); - for (size_t i = (items_available - n_items); i < items_available; i++) - { - ret.push_back(q_.at(i)); - } - return ret; - } - - std::vector last_formatted(size_t lim = 0) - { - std::lock_guard lock(base_sink::mutex_); - auto items_available = q_.size(); - auto n_items = lim > 0 ? (std::min)(lim, items_available) : items_available; - std::vector ret; - ret.reserve(n_items); - for (size_t i = (items_available - n_items); i < items_available; i++) - { - memory_buf_t formatted; - base_sink::formatter_->format(q_.at(i), formatted); - ret.push_back(SPDLOG_BUF_TO_STRING(formatted)); - } - return ret; - } - -protected: - void sink_it_(const details::log_msg &msg) override - { - q_.push_back(details::log_msg_buffer{msg}); - } - void flush_() override {} - -private: - details::circular_q q_; -}; - -using ringbuffer_sink_mt = ringbuffer_sink; -using ringbuffer_sink_st = ringbuffer_sink; - -} // namespace sinks - -} // namespace spdlog diff --git a/tpl/spdlog/include/spdlog/sinks/rotating_file_sink-inl.h b/tpl/spdlog/include/spdlog/sinks/rotating_file_sink-inl.h deleted file mode 100644 index cf8b9d5..0000000 --- a/tpl/spdlog/include/spdlog/sinks/rotating_file_sink-inl.h +++ /dev/null @@ -1,152 +0,0 @@ -// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. -// Distributed under the MIT License (http://opensource.org/licenses/MIT) - -#pragma once - -#ifndef SPDLOG_HEADER_ONLY -# include -#endif - -#include - -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -namespace spdlog { -namespace sinks { - -template -SPDLOG_INLINE rotating_file_sink::rotating_file_sink( - filename_t base_filename, std::size_t max_size, std::size_t max_files, bool rotate_on_open, const file_event_handlers &event_handlers) - : base_filename_(std::move(base_filename)) - , max_size_(max_size) - , max_files_(max_files) - , file_helper_{event_handlers} -{ - if (max_size == 0) - { - throw_spdlog_ex("rotating sink constructor: max_size arg cannot be zero"); - } - - if (max_files > 200000) - { - throw_spdlog_ex("rotating sink constructor: max_files arg cannot exceed 200000"); - } - file_helper_.open(calc_filename(base_filename_, 0)); - current_size_ = file_helper_.size(); // expensive. called only once - if (rotate_on_open && current_size_ > 0) - { - rotate_(); - current_size_ = 0; - } -} - -// calc filename according to index and file extension if exists. -// e.g. calc_filename("logs/mylog.txt, 3) => "logs/mylog.3.txt". -template -SPDLOG_INLINE filename_t rotating_file_sink::calc_filename(const filename_t &filename, std::size_t index) -{ - if (index == 0u) - { - return filename; - } - - filename_t basename, ext; - std::tie(basename, ext) = details::file_helper::split_by_extension(filename); - return fmt_lib::format(SPDLOG_FILENAME_T("{}.{}{}"), basename, index, ext); -} - -template -SPDLOG_INLINE filename_t rotating_file_sink::filename() -{ - std::lock_guard lock(base_sink::mutex_); - return file_helper_.filename(); -} - -template -SPDLOG_INLINE void rotating_file_sink::sink_it_(const details::log_msg &msg) -{ - memory_buf_t formatted; - base_sink::formatter_->format(msg, formatted); - auto new_size = current_size_ + formatted.size(); - - // rotate if the new estimated file size exceeds max size. - // rotate only if the real size > 0 to better deal with full disk (see issue #2261). - // we only check the real size when new_size > max_size_ because it is relatively expensive. - if (new_size > max_size_) - { - file_helper_.flush(); - if (file_helper_.size() > 0) - { - rotate_(); - new_size = formatted.size(); - } - } - file_helper_.write(formatted); - current_size_ = new_size; -} - -template -SPDLOG_INLINE void rotating_file_sink::flush_() -{ - file_helper_.flush(); -} - -// Rotate files: -// log.txt -> log.1.txt -// log.1.txt -> log.2.txt -// log.2.txt -> log.3.txt -// log.3.txt -> delete -template -SPDLOG_INLINE void rotating_file_sink::rotate_() -{ - using details::os::filename_to_str; - using details::os::path_exists; - - file_helper_.close(); - for (auto i = max_files_; i > 0; --i) - { - filename_t src = calc_filename(base_filename_, i - 1); - if (!path_exists(src)) - { - continue; - } - filename_t target = calc_filename(base_filename_, i); - - if (!rename_file_(src, target)) - { - // if failed try again after a small delay. - // this is a workaround to a windows issue, where very high rotation - // rates can cause the rename to fail with permission denied (because of antivirus?). - details::os::sleep_for_millis(100); - if (!rename_file_(src, target)) - { - file_helper_.reopen(true); // truncate the log file anyway to prevent it to grow beyond its limit! - current_size_ = 0; - throw_spdlog_ex("rotating_file_sink: failed renaming " + filename_to_str(src) + " to " + filename_to_str(target), errno); - } - } - } - file_helper_.reopen(true); -} - -// delete the target if exists, and rename the src file to target -// return true on success, false otherwise. -template -SPDLOG_INLINE bool rotating_file_sink::rename_file_(const filename_t &src_filename, const filename_t &target_filename) -{ - // try to delete the target file in case it already exists. - (void)details::os::remove(target_filename); - return details::os::rename(src_filename, target_filename) == 0; -} - -} // namespace sinks -} // namespace spdlog diff --git a/tpl/spdlog/include/spdlog/sinks/rotating_file_sink.h b/tpl/spdlog/include/spdlog/sinks/rotating_file_sink.h deleted file mode 100644 index ce0d7b1..0000000 --- a/tpl/spdlog/include/spdlog/sinks/rotating_file_sink.h +++ /dev/null @@ -1,81 +0,0 @@ -// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. -// Distributed under the MIT License (http://opensource.org/licenses/MIT) - -#pragma once - -#include -#include -#include -#include - -#include -#include -#include - -namespace spdlog { -namespace sinks { - -// -// Rotating file sink based on size -// -template -class rotating_file_sink final : public base_sink -{ -public: - rotating_file_sink(filename_t base_filename, std::size_t max_size, std::size_t max_files, bool rotate_on_open = false, - const file_event_handlers &event_handlers = {}); - static filename_t calc_filename(const filename_t &filename, std::size_t index); - filename_t filename(); - -protected: - void sink_it_(const details::log_msg &msg) override; - void flush_() override; - -private: - // Rotate files: - // log.txt -> log.1.txt - // log.1.txt -> log.2.txt - // log.2.txt -> log.3.txt - // log.3.txt -> delete - void rotate_(); - - // delete the target if exists, and rename the src file to target - // return true on success, false otherwise. - bool rename_file_(const filename_t &src_filename, const filename_t &target_filename); - - filename_t base_filename_; - std::size_t max_size_; - std::size_t max_files_; - std::size_t current_size_; - details::file_helper file_helper_; -}; - -using rotating_file_sink_mt = rotating_file_sink; -using rotating_file_sink_st = rotating_file_sink; - -} // namespace sinks - -// -// factory functions -// - -template -inline std::shared_ptr rotating_logger_mt(const std::string &logger_name, const filename_t &filename, size_t max_file_size, - size_t max_files, bool rotate_on_open = false, const file_event_handlers &event_handlers = {}) -{ - return Factory::template create( - logger_name, filename, max_file_size, max_files, rotate_on_open, event_handlers); -} - -template -inline std::shared_ptr rotating_logger_st(const std::string &logger_name, const filename_t &filename, size_t max_file_size, - size_t max_files, bool rotate_on_open = false, const file_event_handlers &event_handlers = {}) -{ - return Factory::template create( - logger_name, filename, max_file_size, max_files, rotate_on_open, event_handlers); -} -} // namespace spdlog - -#ifdef SPDLOG_HEADER_ONLY -# include "rotating_file_sink-inl.h" -#endif diff --git a/tpl/spdlog/include/spdlog/sinks/sink-inl.h b/tpl/spdlog/include/spdlog/sinks/sink-inl.h deleted file mode 100644 index df07add..0000000 --- a/tpl/spdlog/include/spdlog/sinks/sink-inl.h +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. -// Distributed under the MIT License (http://opensource.org/licenses/MIT) - -#pragma once - -#ifndef SPDLOG_HEADER_ONLY -# include -#endif - -#include - -SPDLOG_INLINE bool spdlog::sinks::sink::should_log(spdlog::level::level_enum msg_level) const -{ - return msg_level >= level_.load(std::memory_order_relaxed); -} - -SPDLOG_INLINE void spdlog::sinks::sink::set_level(level::level_enum log_level) -{ - level_.store(log_level, std::memory_order_relaxed); -} - -SPDLOG_INLINE spdlog::level::level_enum spdlog::sinks::sink::level() const -{ - return static_cast(level_.load(std::memory_order_relaxed)); -} diff --git a/tpl/spdlog/include/spdlog/sinks/sink.h b/tpl/spdlog/include/spdlog/sinks/sink.h deleted file mode 100644 index 0a28ccc..0000000 --- a/tpl/spdlog/include/spdlog/sinks/sink.h +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. -// Distributed under the MIT License (http://opensource.org/licenses/MIT) - -#pragma once - -#include -#include - -namespace spdlog { - -namespace sinks { -class SPDLOG_API sink -{ -public: - virtual ~sink() = default; - virtual void log(const details::log_msg &msg) = 0; - virtual void flush() = 0; - virtual void set_pattern(const std::string &pattern) = 0; - virtual void set_formatter(std::unique_ptr sink_formatter) = 0; - - void set_level(level::level_enum log_level); - level::level_enum level() const; - bool should_log(level::level_enum msg_level) const; - -protected: - // sink log level - default is all - level_t level_{level::trace}; -}; - -} // namespace sinks -} // namespace spdlog - -#ifdef SPDLOG_HEADER_ONLY -# include "sink-inl.h" -#endif diff --git a/tpl/spdlog/include/spdlog/sinks/stdout_color_sinks-inl.h b/tpl/spdlog/include/spdlog/sinks/stdout_color_sinks-inl.h deleted file mode 100644 index 066df18..0000000 --- a/tpl/spdlog/include/spdlog/sinks/stdout_color_sinks-inl.h +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. -// Distributed under the MIT License (http://opensource.org/licenses/MIT) - -#pragma once - -#ifndef SPDLOG_HEADER_ONLY -# include -#endif - -#include -#include - -namespace spdlog { - -template -SPDLOG_INLINE std::shared_ptr stdout_color_mt(const std::string &logger_name, color_mode mode) -{ - return Factory::template create(logger_name, mode); -} - -template -SPDLOG_INLINE std::shared_ptr stdout_color_st(const std::string &logger_name, color_mode mode) -{ - return Factory::template create(logger_name, mode); -} - -template -SPDLOG_INLINE std::shared_ptr stderr_color_mt(const std::string &logger_name, color_mode mode) -{ - return Factory::template create(logger_name, mode); -} - -template -SPDLOG_INLINE std::shared_ptr stderr_color_st(const std::string &logger_name, color_mode mode) -{ - return Factory::template create(logger_name, mode); -} -} // namespace spdlog diff --git a/tpl/spdlog/include/spdlog/sinks/stdout_color_sinks.h b/tpl/spdlog/include/spdlog/sinks/stdout_color_sinks.h deleted file mode 100644 index 420b13a..0000000 --- a/tpl/spdlog/include/spdlog/sinks/stdout_color_sinks.h +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. -// Distributed under the MIT License (http://opensource.org/licenses/MIT) - -#pragma once - -#ifdef _WIN32 -# include -#else -# include -#endif - -#include - -namespace spdlog { -namespace sinks { -#ifdef _WIN32 -using stdout_color_sink_mt = wincolor_stdout_sink_mt; -using stdout_color_sink_st = wincolor_stdout_sink_st; -using stderr_color_sink_mt = wincolor_stderr_sink_mt; -using stderr_color_sink_st = wincolor_stderr_sink_st; -#else -using stdout_color_sink_mt = ansicolor_stdout_sink_mt; -using stdout_color_sink_st = ansicolor_stdout_sink_st; -using stderr_color_sink_mt = ansicolor_stderr_sink_mt; -using stderr_color_sink_st = ansicolor_stderr_sink_st; -#endif -} // namespace sinks - -template -std::shared_ptr stdout_color_mt(const std::string &logger_name, color_mode mode = color_mode::automatic); - -template -std::shared_ptr stdout_color_st(const std::string &logger_name, color_mode mode = color_mode::automatic); - -template -std::shared_ptr stderr_color_mt(const std::string &logger_name, color_mode mode = color_mode::automatic); - -template -std::shared_ptr stderr_color_st(const std::string &logger_name, color_mode mode = color_mode::automatic); - -} // namespace spdlog - -#ifdef SPDLOG_HEADER_ONLY -# include "stdout_color_sinks-inl.h" -#endif diff --git a/tpl/spdlog/include/spdlog/sinks/stdout_sinks-inl.h b/tpl/spdlog/include/spdlog/sinks/stdout_sinks-inl.h deleted file mode 100644 index c175437..0000000 --- a/tpl/spdlog/include/spdlog/sinks/stdout_sinks-inl.h +++ /dev/null @@ -1,138 +0,0 @@ -// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. -// Distributed under the MIT License (http://opensource.org/licenses/MIT) - -#pragma once - -#ifndef SPDLOG_HEADER_ONLY -# include -#endif - -#include -#include -#include - -#ifdef _WIN32 -// under windows using fwrite to non-binary stream results in \r\r\n (see issue #1675) -// so instead we use ::FileWrite -# include - -# ifndef _USING_V110_SDK71_ // fileapi.h doesn't exist in winxp -# include // WriteFile (..) -# endif - -# include // _get_osfhandle(..) -# include // _fileno(..) -#endif // WIN32 - -namespace spdlog { - -namespace sinks { - -template -SPDLOG_INLINE stdout_sink_base::stdout_sink_base(FILE *file) - : mutex_(ConsoleMutex::mutex()) - , file_(file) - , formatter_(details::make_unique()) -{ -#ifdef _WIN32 - // get windows handle from the FILE* object - - handle_ = reinterpret_cast(::_get_osfhandle(::_fileno(file_))); - - // don't throw to support cases where no console is attached, - // and let the log method to do nothing if (handle_ == INVALID_HANDLE_VALUE). - // throw only if non stdout/stderr target is requested (probably regular file and not console). - if (handle_ == INVALID_HANDLE_VALUE && file != stdout && file != stderr) - { - throw_spdlog_ex("spdlog::stdout_sink_base: _get_osfhandle() failed", errno); - } -#endif // WIN32 -} - -template -SPDLOG_INLINE void stdout_sink_base::log(const details::log_msg &msg) -{ -#ifdef _WIN32 - if (handle_ == INVALID_HANDLE_VALUE) - { - return; - } - std::lock_guard lock(mutex_); - memory_buf_t formatted; - formatter_->format(msg, formatted); - auto size = static_cast(formatted.size()); - DWORD bytes_written = 0; - bool ok = ::WriteFile(handle_, formatted.data(), size, &bytes_written, nullptr) != 0; - if (!ok) - { - throw_spdlog_ex("stdout_sink_base: WriteFile() failed. GetLastError(): " + std::to_string(::GetLastError())); - } -#else - std::lock_guard lock(mutex_); - memory_buf_t formatted; - formatter_->format(msg, formatted); - ::fwrite(formatted.data(), sizeof(char), formatted.size(), file_); -#endif // WIN32 - ::fflush(file_); // flush every line to terminal -} - -template -SPDLOG_INLINE void stdout_sink_base::flush() -{ - std::lock_guard lock(mutex_); - fflush(file_); -} - -template -SPDLOG_INLINE void stdout_sink_base::set_pattern(const std::string &pattern) -{ - std::lock_guard lock(mutex_); - formatter_ = std::unique_ptr(new pattern_formatter(pattern)); -} - -template -SPDLOG_INLINE void stdout_sink_base::set_formatter(std::unique_ptr sink_formatter) -{ - std::lock_guard lock(mutex_); - formatter_ = std::move(sink_formatter); -} - -// stdout sink -template -SPDLOG_INLINE stdout_sink::stdout_sink() - : stdout_sink_base(stdout) -{} - -// stderr sink -template -SPDLOG_INLINE stderr_sink::stderr_sink() - : stdout_sink_base(stderr) -{} - -} // namespace sinks - -// factory methods -template -SPDLOG_INLINE std::shared_ptr stdout_logger_mt(const std::string &logger_name) -{ - return Factory::template create(logger_name); -} - -template -SPDLOG_INLINE std::shared_ptr stdout_logger_st(const std::string &logger_name) -{ - return Factory::template create(logger_name); -} - -template -SPDLOG_INLINE std::shared_ptr stderr_logger_mt(const std::string &logger_name) -{ - return Factory::template create(logger_name); -} - -template -SPDLOG_INLINE std::shared_ptr stderr_logger_st(const std::string &logger_name) -{ - return Factory::template create(logger_name); -} -} // namespace spdlog diff --git a/tpl/spdlog/include/spdlog/sinks/stdout_sinks.h b/tpl/spdlog/include/spdlog/sinks/stdout_sinks.h deleted file mode 100644 index 6fdc0de..0000000 --- a/tpl/spdlog/include/spdlog/sinks/stdout_sinks.h +++ /dev/null @@ -1,87 +0,0 @@ -// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. -// Distributed under the MIT License (http://opensource.org/licenses/MIT) - -#pragma once - -#include -#include -#include -#include - -#ifdef _WIN32 -# include -#endif - -namespace spdlog { - -namespace sinks { - -template -class stdout_sink_base : public sink -{ -public: - using mutex_t = typename ConsoleMutex::mutex_t; - explicit stdout_sink_base(FILE *file); - ~stdout_sink_base() override = default; - - stdout_sink_base(const stdout_sink_base &other) = delete; - stdout_sink_base(stdout_sink_base &&other) = delete; - - stdout_sink_base &operator=(const stdout_sink_base &other) = delete; - stdout_sink_base &operator=(stdout_sink_base &&other) = delete; - - void log(const details::log_msg &msg) override; - void flush() override; - void set_pattern(const std::string &pattern) override; - - void set_formatter(std::unique_ptr sink_formatter) override; - -protected: - mutex_t &mutex_; - FILE *file_; - std::unique_ptr formatter_; -#ifdef _WIN32 - HANDLE handle_; -#endif // WIN32 -}; - -template -class stdout_sink : public stdout_sink_base -{ -public: - stdout_sink(); -}; - -template -class stderr_sink : public stdout_sink_base -{ -public: - stderr_sink(); -}; - -using stdout_sink_mt = stdout_sink; -using stdout_sink_st = stdout_sink; - -using stderr_sink_mt = stderr_sink; -using stderr_sink_st = stderr_sink; - -} // namespace sinks - -// factory methods -template -std::shared_ptr stdout_logger_mt(const std::string &logger_name); - -template -std::shared_ptr stdout_logger_st(const std::string &logger_name); - -template -std::shared_ptr stderr_logger_mt(const std::string &logger_name); - -template -std::shared_ptr stderr_logger_st(const std::string &logger_name); - -} // namespace spdlog - -#ifdef SPDLOG_HEADER_ONLY -# include "stdout_sinks-inl.h" -#endif diff --git a/tpl/spdlog/include/spdlog/sinks/syslog_sink.h b/tpl/spdlog/include/spdlog/sinks/syslog_sink.h deleted file mode 100644 index 7c38fcb..0000000 --- a/tpl/spdlog/include/spdlog/sinks/syslog_sink.h +++ /dev/null @@ -1,109 +0,0 @@ -// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. -// Distributed under the MIT License (http://opensource.org/licenses/MIT) - -#pragma once - -#include -#include -#include - -#include -#include -#include - -namespace spdlog { -namespace sinks { -/** - * Sink that write to syslog using the `syscall()` library call. - */ -template -class syslog_sink : public base_sink -{ - -public: - syslog_sink(std::string ident, int syslog_option, int syslog_facility, bool enable_formatting) - : enable_formatting_{enable_formatting} - , syslog_levels_{{/* spdlog::level::trace */ LOG_DEBUG, - /* spdlog::level::debug */ LOG_DEBUG, - /* spdlog::level::info */ LOG_INFO, - /* spdlog::level::warn */ LOG_WARNING, - /* spdlog::level::err */ LOG_ERR, - /* spdlog::level::critical */ LOG_CRIT, - /* spdlog::level::off */ LOG_INFO}} - , ident_{std::move(ident)} - { - // set ident to be program name if empty - ::openlog(ident_.empty() ? nullptr : ident_.c_str(), syslog_option, syslog_facility); - } - - ~syslog_sink() override - { - ::closelog(); - } - - syslog_sink(const syslog_sink &) = delete; - syslog_sink &operator=(const syslog_sink &) = delete; - -protected: - void sink_it_(const details::log_msg &msg) override - { - string_view_t payload; - memory_buf_t formatted; - if (enable_formatting_) - { - base_sink::formatter_->format(msg, formatted); - payload = string_view_t(formatted.data(), formatted.size()); - } - else - { - payload = msg.payload; - } - - size_t length = payload.size(); - // limit to max int - if (length > static_cast(std::numeric_limits::max())) - { - length = static_cast(std::numeric_limits::max()); - } - - ::syslog(syslog_prio_from_level(msg), "%.*s", static_cast(length), payload.data()); - } - - void flush_() override {} - bool enable_formatting_ = false; - -private: - using levels_array = std::array; - levels_array syslog_levels_; - // must store the ident because the man says openlog might use the pointer as - // is and not a string copy - const std::string ident_; - - // - // Simply maps spdlog's log level to syslog priority level. - // - int syslog_prio_from_level(const details::log_msg &msg) const - { - return syslog_levels_.at(static_cast(msg.level)); - } -}; - -using syslog_sink_mt = syslog_sink; -using syslog_sink_st = syslog_sink; -} // namespace sinks - -// Create and register a syslog logger -template -inline std::shared_ptr syslog_logger_mt(const std::string &logger_name, const std::string &syslog_ident = "", int syslog_option = 0, - int syslog_facility = LOG_USER, bool enable_formatting = false) -{ - return Factory::template create(logger_name, syslog_ident, syslog_option, syslog_facility, enable_formatting); -} - -template -inline std::shared_ptr syslog_logger_st(const std::string &logger_name, const std::string &syslog_ident = "", int syslog_option = 0, - int syslog_facility = LOG_USER, bool enable_formatting = false) -{ - return Factory::template create(logger_name, syslog_ident, syslog_option, syslog_facility, enable_formatting); -} -} // namespace spdlog diff --git a/tpl/spdlog/include/spdlog/sinks/systemd_sink.h b/tpl/spdlog/include/spdlog/sinks/systemd_sink.h deleted file mode 100644 index b00a95f..0000000 --- a/tpl/spdlog/include/spdlog/sinks/systemd_sink.h +++ /dev/null @@ -1,126 +0,0 @@ -// Copyright(c) 2019 ZVYAGIN.Alexander@gmail.com -// Distributed under the MIT License (http://opensource.org/licenses/MIT) - -#pragma once - -#include -#include -#include -#include - -#include -#ifndef SD_JOURNAL_SUPPRESS_LOCATION -# define SD_JOURNAL_SUPPRESS_LOCATION -#endif -#include - -namespace spdlog { -namespace sinks { - -/** - * Sink that write to systemd journal using the `sd_journal_send()` library call. - */ -template -class systemd_sink : public base_sink -{ -public: - systemd_sink(std::string ident = "", bool enable_formatting = false) - : ident_{std::move(ident)} - , enable_formatting_{enable_formatting} - , syslog_levels_{{/* spdlog::level::trace */ LOG_DEBUG, - /* spdlog::level::debug */ LOG_DEBUG, - /* spdlog::level::info */ LOG_INFO, - /* spdlog::level::warn */ LOG_WARNING, - /* spdlog::level::err */ LOG_ERR, - /* spdlog::level::critical */ LOG_CRIT, - /* spdlog::level::off */ LOG_INFO}} - {} - - ~systemd_sink() override {} - - systemd_sink(const systemd_sink &) = delete; - systemd_sink &operator=(const systemd_sink &) = delete; - -protected: - const std::string ident_; - bool enable_formatting_ = false; - using levels_array = std::array; - levels_array syslog_levels_; - - void sink_it_(const details::log_msg &msg) override - { - int err; - string_view_t payload; - memory_buf_t formatted; - if (enable_formatting_) - { - base_sink::formatter_->format(msg, formatted); - payload = string_view_t(formatted.data(), formatted.size()); - } - else - { - payload = msg.payload; - } - - size_t length = payload.size(); - // limit to max int - if (length > static_cast(std::numeric_limits::max())) - { - length = static_cast(std::numeric_limits::max()); - } - - const string_view_t syslog_identifier = ident_.empty() ? msg.logger_name : ident_; - - // Do not send source location if not available - if (msg.source.empty()) - { - // Note: function call inside '()' to avoid macro expansion - err = (sd_journal_send)("MESSAGE=%.*s", static_cast(length), payload.data(), "PRIORITY=%d", syslog_level(msg.level), -#ifndef SPDLOG_NO_THREAD_ID - "TID=%zu", details::os::thread_id(), -#endif - "SYSLOG_IDENTIFIER=%.*s", static_cast(syslog_identifier.size()), syslog_identifier.data(), nullptr); - } - else - { - err = (sd_journal_send)("MESSAGE=%.*s", static_cast(length), payload.data(), "PRIORITY=%d", syslog_level(msg.level), -#ifndef SPDLOG_NO_THREAD_ID - "TID=%zu", details::os::thread_id(), -#endif - "SYSLOG_IDENTIFIER=%.*s", static_cast(syslog_identifier.size()), syslog_identifier.data(), "CODE_FILE=%s", - msg.source.filename, "CODE_LINE=%d", msg.source.line, "CODE_FUNC=%s", msg.source.funcname, nullptr); - } - - if (err) - { - throw_spdlog_ex("Failed writing to systemd", errno); - } - } - - int syslog_level(level::level_enum l) - { - return syslog_levels_.at(static_cast(l)); - } - - void flush_() override {} -}; - -using systemd_sink_mt = systemd_sink; -using systemd_sink_st = systemd_sink; -} // namespace sinks - -// Create and register a syslog logger -template -inline std::shared_ptr systemd_logger_mt( - const std::string &logger_name, const std::string &ident = "", bool enable_formatting = false) -{ - return Factory::template create(logger_name, ident, enable_formatting); -} - -template -inline std::shared_ptr systemd_logger_st( - const std::string &logger_name, const std::string &ident = "", bool enable_formatting = false) -{ - return Factory::template create(logger_name, ident, enable_formatting); -} -} // namespace spdlog diff --git a/tpl/spdlog/include/spdlog/sinks/tcp_sink.h b/tpl/spdlog/include/spdlog/sinks/tcp_sink.h deleted file mode 100644 index e0efb31..0000000 --- a/tpl/spdlog/include/spdlog/sinks/tcp_sink.h +++ /dev/null @@ -1,81 +0,0 @@ -// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. -// Distributed under the MIT License (http://opensource.org/licenses/MIT) - -#pragma once - -#include -#include -#include -#ifdef _WIN32 -# include -#else -# include -#endif - -#include -#include -#include -#include - -#pragma once - -// Simple tcp client sink -// Connects to remote address and send the formatted log. -// Will attempt to reconnect if connection drops. -// If more complicated behaviour is needed (i.e get responses), you can inherit it and override the sink_it_ method. - -namespace spdlog { -namespace sinks { - -struct tcp_sink_config -{ - std::string server_host; - int server_port; - bool lazy_connect = false; // if true connect on first log call instead of on construction - - tcp_sink_config(std::string host, int port) - : server_host{std::move(host)} - , server_port{port} - {} -}; - -template -class tcp_sink : public spdlog::sinks::base_sink -{ -public: - // connect to tcp host/port or throw if failed - // host can be hostname or ip address - - explicit tcp_sink(tcp_sink_config sink_config) - : config_{std::move(sink_config)} - { - if (!config_.lazy_connect) - { - this->client_.connect(config_.server_host, config_.server_port); - } - } - - ~tcp_sink() override = default; - -protected: - void sink_it_(const spdlog::details::log_msg &msg) override - { - spdlog::memory_buf_t formatted; - spdlog::sinks::base_sink::formatter_->format(msg, formatted); - if (!client_.is_connected()) - { - client_.connect(config_.server_host, config_.server_port); - } - client_.send(formatted.data(), formatted.size()); - } - - void flush_() override {} - tcp_sink_config config_; - details::tcp_client client_; -}; - -using tcp_sink_mt = tcp_sink; -using tcp_sink_st = tcp_sink; - -} // namespace sinks -} // namespace spdlog diff --git a/tpl/spdlog/include/spdlog/sinks/udp_sink.h b/tpl/spdlog/include/spdlog/sinks/udp_sink.h deleted file mode 100644 index ccbce2b..0000000 --- a/tpl/spdlog/include/spdlog/sinks/udp_sink.h +++ /dev/null @@ -1,74 +0,0 @@ -// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. -// Distributed under the MIT License (http://opensource.org/licenses/MIT) - -#pragma once - -#include -#include -#include -#ifdef _WIN32 -# include -#else -# include -#endif - -#include -#include -#include -#include - -// Simple udp client sink -// Sends formatted log via udp - -namespace spdlog { -namespace sinks { - -struct udp_sink_config -{ - std::string server_host; - uint16_t server_port; - - udp_sink_config(std::string host, uint16_t port) - : server_host{std::move(host)} - , server_port{port} - {} -}; - -template -class udp_sink : public spdlog::sinks::base_sink -{ -public: - // host can be hostname or ip address - explicit udp_sink(udp_sink_config sink_config) - : client_{sink_config.server_host, sink_config.server_port} - {} - - ~udp_sink() override = default; - -protected: - void sink_it_(const spdlog::details::log_msg &msg) override - { - spdlog::memory_buf_t formatted; - spdlog::sinks::base_sink::formatter_->format(msg, formatted); - client_.send(formatted.data(), formatted.size()); - } - - void flush_() override {} - details::udp_client client_; -}; - -using udp_sink_mt = udp_sink; -using udp_sink_st = udp_sink; - -} // namespace sinks - -// -// factory functions -// -template -inline std::shared_ptr udp_logger_mt(const std::string &logger_name, sinks::udp_sink_config skin_config) -{ - return Factory::template create(logger_name, skin_config); -} - -} // namespace spdlog diff --git a/tpl/spdlog/include/spdlog/sinks/win_eventlog_sink.h b/tpl/spdlog/include/spdlog/sinks/win_eventlog_sink.h deleted file mode 100644 index d23d00a..0000000 --- a/tpl/spdlog/include/spdlog/sinks/win_eventlog_sink.h +++ /dev/null @@ -1,289 +0,0 @@ -// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. -// Distributed under the MIT License (http://opensource.org/licenses/MIT) - -// Writing to Windows Event Log requires the registry entries below to be present, with the following modifications: -// 1. should be replaced with your log name (e.g. your application name) -// 2. should be replaced with the specific source name and the key should be duplicated for -// each source used in the application -// -// Since typically modifications of this kind require elevation, it's better to do it as a part of setup procedure. -// The snippet below uses mscoree.dll as the message file as it exists on most of the Windows systems anyway and -// happens to contain the needed resource. -// -// You can also specify a custom message file if needed. -// Please refer to Event Log functions descriptions in MSDN for more details on custom message files. - -/*--------------------------------------------------------------------------------------- - -Windows Registry Editor Version 5.00 - -[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\EventLog\] - -[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\EventLog\\] -"TypesSupported"=dword:00000007 -"EventMessageFile"=hex(2):25,00,73,00,79,00,73,00,74,00,65,00,6d,00,72,00,6f,\ - 00,6f,00,74,00,25,00,5c,00,53,00,79,00,73,00,74,00,65,00,6d,00,33,00,32,00,\ - 5c,00,6d,00,73,00,63,00,6f,00,72,00,65,00,65,00,2e,00,64,00,6c,00,6c,00,00,\ - 00 - ------------------------------------------------------------------------------------------*/ - -#pragma once - -#include -#include - -#include -#include - -#include -#include -#include - -namespace spdlog { -namespace sinks { - -namespace win_eventlog { - -namespace internal { - -struct local_alloc_t -{ - HLOCAL hlocal_; - - SPDLOG_CONSTEXPR local_alloc_t() SPDLOG_NOEXCEPT : hlocal_(nullptr) {} - - local_alloc_t(local_alloc_t const &) = delete; - local_alloc_t &operator=(local_alloc_t const &) = delete; - - ~local_alloc_t() SPDLOG_NOEXCEPT - { - if (hlocal_) - { - LocalFree(hlocal_); - } - } -}; - -/** Windows error */ -struct win32_error : public spdlog_ex -{ - /** Formats an error report line: "user-message: error-code (system message)" */ - static std::string format(std::string const &user_message, DWORD error_code = GetLastError()) - { - std::string system_message; - - local_alloc_t format_message_result{}; - auto format_message_succeeded = - ::FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, nullptr, - error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&format_message_result.hlocal_, 0, nullptr); - - if (format_message_succeeded && format_message_result.hlocal_) - { - system_message = fmt_lib::format(" ({})", (LPSTR)format_message_result.hlocal_); - } - - return fmt_lib::format("{}: {}{}", user_message, error_code, system_message); - } - - explicit win32_error(std::string const &func_name, DWORD error = GetLastError()) - : spdlog_ex(format(func_name, error)) - {} -}; - -/** Wrapper for security identifiers (SID) on Windows */ -struct sid_t -{ - std::vector buffer_; - -public: - sid_t() {} - - /** creates a wrapped SID copy */ - static sid_t duplicate_sid(PSID psid) - { - if (!::IsValidSid(psid)) - { - throw_spdlog_ex("sid_t::sid_t(): invalid SID received"); - } - - auto const sid_length{::GetLengthSid(psid)}; - - sid_t result; - result.buffer_.resize(sid_length); - if (!::CopySid(sid_length, (PSID)result.as_sid(), psid)) - { - SPDLOG_THROW(win32_error("CopySid")); - } - - return result; - } - - /** Retrieves pointer to the internal buffer contents as SID* */ - SID *as_sid() const - { - return buffer_.empty() ? nullptr : (SID *)buffer_.data(); - } - - /** Get SID for the current user */ - static sid_t get_current_user_sid() - { - /* create and init RAII holder for process token */ - struct process_token_t - { - HANDLE token_handle_ = INVALID_HANDLE_VALUE; - explicit process_token_t(HANDLE process) - { - if (!::OpenProcessToken(process, TOKEN_QUERY, &token_handle_)) - { - SPDLOG_THROW(win32_error("OpenProcessToken")); - } - } - - ~process_token_t() - { - ::CloseHandle(token_handle_); - } - - } current_process_token(::GetCurrentProcess()); // GetCurrentProcess returns pseudohandle, no leak here! - - // Get the required size, this is expected to fail with ERROR_INSUFFICIENT_BUFFER and return the token size - DWORD tusize = 0; - if (::GetTokenInformation(current_process_token.token_handle_, TokenUser, NULL, 0, &tusize)) - { - SPDLOG_THROW(win32_error("GetTokenInformation should fail")); - } - - // get user token - std::vector buffer(static_cast(tusize)); - if (!::GetTokenInformation(current_process_token.token_handle_, TokenUser, (LPVOID)buffer.data(), tusize, &tusize)) - { - SPDLOG_THROW(win32_error("GetTokenInformation")); - } - - // create a wrapper of the SID data as stored in the user token - return sid_t::duplicate_sid(((TOKEN_USER *)buffer.data())->User.Sid); - } -}; - -struct eventlog -{ - static WORD get_event_type(details::log_msg const &msg) - { - switch (msg.level) - { - case level::trace: - case level::debug: - return EVENTLOG_SUCCESS; - - case level::info: - return EVENTLOG_INFORMATION_TYPE; - - case level::warn: - return EVENTLOG_WARNING_TYPE; - - case level::err: - case level::critical: - case level::off: - return EVENTLOG_ERROR_TYPE; - - default: - return EVENTLOG_INFORMATION_TYPE; - } - } - - static WORD get_event_category(details::log_msg const &msg) - { - return (WORD)msg.level; - } -}; - -} // namespace internal - -/* - * Windows Event Log sink - */ -template -class win_eventlog_sink : public base_sink -{ -private: - HANDLE hEventLog_{NULL}; - internal::sid_t current_user_sid_; - std::string source_; - DWORD event_id_; - - HANDLE event_log_handle() - { - if (!hEventLog_) - { - hEventLog_ = ::RegisterEventSourceA(nullptr, source_.c_str()); - if (!hEventLog_ || hEventLog_ == (HANDLE)ERROR_ACCESS_DENIED) - { - SPDLOG_THROW(internal::win32_error("RegisterEventSource")); - } - } - - return hEventLog_; - } - -protected: - void sink_it_(const details::log_msg &msg) override - { - using namespace internal; - - bool succeeded; - memory_buf_t formatted; - base_sink::formatter_->format(msg, formatted); - formatted.push_back('\0'); - -#ifdef SPDLOG_WCHAR_TO_UTF8_SUPPORT - wmemory_buf_t buf; - details::os::utf8_to_wstrbuf(string_view_t(formatted.data(), formatted.size()), buf); - - LPCWSTR lp_wstr = buf.data(); - succeeded = static_cast(::ReportEventW(event_log_handle(), eventlog::get_event_type(msg), eventlog::get_event_category(msg), - event_id_, current_user_sid_.as_sid(), 1, 0, &lp_wstr, nullptr)); -#else - LPCSTR lp_str = formatted.data(); - succeeded = static_cast(::ReportEventA(event_log_handle(), eventlog::get_event_type(msg), eventlog::get_event_category(msg), - event_id_, current_user_sid_.as_sid(), 1, 0, &lp_str, nullptr)); -#endif - - if (!succeeded) - { - SPDLOG_THROW(win32_error("ReportEvent")); - } - } - - void flush_() override {} - -public: - win_eventlog_sink(std::string const &source, DWORD event_id = 1000 /* according to mscoree.dll */) - : source_(source) - , event_id_(event_id) - { - try - { - current_user_sid_ = internal::sid_t::get_current_user_sid(); - } - catch (...) - { - // get_current_user_sid() is unlikely to fail and if it does, we can still proceed without - // current_user_sid but in the event log the record will have no user name - } - } - - ~win_eventlog_sink() - { - if (hEventLog_) - DeregisterEventSource(hEventLog_); - } -}; - -} // namespace win_eventlog - -using win_eventlog_sink_mt = win_eventlog::win_eventlog_sink; -using win_eventlog_sink_st = win_eventlog::win_eventlog_sink; - -} // namespace sinks -} // namespace spdlog diff --git a/tpl/spdlog/include/spdlog/sinks/wincolor_sink-inl.h b/tpl/spdlog/include/spdlog/sinks/wincolor_sink-inl.h deleted file mode 100644 index 8311929..0000000 --- a/tpl/spdlog/include/spdlog/sinks/wincolor_sink-inl.h +++ /dev/null @@ -1,175 +0,0 @@ -// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. -// Distributed under the MIT License (http://opensource.org/licenses/MIT) - -#pragma once - -#ifndef SPDLOG_HEADER_ONLY -# include -#endif - -#include -#include - -#include -#include - -namespace spdlog { -namespace sinks { -template -SPDLOG_INLINE wincolor_sink::wincolor_sink(void *out_handle, color_mode mode) - : out_handle_(out_handle) - , mutex_(ConsoleMutex::mutex()) - , formatter_(details::make_unique()) -{ - - set_color_mode_impl(mode); - // set level colors - colors_[level::trace] = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE; // white - colors_[level::debug] = FOREGROUND_GREEN | FOREGROUND_BLUE; // cyan - colors_[level::info] = FOREGROUND_GREEN; // green - colors_[level::warn] = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY; // intense yellow - colors_[level::err] = FOREGROUND_RED | FOREGROUND_INTENSITY; // intense red - colors_[level::critical] = - BACKGROUND_RED | FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY; // intense white on red background - colors_[level::off] = 0; -} - -template -SPDLOG_INLINE wincolor_sink::~wincolor_sink() -{ - this->flush(); -} - -// change the color for the given level -template -void SPDLOG_INLINE wincolor_sink::set_color(level::level_enum level, std::uint16_t color) -{ - std::lock_guard lock(mutex_); - colors_[static_cast(level)] = color; -} - -template -void SPDLOG_INLINE wincolor_sink::log(const details::log_msg &msg) -{ - if (out_handle_ == nullptr || out_handle_ == INVALID_HANDLE_VALUE) - { - return; - } - - std::lock_guard lock(mutex_); - msg.color_range_start = 0; - msg.color_range_end = 0; - memory_buf_t formatted; - formatter_->format(msg, formatted); - if (should_do_colors_ && msg.color_range_end > msg.color_range_start) - { - // before color range - print_range_(formatted, 0, msg.color_range_start); - // in color range - auto orig_attribs = static_cast(set_foreground_color_(colors_[static_cast(msg.level)])); - print_range_(formatted, msg.color_range_start, msg.color_range_end); - // reset to orig colors - ::SetConsoleTextAttribute(static_cast(out_handle_), orig_attribs); - print_range_(formatted, msg.color_range_end, formatted.size()); - } - else // print without colors if color range is invalid (or color is disabled) - { - write_to_file_(formatted); - } -} - -template -void SPDLOG_INLINE wincolor_sink::flush() -{ - // windows console always flushed? -} - -template -void SPDLOG_INLINE wincolor_sink::set_pattern(const std::string &pattern) -{ - std::lock_guard lock(mutex_); - formatter_ = std::unique_ptr(new pattern_formatter(pattern)); -} - -template -void SPDLOG_INLINE wincolor_sink::set_formatter(std::unique_ptr sink_formatter) -{ - std::lock_guard lock(mutex_); - formatter_ = std::move(sink_formatter); -} - -template -void SPDLOG_INLINE wincolor_sink::set_color_mode(color_mode mode) -{ - std::lock_guard lock(mutex_); - set_color_mode_impl(mode); -} - -template -void SPDLOG_INLINE wincolor_sink::set_color_mode_impl(color_mode mode) -{ - if (mode == color_mode::automatic) - { - // should do colors only if out_handle_ points to actual console. - DWORD console_mode; - bool in_console = ::GetConsoleMode(static_cast(out_handle_), &console_mode) != 0; - should_do_colors_ = in_console; - } - else - { - should_do_colors_ = mode == color_mode::always ? true : false; - } -} - -// set foreground color and return the orig console attributes (for resetting later) -template -std::uint16_t SPDLOG_INLINE wincolor_sink::set_foreground_color_(std::uint16_t attribs) -{ - CONSOLE_SCREEN_BUFFER_INFO orig_buffer_info; - if (!::GetConsoleScreenBufferInfo(static_cast(out_handle_), &orig_buffer_info)) - { - // just return white if failed getting console info - return FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE; - } - - // change only the foreground bits (lowest 4 bits) - auto new_attribs = static_cast(attribs) | (orig_buffer_info.wAttributes & 0xfff0); - auto ignored = ::SetConsoleTextAttribute(static_cast(out_handle_), static_cast(new_attribs)); - (void)(ignored); - return static_cast(orig_buffer_info.wAttributes); // return orig attribs -} - -// print a range of formatted message to console -template -void SPDLOG_INLINE wincolor_sink::print_range_(const memory_buf_t &formatted, size_t start, size_t end) -{ - if (end > start) - { - auto size = static_cast(end - start); - auto ignored = ::WriteConsoleA(static_cast(out_handle_), formatted.data() + start, size, nullptr, nullptr); - (void)(ignored); - } -} - -template -void SPDLOG_INLINE wincolor_sink::write_to_file_(const memory_buf_t &formatted) -{ - auto size = static_cast(formatted.size()); - DWORD bytes_written = 0; - auto ignored = ::WriteFile(static_cast(out_handle_), formatted.data(), size, &bytes_written, nullptr); - (void)(ignored); -} - -// wincolor_stdout_sink -template -SPDLOG_INLINE wincolor_stdout_sink::wincolor_stdout_sink(color_mode mode) - : wincolor_sink(::GetStdHandle(STD_OUTPUT_HANDLE), mode) -{} - -// wincolor_stderr_sink -template -SPDLOG_INLINE wincolor_stderr_sink::wincolor_stderr_sink(color_mode mode) - : wincolor_sink(::GetStdHandle(STD_ERROR_HANDLE), mode) -{} -} // namespace sinks -} // namespace spdlog diff --git a/tpl/spdlog/include/spdlog/sinks/wincolor_sink.h b/tpl/spdlog/include/spdlog/sinks/wincolor_sink.h deleted file mode 100644 index 9b030fc..0000000 --- a/tpl/spdlog/include/spdlog/sinks/wincolor_sink.h +++ /dev/null @@ -1,85 +0,0 @@ -// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. -// Distributed under the MIT License (http://opensource.org/licenses/MIT) - -#pragma once - -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -namespace spdlog { -namespace sinks { -/* - * Windows color console sink. Uses WriteConsoleA to write to the console with - * colors - */ -template -class wincolor_sink : public sink -{ -public: - wincolor_sink(void *out_handle, color_mode mode); - ~wincolor_sink() override; - - wincolor_sink(const wincolor_sink &other) = delete; - wincolor_sink &operator=(const wincolor_sink &other) = delete; - - // change the color for the given level - void set_color(level::level_enum level, std::uint16_t color); - void log(const details::log_msg &msg) final override; - void flush() final override; - void set_pattern(const std::string &pattern) override final; - void set_formatter(std::unique_ptr sink_formatter) override final; - void set_color_mode(color_mode mode); - -protected: - using mutex_t = typename ConsoleMutex::mutex_t; - void *out_handle_; - mutex_t &mutex_; - bool should_do_colors_; - std::unique_ptr formatter_; - std::array colors_; - - // set foreground color and return the orig console attributes (for resetting later) - std::uint16_t set_foreground_color_(std::uint16_t attribs); - - // print a range of formatted message to console - void print_range_(const memory_buf_t &formatted, size_t start, size_t end); - - // in case we are redirected to file (not in console mode) - void write_to_file_(const memory_buf_t &formatted); - - void set_color_mode_impl(color_mode mode); -}; - -template -class wincolor_stdout_sink : public wincolor_sink -{ -public: - explicit wincolor_stdout_sink(color_mode mode = color_mode::automatic); -}; - -template -class wincolor_stderr_sink : public wincolor_sink -{ -public: - explicit wincolor_stderr_sink(color_mode mode = color_mode::automatic); -}; - -using wincolor_stdout_sink_mt = wincolor_stdout_sink; -using wincolor_stdout_sink_st = wincolor_stdout_sink; - -using wincolor_stderr_sink_mt = wincolor_stderr_sink; -using wincolor_stderr_sink_st = wincolor_stderr_sink; -} // namespace sinks -} // namespace spdlog - -#ifdef SPDLOG_HEADER_ONLY -# include "wincolor_sink-inl.h" -#endif diff --git a/tpl/spdlog/include/spdlog/spdlog-inl.h b/tpl/spdlog/include/spdlog/spdlog-inl.h deleted file mode 100644 index 22ea22b..0000000 --- a/tpl/spdlog/include/spdlog/spdlog-inl.h +++ /dev/null @@ -1,125 +0,0 @@ -// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. -// Distributed under the MIT License (http://opensource.org/licenses/MIT) - -#pragma once - -#ifndef SPDLOG_HEADER_ONLY -# include -#endif - -#include -#include - -namespace spdlog { - -SPDLOG_INLINE void initialize_logger(std::shared_ptr logger) -{ - details::registry::instance().initialize_logger(std::move(logger)); -} - -SPDLOG_INLINE std::shared_ptr get(const std::string &name) -{ - return details::registry::instance().get(name); -} - -SPDLOG_INLINE void set_formatter(std::unique_ptr formatter) -{ - details::registry::instance().set_formatter(std::move(formatter)); -} - -SPDLOG_INLINE void set_pattern(std::string pattern, pattern_time_type time_type) -{ - set_formatter(std::unique_ptr(new pattern_formatter(std::move(pattern), time_type))); -} - -SPDLOG_INLINE void enable_backtrace(size_t n_messages) -{ - details::registry::instance().enable_backtrace(n_messages); -} - -SPDLOG_INLINE void disable_backtrace() -{ - details::registry::instance().disable_backtrace(); -} - -SPDLOG_INLINE void dump_backtrace() -{ - default_logger_raw()->dump_backtrace(); -} - -SPDLOG_INLINE level::level_enum get_level() -{ - return default_logger_raw()->level(); -} - -SPDLOG_INLINE bool should_log(level::level_enum log_level) -{ - return default_logger_raw()->should_log(log_level); -} - -SPDLOG_INLINE void set_level(level::level_enum log_level) -{ - details::registry::instance().set_level(log_level); -} - -SPDLOG_INLINE void flush_on(level::level_enum log_level) -{ - details::registry::instance().flush_on(log_level); -} - -SPDLOG_INLINE void set_error_handler(void (*handler)(const std::string &msg)) -{ - details::registry::instance().set_error_handler(handler); -} - -SPDLOG_INLINE void register_logger(std::shared_ptr logger) -{ - details::registry::instance().register_logger(std::move(logger)); -} - -SPDLOG_INLINE void apply_all(const std::function)> &fun) -{ - details::registry::instance().apply_all(fun); -} - -SPDLOG_INLINE void drop(const std::string &name) -{ - details::registry::instance().drop(name); -} - -SPDLOG_INLINE void drop_all() -{ - details::registry::instance().drop_all(); -} - -SPDLOG_INLINE void shutdown() -{ - details::registry::instance().shutdown(); -} - -SPDLOG_INLINE void set_automatic_registration(bool automatic_registration) -{ - details::registry::instance().set_automatic_registration(automatic_registration); -} - -SPDLOG_INLINE std::shared_ptr default_logger() -{ - return details::registry::instance().default_logger(); -} - -SPDLOG_INLINE spdlog::logger *default_logger_raw() -{ - return details::registry::instance().get_default_raw(); -} - -SPDLOG_INLINE void set_default_logger(std::shared_ptr default_logger) -{ - details::registry::instance().set_default_logger(std::move(default_logger)); -} - -SPDLOG_INLINE void apply_logger_env_levels(std::shared_ptr logger) -{ - details::registry::instance().apply_logger_env_levels(std::move(logger)); -} - -} // namespace spdlog diff --git a/tpl/spdlog/include/spdlog/spdlog.h b/tpl/spdlog/include/spdlog/spdlog.h deleted file mode 100644 index fbfe5fb..0000000 --- a/tpl/spdlog/include/spdlog/spdlog.h +++ /dev/null @@ -1,363 +0,0 @@ -// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. -// Distributed under the MIT License (http://opensource.org/licenses/MIT) - -// spdlog main header file. -// see example.cpp for usage example - -#ifndef SPDLOG_H -#define SPDLOG_H - -#pragma once - -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -namespace spdlog { - -using default_factory = synchronous_factory; - -// Create and register a logger with a templated sink type -// The logger's level, formatter and flush level will be set according the -// global settings. -// -// Example: -// spdlog::create("logger_name", "dailylog_filename", 11, 59); -template -inline std::shared_ptr create(std::string logger_name, SinkArgs &&...sink_args) -{ - return default_factory::create(std::move(logger_name), std::forward(sink_args)...); -} - -// Initialize and register a logger, -// formatter and flush level will be set according the global settings. -// -// Useful for initializing manually created loggers with the global settings. -// -// Example: -// auto mylogger = std::make_shared("mylogger", ...); -// spdlog::initialize_logger(mylogger); -SPDLOG_API void initialize_logger(std::shared_ptr logger); - -// Return an existing logger or nullptr if a logger with such name doesn't -// exist. -// example: spdlog::get("my_logger")->info("hello {}", "world"); -SPDLOG_API std::shared_ptr get(const std::string &name); - -// Set global formatter. Each sink in each logger will get a clone of this object -SPDLOG_API void set_formatter(std::unique_ptr formatter); - -// Set global format string. -// example: spdlog::set_pattern("%Y-%m-%d %H:%M:%S.%e %l : %v"); -SPDLOG_API void set_pattern(std::string pattern, pattern_time_type time_type = pattern_time_type::local); - -// enable global backtrace support -SPDLOG_API void enable_backtrace(size_t n_messages); - -// disable global backtrace support -SPDLOG_API void disable_backtrace(); - -// call dump backtrace on default logger -SPDLOG_API void dump_backtrace(); - -// Get global logging level -SPDLOG_API level::level_enum get_level(); - -// Set global logging level -SPDLOG_API void set_level(level::level_enum log_level); - -// Determine whether the default logger should log messages with a certain level -SPDLOG_API bool should_log(level::level_enum lvl); - -// Set global flush level -SPDLOG_API void flush_on(level::level_enum log_level); - -// Start/Restart a periodic flusher thread -// Warning: Use only if all your loggers are thread safe! -template -inline void flush_every(std::chrono::duration interval) -{ - details::registry::instance().flush_every(interval); -} - -// Set global error handler -SPDLOG_API void set_error_handler(void (*handler)(const std::string &msg)); - -// Register the given logger with the given name -SPDLOG_API void register_logger(std::shared_ptr logger); - -// Apply a user defined function on all registered loggers -// Example: -// spdlog::apply_all([&](std::shared_ptr l) {l->flush();}); -SPDLOG_API void apply_all(const std::function)> &fun); - -// Drop the reference to the given logger -SPDLOG_API void drop(const std::string &name); - -// Drop all references from the registry -SPDLOG_API void drop_all(); - -// stop any running threads started by spdlog and clean registry loggers -SPDLOG_API void shutdown(); - -// Automatic registration of loggers when using spdlog::create() or spdlog::create_async -SPDLOG_API void set_automatic_registration(bool automatic_registration); - -// API for using default logger (stdout_color_mt), -// e.g: spdlog::info("Message {}", 1); -// -// The default logger object can be accessed using the spdlog::default_logger(): -// For example, to add another sink to it: -// spdlog::default_logger()->sinks().push_back(some_sink); -// -// The default logger can replaced using spdlog::set_default_logger(new_logger). -// For example, to replace it with a file logger. -// -// IMPORTANT: -// The default API is thread safe (for _mt loggers), but: -// set_default_logger() *should not* be used concurrently with the default API. -// e.g do not call set_default_logger() from one thread while calling spdlog::info() from another. - -SPDLOG_API std::shared_ptr default_logger(); - -SPDLOG_API spdlog::logger *default_logger_raw(); - -SPDLOG_API void set_default_logger(std::shared_ptr default_logger); - -// Initialize logger level based on environment configs. -// -// Useful for applying SPDLOG_LEVEL to manually created loggers. -// -// Example: -// auto mylogger = std::make_shared("mylogger", ...); -// spdlog::apply_logger_env_levels(mylogger); -SPDLOG_API void apply_logger_env_levels(std::shared_ptr logger); - -template -inline void log(source_loc source, level::level_enum lvl, format_string_t fmt, Args &&...args) -{ - default_logger_raw()->log(source, lvl, fmt, std::forward(args)...); -} - -template -inline void log(level::level_enum lvl, format_string_t fmt, Args &&...args) -{ - default_logger_raw()->log(source_loc{}, lvl, fmt, std::forward(args)...); -} - -template -inline void trace(format_string_t fmt, Args &&...args) -{ - default_logger_raw()->trace(fmt, std::forward(args)...); -} - -template -inline void debug(format_string_t fmt, Args &&...args) -{ - default_logger_raw()->debug(fmt, std::forward(args)...); -} - -template -inline void info(format_string_t fmt, Args &&...args) -{ - default_logger_raw()->info(fmt, std::forward(args)...); -} - -template -inline void warn(format_string_t fmt, Args &&...args) -{ - default_logger_raw()->warn(fmt, std::forward(args)...); -} - -template -inline void error(format_string_t fmt, Args &&...args) -{ - default_logger_raw()->error(fmt, std::forward(args)...); -} - -template -inline void critical(format_string_t fmt, Args &&...args) -{ - default_logger_raw()->critical(fmt, std::forward(args)...); -} - -template -inline void log(source_loc source, level::level_enum lvl, const T &msg) -{ - default_logger_raw()->log(source, lvl, msg); -} - -template -inline void log(level::level_enum lvl, const T &msg) -{ - default_logger_raw()->log(lvl, msg); -} - -#ifdef SPDLOG_WCHAR_TO_UTF8_SUPPORT -template -inline void log(source_loc source, level::level_enum lvl, wformat_string_t fmt, Args &&...args) -{ - default_logger_raw()->log(source, lvl, fmt, std::forward(args)...); -} - -template -inline void log(level::level_enum lvl, wformat_string_t fmt, Args &&...args) -{ - default_logger_raw()->log(source_loc{}, lvl, fmt, std::forward(args)...); -} - -template -inline void trace(wformat_string_t fmt, Args &&...args) -{ - default_logger_raw()->trace(fmt, std::forward(args)...); -} - -template -inline void debug(wformat_string_t fmt, Args &&...args) -{ - default_logger_raw()->debug(fmt, std::forward(args)...); -} - -template -inline void info(wformat_string_t fmt, Args &&...args) -{ - default_logger_raw()->info(fmt, std::forward(args)...); -} - -template -inline void warn(wformat_string_t fmt, Args &&...args) -{ - default_logger_raw()->warn(fmt, std::forward(args)...); -} - -template -inline void error(wformat_string_t fmt, Args &&...args) -{ - default_logger_raw()->error(fmt, std::forward(args)...); -} - -template -inline void critical(wformat_string_t fmt, Args &&...args) -{ - default_logger_raw()->critical(fmt, std::forward(args)...); -} -#endif - -template -inline void trace(const T &msg) -{ - default_logger_raw()->trace(msg); -} - -template -inline void debug(const T &msg) -{ - default_logger_raw()->debug(msg); -} - -template -inline void info(const T &msg) -{ - default_logger_raw()->info(msg); -} - -template -inline void warn(const T &msg) -{ - default_logger_raw()->warn(msg); -} - -template -inline void error(const T &msg) -{ - default_logger_raw()->error(msg); -} - -template -inline void critical(const T &msg) -{ - default_logger_raw()->critical(msg); -} - -} // namespace spdlog - -// -// enable/disable log calls at compile time according to global level. -// -// define SPDLOG_ACTIVE_LEVEL to one of those (before including spdlog.h): -// SPDLOG_LEVEL_TRACE, -// SPDLOG_LEVEL_DEBUG, -// SPDLOG_LEVEL_INFO, -// SPDLOG_LEVEL_WARN, -// SPDLOG_LEVEL_ERROR, -// SPDLOG_LEVEL_CRITICAL, -// SPDLOG_LEVEL_OFF -// - -#ifndef SPDLOG_NO_SOURCE_LOC -# define SPDLOG_LOGGER_CALL(logger, level, ...) \ - (logger)->log(spdlog::source_loc{__FILE__, __LINE__, SPDLOG_FUNCTION}, level, __VA_ARGS__) -#else -# define SPDLOG_LOGGER_CALL(logger, level, ...) (logger)->log(spdlog::source_loc{}, level, __VA_ARGS__) -#endif - -#if SPDLOG_ACTIVE_LEVEL <= SPDLOG_LEVEL_TRACE -# define SPDLOG_LOGGER_TRACE(logger, ...) SPDLOG_LOGGER_CALL(logger, spdlog::level::trace, __VA_ARGS__) -# define SPDLOG_TRACE(...) SPDLOG_LOGGER_TRACE(spdlog::default_logger_raw(), __VA_ARGS__) -#else -# define SPDLOG_LOGGER_TRACE(logger, ...) (void)0 -# define SPDLOG_TRACE(...) (void)0 -#endif - -#if SPDLOG_ACTIVE_LEVEL <= SPDLOG_LEVEL_DEBUG -# define SPDLOG_LOGGER_DEBUG(logger, ...) SPDLOG_LOGGER_CALL(logger, spdlog::level::debug, __VA_ARGS__) -# define SPDLOG_DEBUG(...) SPDLOG_LOGGER_DEBUG(spdlog::default_logger_raw(), __VA_ARGS__) -#else -# define SPDLOG_LOGGER_DEBUG(logger, ...) (void)0 -# define SPDLOG_DEBUG(...) (void)0 -#endif - -#if SPDLOG_ACTIVE_LEVEL <= SPDLOG_LEVEL_INFO -# define SPDLOG_LOGGER_INFO(logger, ...) SPDLOG_LOGGER_CALL(logger, spdlog::level::info, __VA_ARGS__) -# define SPDLOG_INFO(...) SPDLOG_LOGGER_INFO(spdlog::default_logger_raw(), __VA_ARGS__) -#else -# define SPDLOG_LOGGER_INFO(logger, ...) (void)0 -# define SPDLOG_INFO(...) (void)0 -#endif - -#if SPDLOG_ACTIVE_LEVEL <= SPDLOG_LEVEL_WARN -# define SPDLOG_LOGGER_WARN(logger, ...) SPDLOG_LOGGER_CALL(logger, spdlog::level::warn, __VA_ARGS__) -# define SPDLOG_WARN(...) SPDLOG_LOGGER_WARN(spdlog::default_logger_raw(), __VA_ARGS__) -#else -# define SPDLOG_LOGGER_WARN(logger, ...) (void)0 -# define SPDLOG_WARN(...) (void)0 -#endif - -#if SPDLOG_ACTIVE_LEVEL <= SPDLOG_LEVEL_ERROR -# define SPDLOG_LOGGER_ERROR(logger, ...) SPDLOG_LOGGER_CALL(logger, spdlog::level::err, __VA_ARGS__) -# define SPDLOG_ERROR(...) SPDLOG_LOGGER_ERROR(spdlog::default_logger_raw(), __VA_ARGS__) -#else -# define SPDLOG_LOGGER_ERROR(logger, ...) (void)0 -# define SPDLOG_ERROR(...) (void)0 -#endif - -#if SPDLOG_ACTIVE_LEVEL <= SPDLOG_LEVEL_CRITICAL -# define SPDLOG_LOGGER_CRITICAL(logger, ...) SPDLOG_LOGGER_CALL(logger, spdlog::level::critical, __VA_ARGS__) -# define SPDLOG_CRITICAL(...) SPDLOG_LOGGER_CRITICAL(spdlog::default_logger_raw(), __VA_ARGS__) -#else -# define SPDLOG_LOGGER_CRITICAL(logger, ...) (void)0 -# define SPDLOG_CRITICAL(...) (void)0 -#endif - -#ifdef SPDLOG_HEADER_ONLY -# include "spdlog-inl.h" -#endif - -#endif // SPDLOG_H diff --git a/tpl/spdlog/include/spdlog/stopwatch.h b/tpl/spdlog/include/spdlog/stopwatch.h deleted file mode 100644 index bea7b8a..0000000 --- a/tpl/spdlog/include/spdlog/stopwatch.h +++ /dev/null @@ -1,69 +0,0 @@ -// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. -// Distributed under the MIT License (http://opensource.org/licenses/MIT) - -#pragma once - -#include -#include - -// Stopwatch support for spdlog (using std::chrono::steady_clock). -// Displays elapsed seconds since construction as double. -// -// Usage: -// -// spdlog::stopwatch sw; -// ... -// spdlog::debug("Elapsed: {} seconds", sw); => "Elapsed 0.005116733 seconds" -// spdlog::info("Elapsed: {:.6} seconds", sw); => "Elapsed 0.005163 seconds" -// -// -// If other units are needed (e.g. millis instead of double), include "fmt/chrono.h" and use "duration_cast<..>(sw.elapsed())": -// -// #include -//.. -// using std::chrono::duration_cast; -// using std::chrono::milliseconds; -// spdlog::info("Elapsed {}", duration_cast(sw.elapsed())); => "Elapsed 5ms" - -namespace spdlog { -class stopwatch -{ - using clock = std::chrono::steady_clock; - std::chrono::time_point start_tp_; - -public: - stopwatch() - : start_tp_{clock::now()} - {} - - std::chrono::duration elapsed() const - { - return std::chrono::duration(clock::now() - start_tp_); - } - - void reset() - { - start_tp_ = clock::now(); - } -}; -} // namespace spdlog - -// Support for fmt formatting (e.g. "{:012.9}" or just "{}") -namespace -#ifdef SPDLOG_USE_STD_FORMAT - std -#else - fmt -#endif -{ - -template<> -struct formatter : formatter -{ - template - auto format(const spdlog::stopwatch &sw, FormatContext &ctx) const -> decltype(ctx.out()) - { - return formatter::format(sw.elapsed().count(), ctx); - } -}; -} // namespace std diff --git a/tpl/spdlog/include/spdlog/tweakme.h b/tpl/spdlog/include/spdlog/tweakme.h deleted file mode 100644 index 5bcb5ff..0000000 --- a/tpl/spdlog/include/spdlog/tweakme.h +++ /dev/null @@ -1,140 +0,0 @@ -// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. -// Distributed under the MIT License (http://opensource.org/licenses/MIT) - -#pragma once - -/////////////////////////////////////////////////////////////////////////////// -// -// Edit this file to squeeze more performance, and to customize supported -// features -// -/////////////////////////////////////////////////////////////////////////////// - -/////////////////////////////////////////////////////////////////////////////// -// Under Linux, the much faster CLOCK_REALTIME_COARSE clock can be used. -// This clock is less accurate - can be off by dozens of millis - depending on -// the kernel HZ. -// Uncomment to use it instead of the regular clock. -// -// #define SPDLOG_CLOCK_COARSE -/////////////////////////////////////////////////////////////////////////////// - -/////////////////////////////////////////////////////////////////////////////// -// Uncomment if source location logging is not needed. -// This will prevent spdlog from using __FILE__, __LINE__ and SPDLOG_FUNCTION -// -// #define SPDLOG_NO_SOURCE_LOC -/////////////////////////////////////////////////////////////////////////////// - -/////////////////////////////////////////////////////////////////////////////// -// Uncomment if thread id logging is not needed (i.e. no %t in the log pattern). -// This will prevent spdlog from querying the thread id on each log call. -// -// WARNING: If the log pattern contains thread id (i.e, %t) while this flag is -// on, zero will be logged as thread id. -// -// #define SPDLOG_NO_THREAD_ID -/////////////////////////////////////////////////////////////////////////////// - -/////////////////////////////////////////////////////////////////////////////// -// Uncomment to prevent spdlog from using thread local storage. -// -// WARNING: if your program forks, UNCOMMENT this flag to prevent undefined -// thread ids in the children logs. -// -// #define SPDLOG_NO_TLS -/////////////////////////////////////////////////////////////////////////////// - -/////////////////////////////////////////////////////////////////////////////// -// Uncomment to avoid spdlog's usage of atomic log levels -// Use only if your code never modifies a logger's log levels concurrently by -// different threads. -// -// #define SPDLOG_NO_ATOMIC_LEVELS -/////////////////////////////////////////////////////////////////////////////// - -/////////////////////////////////////////////////////////////////////////////// -// Uncomment to enable usage of wchar_t for file names on Windows. -// -// #define SPDLOG_WCHAR_FILENAMES -/////////////////////////////////////////////////////////////////////////////// - -/////////////////////////////////////////////////////////////////////////////// -// Uncomment to override default eol ("\n" or "\r\n" under Linux/Windows) -// -// #define SPDLOG_EOL ";-)\n" -/////////////////////////////////////////////////////////////////////////////// - -/////////////////////////////////////////////////////////////////////////////// -// Uncomment to override default folder separators ("/" or "\\/" under -// Linux/Windows). Each character in the string is treated as a different -// separator. -// -// #define SPDLOG_FOLDER_SEPS "\\" -/////////////////////////////////////////////////////////////////////////////// - -/////////////////////////////////////////////////////////////////////////////// -// Uncomment to use your own copy of the fmt library instead of spdlog's copy. -// In this case spdlog will try to include so set your -I flag -// accordingly. -// -// #define SPDLOG_FMT_EXTERNAL -/////////////////////////////////////////////////////////////////////////////// - -/////////////////////////////////////////////////////////////////////////////// -// Uncomment to use C++20 std::format instead of fmt. -// -// #define SPDLOG_USE_STD_FORMAT -/////////////////////////////////////////////////////////////////////////////// - -/////////////////////////////////////////////////////////////////////////////// -// Uncomment to enable wchar_t support (convert to utf8) -// -// #define SPDLOG_WCHAR_TO_UTF8_SUPPORT -/////////////////////////////////////////////////////////////////////////////// - -/////////////////////////////////////////////////////////////////////////////// -// Uncomment to prevent child processes from inheriting log file descriptors -// -// #define SPDLOG_PREVENT_CHILD_FD -/////////////////////////////////////////////////////////////////////////////// - -/////////////////////////////////////////////////////////////////////////////// -// Uncomment to customize level names (e.g. "MY TRACE") -// -// #define SPDLOG_LEVEL_NAMES { "MY TRACE", "MY DEBUG", "MY INFO", "MY WARNING", "MY ERROR", "MY CRITICAL", "OFF" } -/////////////////////////////////////////////////////////////////////////////// - -/////////////////////////////////////////////////////////////////////////////// -// Uncomment to customize short level names (e.g. "MT") -// These can be longer than one character. -// -// #define SPDLOG_SHORT_LEVEL_NAMES { "T", "D", "I", "W", "E", "C", "O" } -/////////////////////////////////////////////////////////////////////////////// - -/////////////////////////////////////////////////////////////////////////////// -// Uncomment to disable default logger creation. -// This might save some (very) small initialization time if no default logger is needed. -// -// #define SPDLOG_DISABLE_DEFAULT_LOGGER -/////////////////////////////////////////////////////////////////////////////// - -/////////////////////////////////////////////////////////////////////////////// -// Uncomment and set to compile time level with zero cost (default is INFO). -// Macros like SPDLOG_DEBUG(..), SPDLOG_INFO(..) will expand to empty statements if not enabled -// -// #define SPDLOG_ACTIVE_LEVEL SPDLOG_LEVEL_INFO -/////////////////////////////////////////////////////////////////////////////// - -/////////////////////////////////////////////////////////////////////////////// -// Uncomment (and change if desired) macro to use for function names. -// This is compiler dependent. -// __PRETTY_FUNCTION__ might be nicer in clang/gcc, and __FUNCTION__ in msvc. -// Defaults to __FUNCTION__ (should work on all compilers) if not defined. -// -// #ifdef __PRETTY_FUNCTION__ -// # define SPDLOG_FUNCTION __PRETTY_FUNCTION__ -// #else -// # define SPDLOG_FUNCTION __FUNCTION__ -// #endif -/////////////////////////////////////////////////////////////////////////////// diff --git a/tpl/spdlog/include/spdlog/version.h b/tpl/spdlog/include/spdlog/version.h deleted file mode 100644 index 633cddc..0000000 --- a/tpl/spdlog/include/spdlog/version.h +++ /dev/null @@ -1,10 +0,0 @@ -// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. -// Distributed under the MIT License (http://opensource.org/licenses/MIT) - -#pragma once - -#define SPDLOG_VER_MAJOR 1 -#define SPDLOG_VER_MINOR 12 -#define SPDLOG_VER_PATCH 0 - -#define SPDLOG_VERSION (SPDLOG_VER_MAJOR * 10000 + SPDLOG_VER_MINOR * 100 + SPDLOG_VER_PATCH) From 16644bc82ac12fe10ce5874d6561a0497c09e282 Mon Sep 17 00:00:00 2001 From: Nicolas Morales Date: Thu, 6 Jun 2024 14:44:48 -0700 Subject: [PATCH 11/11] #19: update bvhConfig.cmake.in to have new spdlog dependency --- cmake/bvhConfig.cmake.in | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/cmake/bvhConfig.cmake.in b/cmake/bvhConfig.cmake.in index 466b217..922404f 100644 --- a/cmake/bvhConfig.cmake.in +++ b/cmake/bvhConfig.cmake.in @@ -7,15 +7,14 @@ if (@VTK_FOUND@) find_dependency(VTK REQUIRED HINTS @VTK_DIR@) endif() -# VT optional dependency -if (@vt_FOUND@) - find_dependency(vt REQUIRED HINTS @vt_DIR@) -endif() +# VT +find_dependency(vt REQUIRED HINTS @vt_DIR@) -# Kokkos optional dependency -if (@Kokkos_FOUND@) - find_dependency(Kokkos REQUIRED NO_CMAKE_PACKAGE_REGISTRY HINTS @Kokkos_DIR@) -endif() +# Kokkos +find_dependency(Kokkos REQUIRED NO_CMAKE_PACKAGE_REGISTRY HINTS @Kokkos_DIR@) + +# spdlog +find_dependency(spdlog REQUIRED) if (@perf_FOUND@) find_dependency(perf REQUIRED HINTS @perf_DIR@)