diff --git a/CMakeLists.txt b/CMakeLists.txt index 7efe5049..75b063ca 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -63,31 +63,39 @@ option(SPDLOG_SANITIZE_ADDRESS "Enable address sanitizer in tests" OFF) # install options option(SPDLOG_INSTALL "Generate the install target" ${SPDLOG_MASTER_PROJECT}) option(SPDLOG_FMT_EXTERNAL "Use external fmt library instead of bundled" OFF) +option(SPDLOG_NO_EXCEPTIONS "Compile with -fno-exceptions. Call abort() on any spdlog exceptions" OFF) + +# misc tweakme options if(WIN32) - option(SPDLOG_WCHAR_SUPPORT "Support wchar api" OFF) - option(SPDLOG_WCHAR_FILENAMES "Support wchar filenames" OFF) + option(SPDLOG_WCHAR_SUPPORT "Support wchar api" OFF) + option(SPDLOG_WCHAR_FILENAMES "Support wchar filenames" OFF) +endif() +if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux") + option(SPDLOG_CLOCK_COARSE "Use the much faster (but much less accurate) CLOCK_REALTIME_COARSE instead of the regular clock," OFF) endif() -option(SPDLOG_NO_EXCEPTIONS "Compile with -fno-exceptions. Call abort() on any spdlog exceptions" OFF) - +option(SPDLOG_PREVENT_CHILD_FD "Prevent from child processes to inherit log file descriptors" OFF) +option(SPDLOG_NO_THREAD_ID "prevent spdlog from querying the thread id on each log call if thread id is not needed" OFF) +option(SPDLOG_NO_TLS "prevent spdlog from using thread local storage" OFF) +option(SPDLOG_NO_ATOMIC_LEVELS "prevent spdlog from using of std::atomic log levels (use only if your code never modifies log levels concurrently" OFF) find_package(Threads REQUIRED) - message(STATUS "Build type: " ${CMAKE_BUILD_TYPE}) - #--------------------------------------------------------------------------------------- # Static/Shared library (shared not supported in windows yet) #--------------------------------------------------------------------------------------- set(SPDLOG_SRCS src/spdlog.cpp src/stdout_sinks.cpp - src/fmt.cpp src/color_sinks.cpp src/file_sinks.cpp src/async.cpp) -set(SPDLOG_CFLAGS "${PROJECT_NAME}") + +if(NOT SPDLOG_FMT_EXTERNAL) + list(APPEND SPDLOG_SRCS src/fmt.cpp) +endif() if (SPDLOG_BUILD_SHARED) if(WIN32) @@ -123,22 +131,24 @@ target_link_libraries(spdlog_header_only INTERFACE Threads::Threads) #--------------------------------------------------------------------------------------- -# Use fmt package if using exertnal fmt +# Use fmt package if using external fmt #--------------------------------------------------------------------------------------- if(SPDLOG_FMT_EXTERNAL) if (NOT TARGET fmt::fmt) find_package(fmt REQUIRED) endif () - - set(SPDLOG_CFLAGS "${SPDLOG_CFLAGS} -DSPDLOG_FMT_EXTERNAL") - target_compile_definitions(spdlog PUBLIC SPDLOG_FMT_EXTERNAL) target_link_libraries(spdlog PUBLIC fmt::fmt) target_compile_definitions(spdlog_header_only INTERFACE SPDLOG_FMT_EXTERNAL) target_link_libraries(spdlog_header_only INTERFACE fmt::fmt) + + set(PKG_CONFIG_REQUIRES fmt) # add dependency to pkg-config endif() +#--------------------------------------------------------------------------------------- +# Misc definitions according to tweak options +#--------------------------------------------------------------------------------------- if(SPDLOG_WCHAR_SUPPORT) target_compile_definitions(spdlog PUBLIC SPDLOG_WCHAR_TO_UTF8_SUPPORT) target_compile_definitions(spdlog_header_only INTERFACE SPDLOG_WCHAR_TO_UTF8_SUPPORT) @@ -159,6 +169,31 @@ if(SPDLOG_WCHAR_SUPPORT) endif() endif() +if(SPDLOG_CLOCK_COARSE) + target_compile_definitions(spdlog PRIVATE SPDLOG_CLOCK_COARSE) + target_compile_definitions(spdlog_header_only INTERFACE SPDLOG_CLOCK_COARSE) +endif() + +if(SPDLOG_PREVENT_CHILD_FD) + target_compile_definitions(spdlog PRIVATE SPDLOG_PREVENT_CHILD_FD) + target_compile_definitions(spdlog_header_only INTERFACE SPDLOG_PREVENT_CHILD_FD) +endif() + +if(SPDLOG_NO_THREAD_ID) + target_compile_definitions(spdlog PRIVATE SPDLOG_NO_THREAD_ID) + target_compile_definitions(spdlog_header_only INTERFACE SPDLOG_NO_THREAD_ID) +endif() + +if(SPDLOG_NO_TLS) + target_compile_definitions(spdlog PRIVATE SPDLOG_NO_TLS) + target_compile_definitions(spdlog_header_only INTERFACE SPDLOG_NO_TLS) +endif() + +if(SPDLOG_NO_ATOMIC_LEVELS) + target_compile_definitions(spdlog PUBLIC SPDLOG_NO_ATOMIC_LEVELS) + target_compile_definitions(spdlog_header_only INTERFACE SPDLOG_NO_ATOMIC_LEVELS) +endif() + #--------------------------------------------------------------------------------------- # Build binaries @@ -188,7 +223,7 @@ if (SPDLOG_INSTALL) set(project_config_out "${CMAKE_CURRENT_BINARY_DIR}/spdlogConfig.cmake") set(config_targets_file "spdlogConfigTargets.cmake") set(version_config_file "${CMAKE_CURRENT_BINARY_DIR}/spdlogConfigVersion.cmake") - set(export_dest_dir "${CMAKE_INSTALL_LIBDIR}/spdlog/cmake") + set(export_dest_dir "${CMAKE_INSTALL_LIBDIR}/cmake/spdlog") set(pkgconfig_install_dir "${CMAKE_INSTALL_LIBDIR}/pkgconfig") set(pkg_config "${CMAKE_BINARY_DIR}/${PROJECT_NAME}.pc") @@ -204,11 +239,17 @@ if (SPDLOG_INSTALL) endif() #--------------------------------------------------------------------------------------- - # Package and version files + # Install pkg-config file #--------------------------------------------------------------------------------------- + get_target_property(PKG_CONFIG_DEFINES spdlog INTERFACE_COMPILE_DEFINITIONS) + string(REPLACE ";" " -D" PKG_CONFIG_DEFINES "${PKG_CONFIG_DEFINES}") + string(CONCAT PKG_CONFIG_DEFINES "-D" "${PKG_CONFIG_DEFINES}") configure_file("cmake/${PROJECT_NAME}.pc.in" "${pkg_config}" @ONLY) install(FILES "${pkg_config}" DESTINATION "${pkgconfig_install_dir}") + #--------------------------------------------------------------------------------------- + # Install CMake config files + #--------------------------------------------------------------------------------------- install(EXPORT spdlog DESTINATION ${export_dest_dir} NAMESPACE spdlog:: @@ -216,6 +257,7 @@ if (SPDLOG_INSTALL) include(CMakePackageConfigHelpers) configure_file("${project_config_in}" "${project_config_out}" @ONLY) + write_basic_package_version_file("${version_config_file}" COMPATIBILITY SameMajorVersion) install(FILES "${project_config_out}" @@ -227,3 +269,4 @@ if (SPDLOG_INSTALL) include(cmake/spdlogCPack.cmake) endif () + diff --git a/README.md b/README.md index 4067e842..0f45b9a0 100644 --- a/README.md +++ b/README.md @@ -30,6 +30,8 @@ $ cmake .. && make -j * Gentoo: `emerge dev-libs/spdlog` * Arch Linux: `yaourt -S spdlog-git` * vcpkg: `vcpkg install spdlog` +* conan: `spdlog/[>=1.4.1]@bincrafters/stable` + ## Features * Very fast (see [benchmarks](#benchmarks) below). diff --git a/bench/CMakeLists.txt b/bench/CMakeLists.txt index d087cf66..0ea88423 100644 --- a/bench/CMakeLists.txt +++ b/bench/CMakeLists.txt @@ -24,5 +24,3 @@ target_link_libraries(latency PRIVATE benchmark::benchmark spdlog::spdlog) add_executable(formatter-bench formatter-bench.cpp) target_link_libraries(formatter-bench PRIVATE benchmark::benchmark spdlog::spdlog) - -file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/logs") diff --git a/bench/latency.cpp b/bench/latency.cpp index 730226ca..cd8717d9 100644 --- a/bench/latency.cpp +++ b/bench/latency.cpp @@ -16,26 +16,6 @@ #include "spdlog/sinks/null_sink.h" #include "spdlog/sinks/rotating_file_sink.h" -void prepare_logdir() -{ - spdlog::info("Preparing latency_logs directory.."); -#ifdef _WIN32 - system("if not exist logs mkdir latency_logs"); - system("del /F /Q logs\\*"); -#else - auto rv = system("mkdir -p latency_logs"); - if (rv != 0) - { - throw std::runtime_error("Failed to mkdir -p latency_logs"); - } - rv = system("rm -f latency_logs/*"); - if (rv != 0) - { - throw std::runtime_error("Failed to rm -f latency_logs/*"); - } -#endif -} - void bench_c_string(benchmark::State &state, std::shared_ptr logger) { const char *msg = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum pharetra metus cursus " @@ -83,8 +63,6 @@ int main(int argc, char *argv[]) size_t rotating_files = 5; int n_threads = benchmark::CPUInfo::Get().num_cpus; - prepare_logdir(); - // disabled loggers auto disabled_logger = std::make_shared("bench", std::make_shared()); disabled_logger->set_level(spdlog::level::off); diff --git a/bench/meson.build b/bench/meson.build index c2604271..c877b6ac 100644 --- a/bench/meson.build +++ b/bench/meson.build @@ -12,4 +12,3 @@ foreach i : bench_matrix benchmark('bench_' + i[0], bench_exe, args: i[2]) endforeach -run_command(find_program('mkdir'), meson.current_build_dir() + '/logs') diff --git a/cmake/spdlog.pc.in b/cmake/spdlog.pc.in index 86f5905f..861707c3 100644 --- a/cmake/spdlog.pc.in +++ b/cmake/spdlog.pc.in @@ -7,5 +7,7 @@ Name: lib@PROJECT_NAME@ Description: Fast C++ logging library. URL: https://github.com/gabime/@PROJECT_NAME@ Version: @SPDLOG_VERSION@ -CFlags: -I${includedir}/@SPDLOG_CFLAGS@ -Libs: -L${libdir}/@PROJECT_NAME@ -l@PROJECT_NAME@ +CFlags: -I${includedir} @PKG_CONFIG_DEFINES@ +Libs: -L${libdir} -lspdlog -pthread +Requires: @PKG_CONFIG_REQUIRES@ + diff --git a/example/CMakeLists.txt b/example/CMakeLists.txt index b5fc4060..458ca952 100644 --- a/example/CMakeLists.txt +++ b/example/CMakeLists.txt @@ -25,5 +25,3 @@ if(SPDLOG_BUILD_EXAMPLE_HO) target_link_libraries(example_header_only PRIVATE spdlog::spdlog_header_only) endif() -# Create logs directory -file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/logs") diff --git a/example/example.cpp b/example/example.cpp index 2a18677a..0bc838bd 100644 --- a/example/example.cpp +++ b/example/example.cpp @@ -143,7 +143,7 @@ void async_example() #include "spdlog/fmt/bin_to_hex.h" void binary_example() { - std::vector buf; + std::vector buf(80); for (int i = 0; i < 80; i++) { buf.push_back(static_cast(i & 0xff)); diff --git a/example/meson.build b/example/meson.build index 7e29abb2..c37c4c3c 100644 --- a/example/meson.build +++ b/example/meson.build @@ -1,5 +1,4 @@ executable('example', 'example.cpp', dependencies: spdlog_dep) executable('example_header_only', 'example.cpp', dependencies: spdlog_headeronly_dep) -run_command(find_program('mkdir'), meson.current_build_dir() + '/logs') diff --git a/include/spdlog/async.h b/include/spdlog/async.h index 833be4fb..afaf263f 100644 --- a/include/spdlog/async.h +++ b/include/spdlog/async.h @@ -6,7 +6,7 @@ // // Async logging using global thread pool // All loggers created here share same global thread pool. -// Each log message is pushed to a queue along withe a shared pointer to the +// 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 @@ -14,9 +14,9 @@ // This is because each message in the queue holds a shared_ptr to the // originating logger. -#include "spdlog/async_logger.h" -#include "spdlog/details/registry.h" -#include "spdlog/details/thread_pool.h" +#include +#include +#include #include #include diff --git a/include/spdlog/async_logger-inl.h b/include/spdlog/async_logger-inl.h index cfeda2de..356db0e7 100644 --- a/include/spdlog/async_logger-inl.h +++ b/include/spdlog/async_logger-inl.h @@ -4,11 +4,11 @@ #pragma once #ifndef SPDLOG_HEADER_ONLY -#include "spdlog/async_logger.h" +#include #endif -#include "spdlog/sinks/sink.h" -#include "spdlog/details/thread_pool.h" +#include +#include #include #include diff --git a/include/spdlog/async_logger.h b/include/spdlog/async_logger.h index 0a685186..829c5acc 100644 --- a/include/spdlog/async_logger.h +++ b/include/spdlog/async_logger.h @@ -14,7 +14,7 @@ // Upon destruction, logs all remaining messages in the queue before // destructing.. -#include "spdlog/logger.h" +#include namespace spdlog { diff --git a/include/spdlog/common-inl.h b/include/spdlog/common-inl.h index 7ba12511..a21284d2 100644 --- a/include/spdlog/common-inl.h +++ b/include/spdlog/common-inl.h @@ -4,7 +4,7 @@ #pragma once #ifndef SPDLOG_HEADER_ONLY -#include "spdlog/common.h" +#include #endif namespace spdlog { diff --git a/include/spdlog/common.h b/include/spdlog/common.h index 13fbe970..830220ef 100644 --- a/include/spdlog/common.h +++ b/include/spdlog/common.h @@ -3,8 +3,8 @@ #pragma once -#include "spdlog/tweakme.h" -#include "spdlog/details/null_mutex.h" +#include +#include #include #include @@ -35,7 +35,7 @@ #define SPDLOG_INLINE inline #endif -#include "spdlog/fmt/fmt.h" +#include // visual studio upto 2013 does not support noexcept nor constexpr #if defined(_MSC_VER) && (_MSC_VER < 1900) @@ -62,7 +62,7 @@ #endif #ifndef SPDLOG_FUNCTION -#define SPDLOG_FUNCTION __FUNCTION__ +#define SPDLOG_FUNCTION static_cast(__FUNCTION__) #endif #ifdef SPDLOG_NO_EXCEPTIONS diff --git a/include/spdlog/details/backtracer-inl.h b/include/spdlog/details/backtracer-inl.h index daf1ab33..21553c26 100644 --- a/include/spdlog/details/backtracer-inl.h +++ b/include/spdlog/details/backtracer-inl.h @@ -4,7 +4,7 @@ #pragma once #ifndef SPDLOG_HEADER_ONLY -#include "spdlog/details/backtracer.h" +#include #endif namespace spdlog { namespace details { @@ -26,7 +26,7 @@ SPDLOG_INLINE backtracer &backtracer::operator=(backtracer other) { std::lock_guard lock(mutex_); enabled_ = other.enabled(); - messages_ = other.messages_; + messages_ = std::move(other.messages_); return *this; } @@ -48,11 +48,6 @@ SPDLOG_INLINE bool backtracer::enabled() const return enabled_.load(std::memory_order_relaxed); } -SPDLOG_INLINE backtracer::operator bool() const -{ - return enabled(); -} - SPDLOG_INLINE void backtracer::push_back(const log_msg &msg) { std::lock_guard lock{mutex_}; diff --git a/include/spdlog/details/backtracer.h b/include/spdlog/details/backtracer.h index cf813fe6..0e779cab 100644 --- a/include/spdlog/details/backtracer.h +++ b/include/spdlog/details/backtracer.h @@ -3,8 +3,8 @@ #pragma once -#include "spdlog/details/log_msg_buffer.h" -#include "spdlog/details/circular_q.h" +#include +#include #include #include @@ -31,7 +31,6 @@ public: void enable(size_t size); void disable(); bool enabled() const; - explicit operator bool() const; void push_back(const log_msg &msg); // pop all items in the q and apply the given fun on each of them. diff --git a/include/spdlog/details/circular_q.h b/include/spdlog/details/circular_q.h index fee3a3bf..325dbfea 100644 --- a/include/spdlog/details/circular_q.h +++ b/include/spdlog/details/circular_q.h @@ -1,7 +1,7 @@ // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. // Distributed under the MIT License (http://opensource.org/licenses/MIT) -// cirucal q view of std::vector. +// circular q view of std::vector. #pragma once #include @@ -72,6 +72,27 @@ public: 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() diff --git a/include/spdlog/details/console_globals.h b/include/spdlog/details/console_globals.h index 6761a30d..665201dd 100644 --- a/include/spdlog/details/console_globals.h +++ b/include/spdlog/details/console_globals.h @@ -3,7 +3,7 @@ #pragma once -#include "spdlog/details/null_mutex.h" +#include #include namespace spdlog { diff --git a/include/spdlog/details/file_helper-inl.h b/include/spdlog/details/file_helper-inl.h index d8c9cab4..cdd45f17 100644 --- a/include/spdlog/details/file_helper-inl.h +++ b/include/spdlog/details/file_helper-inl.h @@ -4,11 +4,11 @@ #pragma once #ifndef SPDLOG_HEADER_ONLY -#include "spdlog/details/file_helper.h" +#include #endif -#include "spdlog/details/os.h" -#include "spdlog/common.h" +#include +#include #include #include @@ -28,28 +28,31 @@ SPDLOG_INLINE file_helper::~file_helper() SPDLOG_INLINE void file_helper::open(const filename_t &fname, bool truncate) { close(); + filename_ = fname; auto *mode = truncate ? SPDLOG_FILENAME_T("wb") : SPDLOG_FILENAME_T("ab"); - _filename = fname; - for (int tries = 0; tries < open_tries; ++tries) + + for (int tries = 0; tries < open_tries_; ++tries) { + // create containing folder if not exists already. + os::create_dir(os::dir_name(fname)); if (!os::fopen_s(&fd_, fname, mode)) { return; } - details::os::sleep_for_millis(open_interval); + details::os::sleep_for_millis(open_interval_); } - SPDLOG_THROW(spdlog_ex("Failed opening file " + os::filename_to_str(_filename) + " for writing", errno)); + SPDLOG_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()) + if (filename_.empty()) { SPDLOG_THROW(spdlog_ex("Failed re opening file - was not opened before")); } - open(_filename, truncate); + this->open(filename_, truncate); } SPDLOG_INLINE void file_helper::flush() @@ -72,7 +75,7 @@ SPDLOG_INLINE void file_helper::write(const memory_buf_t &buf) auto data = buf.data(); if (std::fwrite(data, 1, msg_size, fd_) != msg_size) { - SPDLOG_THROW(spdlog_ex("Failed writing to file " + os::filename_to_str(_filename), errno)); + SPDLOG_THROW(spdlog_ex("Failed writing to file " + os::filename_to_str(filename_), errno)); } } @@ -80,19 +83,14 @@ SPDLOG_INLINE size_t file_helper::size() const { if (fd_ == nullptr) { - SPDLOG_THROW(spdlog_ex("Cannot use size() on closed file " + os::filename_to_str(_filename))); + SPDLOG_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; -} - -SPDLOG_INLINE bool file_helper::file_exists(const filename_t &fname) -{ - return os::file_exists(fname); + return filename_; } // @@ -119,7 +117,7 @@ SPDLOG_INLINE std::tuple file_helper::split_by_extension return std::make_tuple(fname, filename_t()); } - // treat casese like "/etc/rc.d/somelogfile or "/abc/.hiddenfile" + // treat cases like "/etc/rc.d/somelogfile or "/abc/.hiddenfile" auto folder_index = fname.rfind(details::os::folder_sep); if (folder_index != filename_t::npos && folder_index >= ext_index - 1) { @@ -129,5 +127,6 @@ SPDLOG_INLINE std::tuple file_helper::split_by_extension // 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/include/spdlog/details/file_helper.h b/include/spdlog/details/file_helper.h index 990d99e3..3228ce84 100644 --- a/include/spdlog/details/file_helper.h +++ b/include/spdlog/details/file_helper.h @@ -3,7 +3,7 @@ #pragma once -#include "spdlog/common.h" +#include #include namespace spdlog { @@ -29,7 +29,6 @@ public: void write(const memory_buf_t &buf); size_t size() const; const filename_t &filename() const; - static bool file_exists(const filename_t &fname); // // return file path and its extension: @@ -47,10 +46,10 @@ public: static std::tuple split_by_extension(const filename_t &fname); private: - const int open_tries = 5; - const int open_interval = 10; + const int open_tries_ = 5; + const int open_interval_ = 10; std::FILE *fd_{nullptr}; - filename_t _filename; + filename_t filename_; }; } // namespace details } // namespace spdlog diff --git a/include/spdlog/details/fmt_helper.h b/include/spdlog/details/fmt_helper.h index 5298e0a7..85b988e6 100644 --- a/include/spdlog/details/fmt_helper.h +++ b/include/spdlog/details/fmt_helper.h @@ -4,8 +4,8 @@ #include #include -#include "spdlog/fmt/fmt.h" -#include "spdlog/common.h" +#include +#include // Some fmt helpers to efficiently format and pad ints and strings namespace spdlog { diff --git a/include/spdlog/details/log_msg-inl.h b/include/spdlog/details/log_msg-inl.h index cb130532..1e4eaaff 100644 --- a/include/spdlog/details/log_msg-inl.h +++ b/include/spdlog/details/log_msg-inl.h @@ -4,10 +4,10 @@ #pragma once #ifndef SPDLOG_HEADER_ONLY -#include "spdlog/details/log_msg.h" +#include #endif -#include "spdlog/details/os.h" +#include namespace spdlog { namespace details { @@ -15,10 +15,7 @@ namespace details { SPDLOG_INLINE log_msg::log_msg(spdlog::source_loc loc, string_view_t logger_name, spdlog::level::level_enum lvl, spdlog::string_view_t msg) : logger_name(logger_name) , level(lvl) -#ifndef SPDLOG_NO_DATETIME , time(os::now()) -#endif - #ifndef SPDLOG_NO_THREAD_ID , thread_id(os::thread_id()) #endif diff --git a/include/spdlog/details/log_msg.h b/include/spdlog/details/log_msg.h index ccd41ecb..9ae473d4 100644 --- a/include/spdlog/details/log_msg.h +++ b/include/spdlog/details/log_msg.h @@ -3,7 +3,7 @@ #pragma once -#include "spdlog/common.h" +#include #include namespace spdlog { diff --git a/include/spdlog/details/log_msg_buffer-inl.h b/include/spdlog/details/log_msg_buffer-inl.h index c8b9e5ef..51f4d5b9 100644 --- a/include/spdlog/details/log_msg_buffer-inl.h +++ b/include/spdlog/details/log_msg_buffer-inl.h @@ -4,7 +4,7 @@ #pragma once #ifndef SPDLOG_HEADER_ONLY -#include "spdlog/details/log_msg_buffer.h" +#include #endif namespace spdlog { @@ -26,9 +26,7 @@ SPDLOG_INLINE log_msg_buffer::log_msg_buffer(const log_msg_buffer &other) update_string_views(); } -SPDLOG_INLINE log_msg_buffer::log_msg_buffer(log_msg_buffer &&other) - : log_msg{std::move(other)} - , buffer{std::move(other.buffer)} +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(); } @@ -42,9 +40,9 @@ SPDLOG_INLINE log_msg_buffer &log_msg_buffer::operator=(const log_msg_buffer &ot return *this; } -SPDLOG_INLINE log_msg_buffer &log_msg_buffer::operator=(log_msg_buffer &&other) +SPDLOG_INLINE log_msg_buffer &log_msg_buffer::operator=(log_msg_buffer &&other) SPDLOG_NOEXCEPT { - log_msg::operator=(std::move(other)); + log_msg::operator=(other); buffer = std::move(other.buffer); update_string_views(); return *this; diff --git a/include/spdlog/details/log_msg_buffer.h b/include/spdlog/details/log_msg_buffer.h index 5ddcbc10..c20ae7b0 100644 --- a/include/spdlog/details/log_msg_buffer.h +++ b/include/spdlog/details/log_msg_buffer.h @@ -3,7 +3,7 @@ #pragma once -#include "spdlog/details/log_msg.h" +#include namespace spdlog { namespace details { @@ -20,9 +20,9 @@ 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); + 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); + log_msg_buffer &operator=(log_msg_buffer &&other) SPDLOG_NOEXCEPT; }; } // namespace details diff --git a/include/spdlog/details/mpmc_blocking_q.h b/include/spdlog/details/mpmc_blocking_q.h index 397cd56c..7f8a2535 100644 --- a/include/spdlog/details/mpmc_blocking_q.h +++ b/include/spdlog/details/mpmc_blocking_q.h @@ -10,7 +10,7 @@ // dequeue_for(..) - will block until the queue is not empty or timeout have // passed. -#include "spdlog/details/circular_q.h" +#include #include #include diff --git a/include/spdlog/details/os-inl.h b/include/spdlog/details/os-inl.h index f436b0d1..84b99969 100644 --- a/include/spdlog/details/os-inl.h +++ b/include/spdlog/details/os-inl.h @@ -4,10 +4,10 @@ #pragma once #ifndef SPDLOG_HEADER_ONLY -#include "spdlog/details/os.h" +#include #endif -#include "spdlog/common.h" +#include #include #include @@ -42,6 +42,8 @@ #include #endif +#include // for _mkdir/_wmkdir + #else // unix #include @@ -91,17 +93,17 @@ SPDLOG_INLINE std::tm localtime(const std::time_t &time_tt) SPDLOG_NOEXCEPT #ifdef _WIN32 std::tm tm; - localtime_s(&tm, &time_tt); + ::localtime_s(&tm, &time_tt); #else std::tm tm; - localtime_r(&time_tt, &tm); + ::localtime_r(&time_tt, &tm); #endif return tm; } SPDLOG_INLINE std::tm localtime() SPDLOG_NOEXCEPT { - std::time_t now_t = time(nullptr); + std::time_t now_t = ::time(nullptr); return localtime(now_t); } @@ -110,52 +112,52 @@ SPDLOG_INLINE std::tm gmtime(const std::time_t &time_tt) SPDLOG_NOEXCEPT #ifdef _WIN32 std::tm tm; - gmtime_s(&tm, &time_tt); + ::gmtime_s(&tm, &time_tt); #else std::tm tm; - gmtime_r(&time_tt, &tm); + ::gmtime_r(&time_tt, &tm); #endif return tm; } SPDLOG_INLINE std::tm gmtime() SPDLOG_NOEXCEPT { - std::time_t now_t = time(nullptr); + std::time_t now_t = ::time(nullptr); return gmtime(now_t); } +#ifdef SPDLOG_PREVENT_CHILD_FD SPDLOG_INLINE void prevent_child_fd(FILE *f) { - #ifdef _WIN32 -#if !defined(__cplusplus_winrt) - auto file_handle = reinterpret_cast(_get_osfhandle(_fileno(f))); + auto file_handle = reinterpret_cast(_get_osfhandle(::_fileno(f))); if (!::SetHandleInformation(file_handle, HANDLE_FLAG_INHERIT, 0)) SPDLOG_THROW(spdlog_ex("SetHandleInformation failed", errno)); -#endif #else - auto fd = fileno(f); - if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1) + auto fd = ::fileno(f); + if (::fcntl(fd, F_SETFD, FD_CLOEXEC) == -1) { SPDLOG_THROW(spdlog_ex("fcntl with FD_CLOEXEC failed", errno)); } #endif } +#endif // SPDLOG_PREVENT_CHILD_FD // 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); + *fp = ::_wfsopen((filename.c_str()), mode.c_str(), _SH_DENYNO); #else - *fp = _fsopen((filename.c_str()), mode.c_str(), _SH_DENYNO); + *fp = ::_fsopen((filename.c_str()), mode.c_str(), _SH_DENYNO); #endif #else // unix - *fp = fopen((filename.c_str()), mode.c_str()); + *fp = ::fopen((filename.c_str()), mode.c_str()); #endif #ifdef SPDLOG_PREVENT_CHILD_FD + // prevent child processes from inheriting log file descriptors if (*fp != nullptr) { prevent_child_fd(*fp); @@ -167,7 +169,7 @@ SPDLOG_INLINE bool fopen_s(FILE **fp, const filename_t &filename, const filename SPDLOG_INLINE int remove(const filename_t &filename) SPDLOG_NOEXCEPT { #if defined(_WIN32) && defined(SPDLOG_WCHAR_FILENAMES) - return _wremove(filename.c_str()); + return ::_wremove(filename.c_str()); #else return std::remove(filename.c_str()); #endif @@ -175,28 +177,28 @@ SPDLOG_INLINE int remove(const filename_t &filename) SPDLOG_NOEXCEPT SPDLOG_INLINE int remove_if_exists(const filename_t &filename) SPDLOG_NOEXCEPT { - return file_exists(filename) ? remove(filename) : 0; + 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()); + return ::_wrename(filename1.c_str(), filename2.c_str()); #else return std::rename(filename1.c_str(), filename2.c_str()); #endif } -// Return true if file exists -SPDLOG_INLINE bool file_exists(const filename_t &filename) SPDLOG_NOEXCEPT +// 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()); + auto attribs = ::GetFileAttributesW(filename.c_str()); #else - auto attribs = GetFileAttributesA(filename.c_str()); + auto attribs = ::GetFileAttributesA(filename.c_str()); #endif - return (attribs != INVALID_FILE_ATTRIBUTES && !(attribs & FILE_ATTRIBUTE_DIRECTORY)); + 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); @@ -211,16 +213,16 @@ SPDLOG_INLINE size_t filesize(FILE *f) SPDLOG_THROW(spdlog_ex("Failed getting file size. fd is null")); } #if defined(_WIN32) && !defined(__CYGWIN__) - int fd = _fileno(f); + int fd = ::_fileno(f); #if _WIN64 // 64 bits - __int64 ret = _filelengthi64(fd); + __int64 ret = ::_filelengthi64(fd); if (ret >= 0) { return static_cast(ret); } #else // windows 32 bits - long ret = _filelength(fd); + long ret = ::_filelength(fd); if (ret >= 0) { return static_cast(ret); @@ -228,7 +230,7 @@ SPDLOG_INLINE size_t filesize(FILE *f) #endif #else // unix - int fd = fileno(f); + int fd = ::fileno(f); // 64 bits(but not in osx or cygwin, where fstat64 is deprecated) #if (defined(__linux__) || defined(__sun) || defined(_AIX)) && (defined(__LP64__) || defined(_LP64)) struct stat64 st; @@ -236,9 +238,8 @@ SPDLOG_INLINE size_t filesize(FILE *f) { return static_cast(st.st_size); } -#else // unix 32 bits or cygwin +#else // other unix or linux 32 bits or cygwin struct stat st; - if (::fstat(fd, &st) == 0) { return static_cast(st.st_size); @@ -255,10 +256,10 @@ 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); + auto rv = ::GetTimeZoneInformation(&tzinfo); #else DYNAMIC_TIME_ZONE_INFORMATION tzinfo; - auto rv = GetDynamicTimeZoneInformation(&tzinfo); + auto rv = ::GetDynamicTimeZoneInformation(&tzinfo); #endif if (rv == TIME_ZONE_ID_INVALID) SPDLOG_THROW(spdlog::spdlog_ex("Failed getting timezone info. ", errno)); @@ -275,7 +276,7 @@ SPDLOG_INLINE int utc_minutes_offset(const std::tm &tm) return offset; #else -#if defined(sun) || defined(__sun) || defined(_AIX) +#if defined(sun) || defined(__sun) || defined(_AIX) || (!defined(_BSD_SOURCE) && !defined(_GNU_SOURCE)) // 'tm_gmtoff' field is BSD extension and it's missing on SunOS/Solaris struct helper { @@ -324,15 +325,15 @@ SPDLOG_INLINE size_t _thread_id() SPDLOG_NOEXCEPT #if defined(__ANDROID__) && defined(__ANDROID_API__) && (__ANDROID_API__ < 21) #define SYS_gettid __NR_gettid #endif - return static_cast(syscall(SYS_gettid)); + return static_cast(::syscall(SYS_gettid)); #elif defined(_AIX) || defined(__DragonFly__) || defined(__FreeBSD__) - return static_cast(pthread_getthreadid_np()); + return static_cast(::pthread_getthreadid_np()); #elif defined(__NetBSD__) - return static_cast(_lwp_self()); + return static_cast(::_lwp_self()); #elif defined(__OpenBSD__) - return static_cast(getthrid()); + return static_cast(::getthrid()); #elif defined(__sun) - return static_cast(thr_self()); + return static_cast(::thr_self()); #elif __APPLE__ uint64_t tid; pthread_threadid_np(nullptr, &tid); @@ -417,16 +418,16 @@ SPDLOG_INLINE bool in_terminal(FILE *file) SPDLOG_NOEXCEPT { #ifdef _WIN32 - return _isatty(_fileno(file)) != 0; + return ::_isatty(_fileno(file)) != 0; #else - return isatty(fileno(file)) != 0; + 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())) + if (wstr.size() > static_cast((std::numeric_limits::max)())) { SPDLOG_THROW(spdlog::spdlog_ex("UTF-16 string is too big to be converted to UTF-8")); } @@ -460,6 +461,76 @@ SPDLOG_INLINE void wstr_to_utf8buf(wstring_view_t wstr, memory_buf_t &target) } #endif // (defined(SPDLOG_WCHAR_TO_UTF8_SUPPORT) || defined(SPDLOG_WCHAR_FILENAMES)) && defined(_WIN32) +// return true on success +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(filename_t path) +{ + if (path_exists(path)) + { + return true; + } + + if (path.empty()) + { + return false; + } + +#ifdef _WIN32 + // support forward slash in windows + std::replace(path.begin(), path.end(), '/', folder_sep); +#endif + + size_t search_offset = 0; + do + { + auto token_pos = path.find(folder_sep, 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(filename_t path) +{ +#ifdef _WIN32 + // support forward slash in windows + std::replace(path.begin(), path.end(), '/', folder_sep); +#endif + auto pos = path.find_last_of(folder_sep); + return pos != filename_t::npos ? path.substr(0, pos) : filename_t{}; +} + } // namespace os } // namespace details } // namespace spdlog diff --git a/include/spdlog/details/os.h b/include/spdlog/details/os.h index 6d9dae13..0894a6c0 100644 --- a/include/spdlog/details/os.h +++ b/include/spdlog/details/os.h @@ -3,7 +3,7 @@ #pragma once -#include "spdlog/common.h" +#include #include // std::time_t namespace spdlog { @@ -33,12 +33,14 @@ SPDLOG_CONSTEXPR static const char *default_eol = SPDLOG_EOL; // folder separator #ifdef _WIN32 -const char folder_sep = '\\'; +static const char folder_sep = '\\'; #else SPDLOG_CONSTEXPR static const char folder_sep = '/'; #endif +#ifdef SPDLOG_PREVENT_CHILD_FD void prevent_child_fd(FILE *f); +#endif // fopen_s on non windows for writing bool fopen_s(FILE **fp, const filename_t &filename, const filename_t &mode); @@ -53,7 +55,7 @@ int remove_if_exists(const filename_t &filename) SPDLOG_NOEXCEPT; int rename(const filename_t &filename1, const filename_t &filename2) SPDLOG_NOEXCEPT; // Return if file exists. -bool file_exists(const filename_t &filename) SPDLOG_NOEXCEPT; +bool path_exists(const filename_t &filename) SPDLOG_NOEXCEPT; // Return file size according to open FILE* object size_t filesize(FILE *f); @@ -81,7 +83,7 @@ int pid() SPDLOG_NOEXCEPT; // Source: https://github.com/agauniyal/rang/ bool is_color_terminal() SPDLOG_NOEXCEPT; -// Detrmine if the terminal attached +// Determine if the terminal attached // Source: https://github.com/agauniyal/rang/ bool in_terminal(FILE *file) SPDLOG_NOEXCEPT; @@ -89,6 +91,17 @@ bool in_terminal(FILE *file) SPDLOG_NOEXCEPT; void wstr_to_utf8buf(wstring_view_t wstr, memory_buf_t &target); #endif +// Return directory name from given path or empty string +// "abc/file" => "abc" +// "abc/" => "abc" +// "abc" => "" +// "abc///" => "abc//" +filename_t dir_name(filename_t path); + +// Create a dir from the given path. +// Return true if succeeded or if this dir already exists. +bool create_dir(filename_t path); + } // namespace os } // namespace details } // namespace spdlog diff --git a/include/spdlog/details/pattern_formatter-inl.h b/include/spdlog/details/pattern_formatter-inl.h index 1b95eb6d..83d0283b 100644 --- a/include/spdlog/details/pattern_formatter-inl.h +++ b/include/spdlog/details/pattern_formatter-inl.h @@ -4,14 +4,14 @@ #pragma once #ifndef SPDLOG_HEADER_ONLY -#include "spdlog/details/pattern_formatter.h" +#include #endif -#include "spdlog/details/fmt_helper.h" -#include "spdlog/details/log_msg.h" -#include "spdlog/details/os.h" -#include "spdlog/fmt/fmt.h" -#include "spdlog/formatter.h" +#include +#include +#include +#include +#include #include #include @@ -39,47 +39,50 @@ public: : padinfo_(padinfo) , dest_(dest) { - - if (padinfo_.width_ <= wrapped_size) + remaining_pad_ = static_cast(padinfo.width_) - static_cast(wrapped_size); + if (remaining_pad_ <= 0) { - total_pad_ = 0; return; } - total_pad_ = padinfo.width_ - wrapped_size; if (padinfo_.side_ == padding_info::left) { - pad_it(total_pad_); - total_pad_ = 0; + pad_it(remaining_pad_); + remaining_pad_ = 0; } else if (padinfo_.side_ == padding_info::center) { - auto half_pad = total_pad_ / 2; - auto reminder = total_pad_ & 1; + auto half_pad = remaining_pad_ / 2; + auto reminder = remaining_pad_ & 1; pad_it(half_pad); - total_pad_ = half_pad + reminder; // for the right side + remaining_pad_ = half_pad + reminder; // for the right side } } ~scoped_padder() { - if (total_pad_) + if (remaining_pad_ >= 0) + { + pad_it(remaining_pad_); + } + else if (padinfo_.truncate_) { - pad_it(total_pad_); + long new_size = static_cast(dest_.size()) + remaining_pad_; + dest_.resize(static_cast(new_size)); } } private: - void pad_it(size_t count) + void pad_it(long count) { // count = std::min(count, spaces_.size()); - assert(count <= spaces_.size()); + // assert(count <= spaces_.size()); fmt_helper::append_string_view(string_view_t(spaces_.data(), count), dest_); } const padding_info &padinfo_; memory_buf_t &dest_; - size_t total_pad_; + long remaining_pad_; string_view_t spaces_{" ", 64}; }; @@ -593,14 +596,7 @@ public: const size_t field_size = 6; ScopedPadder p(field_size, padinfo_, dest); -#ifdef _WIN32 - int total_minutes = get_cached_offset(msg, tm_time); -#else - // No need to chache under gcc, - // it is very fast (already stored in tm.tm_gmtoff) - (void)(msg); - int total_minutes = os::utc_minutes_offset(tm_time); -#endif + auto total_minutes = get_cached_offset(msg, tm_time); bool is_negative = total_minutes < 0; if (is_negative) { @@ -619,7 +615,6 @@ public: private: log_clock::time_point last_update_{std::chrono::seconds(0)}; -#ifdef _WIN32 int offset_minutes_{0}; int get_cached_offset(const log_msg &msg, const std::tm &tm_time) @@ -632,7 +627,6 @@ private: } return offset_minutes_; } -#endif }; // Thread id @@ -885,7 +879,7 @@ public: fmt_helper::pad6(static_cast(delta_units.count()), dest); } -protected: +private: log_clock::time_point last_message_time_; }; @@ -904,8 +898,6 @@ public: using std::chrono::milliseconds; using std::chrono::seconds; -#ifndef SPDLOG_NO_DATETIME - // cache the date/time part for the next second. auto duration = msg.time.time_since_epoch(); auto secs = duration_cast(duration); @@ -941,10 +933,6 @@ public: dest.push_back(']'); dest.push_back(' '); -#else // no datetime needed - (void)tm_time; -#endif - #ifndef SPDLOG_NO_NAME if (msg.logger_name.size() > 0) { @@ -1014,14 +1002,13 @@ SPDLOG_INLINE std::unique_ptr pattern_formatter::clone() const SPDLOG_INLINE void pattern_formatter::format(const details::log_msg &msg, memory_buf_t &dest) { -#ifndef SPDLOG_NO_DATETIME 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; } -#endif + for (auto &f : formatters_) { f->format(msg, cached_tm_, dest); @@ -1225,7 +1212,7 @@ SPDLOG_INLINE void pattern_formatter::handle_flag_(char flag, details::padding_i } } -// Extract given pad spec (e.g. %8X) +// 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) @@ -1256,7 +1243,7 @@ SPDLOG_INLINE details::padding_info pattern_formatter::handle_padspec_(std::stri if (it == end || !std::isdigit(static_cast(*it))) { - return padding_info{0, side}; + return padding_info{}; // no padding if no digit found here } auto width = static_cast(*it) - '0'; @@ -1265,7 +1252,20 @@ SPDLOG_INLINE details::padding_info pattern_formatter::handle_padspec_(std::stri auto digit = static_cast(*it) - '0'; width = width * 10 + digit; } - return details::padding_info{std::min(width, max_width), side}; + + // 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) diff --git a/include/spdlog/details/pattern_formatter.h b/include/spdlog/details/pattern_formatter.h index 7191ea9b..fa134ada 100644 --- a/include/spdlog/details/pattern_formatter.h +++ b/include/spdlog/details/pattern_formatter.h @@ -3,10 +3,10 @@ #pragma once -#include "spdlog/common.h" -#include "spdlog/details/log_msg.h" -#include "spdlog/details/os.h" -#include "spdlog/formatter.h" +#include +#include +#include +#include #include #include @@ -29,17 +29,21 @@ struct padding_info }; padding_info() = default; - padding_info(size_t width, padding_info::pad_side side) + padding_info(size_t width, padding_info::pad_side side, bool truncate) : width_(width) , side_(side) + , truncate_(truncate) + , enabled_(true) {} bool enabled() const { - return width_ != 0; + return enabled_; } const size_t width_ = 0; const pad_side side_ = left; + bool truncate_ = false; + bool enabled_ = false; }; class flag_formatter diff --git a/include/spdlog/details/periodic_worker-inl.h b/include/spdlog/details/periodic_worker-inl.h index 1af6288a..1d794994 100644 --- a/include/spdlog/details/periodic_worker-inl.h +++ b/include/spdlog/details/periodic_worker-inl.h @@ -4,7 +4,7 @@ #pragma once #ifndef SPDLOG_HEADER_ONLY -#include "spdlog/details/periodic_worker.h" +#include #endif namespace spdlog { diff --git a/include/spdlog/details/registry-inl.h b/include/spdlog/details/registry-inl.h index 93342383..0a3d44af 100644 --- a/include/spdlog/details/registry-inl.h +++ b/include/spdlog/details/registry-inl.h @@ -7,16 +7,17 @@ #include "spdlog/details/registry.h" #endif -#include "spdlog/common.h" -#include "spdlog/logger.h" -#include "spdlog/details/pattern_formatter.h" +#include +#include +#include +#include #ifndef SPDLOG_DISABLE_DEFAULT_LOGGER // support for the default stdout color logger #ifdef _WIN32 -#include "spdlog/sinks/wincolor_sink.h" +#include #else -#include "spdlog/sinks/ansicolor_sink.h" +#include #endif #endif // SPDLOG_DISABLE_DEFAULT_LOGGER @@ -256,10 +257,10 @@ SPDLOG_INLINE std::recursive_mutex ®istry::tp_mutex() return tp_mutex_; } -SPDLOG_INLINE void registry::set_automatic_registration(bool automatic_regsistration) +SPDLOG_INLINE void registry::set_automatic_registration(bool automatic_registration) { std::lock_guard lock(logger_map_mutex_); - automatic_registration_ = automatic_regsistration; + automatic_registration_ = automatic_registration; } SPDLOG_INLINE registry ®istry::instance() diff --git a/include/spdlog/details/registry.h b/include/spdlog/details/registry.h index a75e3a47..53230280 100644 --- a/include/spdlog/details/registry.h +++ b/include/spdlog/details/registry.h @@ -8,8 +8,7 @@ // If user requests a non existing logger, nullptr will be returned // This class is thread safe -#include "spdlog/common.h" -#include "spdlog/details/periodic_worker.h" +#include #include #include @@ -82,7 +81,7 @@ public: std::recursive_mutex &tp_mutex(); - void set_automatic_registration(bool automatic_regsistration); + void set_automatic_registration(bool automatic_registration); // Factory function to create a new logger and register it in this registry template diff --git a/include/spdlog/details/thread_pool-inl.h b/include/spdlog/details/thread_pool-inl.h index 77d0b1fb..910eb2a0 100644 --- a/include/spdlog/details/thread_pool-inl.h +++ b/include/spdlog/details/thread_pool-inl.h @@ -4,10 +4,10 @@ #pragma once #ifndef SPDLOG_HEADER_ONLY -#include "spdlog/details/thread_pool.h" +#include #endif -#include "spdlog/common.h" +#include namespace spdlog { namespace details { @@ -98,24 +98,20 @@ bool SPDLOG_INLINE thread_pool::process_next_msg_() switch (incoming_async_msg.msg_type) { - case async_msg_type::log: - { + case async_msg_type::log: { incoming_async_msg.worker_ptr->backend_sink_it_(incoming_async_msg); return true; } - case async_msg_type::flush: - { + case async_msg_type::flush: { incoming_async_msg.worker_ptr->backend_flush_(); return true; } - case async_msg_type::terminate: - { + case async_msg_type::terminate: { return false; } - default: - { + default: { assert(false && "Unexpected async_msg_type"); } } diff --git a/include/spdlog/details/thread_pool.h b/include/spdlog/details/thread_pool.h index 81bd12de..12078044 100644 --- a/include/spdlog/details/thread_pool.h +++ b/include/spdlog/details/thread_pool.h @@ -3,9 +3,9 @@ #pragma once -#include "spdlog/details/log_msg_buffer.h" -#include "spdlog/details/mpmc_blocking_q.h" -#include "spdlog/details/os.h" +#include +#include +#include #include #include @@ -27,7 +27,7 @@ enum class async_msg_type terminate }; -#include "spdlog/details/log_msg_buffer.h" +#include // Async msg to move to/from the queue // Movable only. should never be copied struct async_msg : log_msg_buffer diff --git a/include/spdlog/fmt/fmt.h b/include/spdlog/fmt/fmt.h index 5d039b8c..ea2efb17 100644 --- a/include/spdlog/fmt/fmt.h +++ b/include/spdlog/fmt/fmt.h @@ -22,6 +22,6 @@ #include "bundled/core.h" #include "bundled/format.h" #else // SPDLOG_FMT_EXTERNAL is defined - use external fmtlib -#include "fmt/core.h" -#include "fmt/format.h" +#include +#include #endif diff --git a/include/spdlog/formatter.h b/include/spdlog/formatter.h index 9a4ed035..5086fb21 100644 --- a/include/spdlog/formatter.h +++ b/include/spdlog/formatter.h @@ -3,8 +3,8 @@ #pragma once -#include "fmt/fmt.h" -#include "spdlog/details/log_msg.h" +#include +#include namespace spdlog { diff --git a/include/spdlog/logger-inl.h b/include/spdlog/logger-inl.h index 05c57e8e..95a485f1 100644 --- a/include/spdlog/logger-inl.h +++ b/include/spdlog/logger-inl.h @@ -4,12 +4,12 @@ #pragma once #ifndef SPDLOG_HEADER_ONLY -#include "spdlog/logger.h" +#include #endif -#include "spdlog/sinks/sink.h" -#include "spdlog/details/backtracer.h" -#include "spdlog/details/pattern_formatter.h" +#include +#include +#include #include @@ -64,11 +64,6 @@ SPDLOG_INLINE void swap(logger &a, logger &b) a.swap(b); } -SPDLOG_INLINE bool logger::should_log(level::level_enum msg_level) const -{ - return msg_level >= level_.load(std::memory_order_relaxed); -} - SPDLOG_INLINE void logger::set_level(level::level_enum log_level) { level_.store(log_level); @@ -85,7 +80,7 @@ SPDLOG_INLINE const std::string &logger::name() const } // set formatting for the sinks in this logger. -// each sink will get a seperate instance of the formatter object. +// 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) @@ -155,7 +150,7 @@ SPDLOG_INLINE std::vector &logger::sinks() // error handler SPDLOG_INLINE void logger::set_error_handler(err_handler handler) { - custom_err_handler_ = handler; + custom_err_handler_ = std::move(handler); } // create new logger with same sinks and configuration. @@ -167,6 +162,18 @@ SPDLOG_INLINE std::shared_ptr logger::clone(std::string logger_name) } // 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_) @@ -202,7 +209,7 @@ SPDLOG_INLINE void logger::flush_() SPDLOG_INLINE void logger::dump_backtrace_() { using details::log_msg; - if (tracer_) + if (tracer_.enabled()) { sink_it_(log_msg{name(), level::info, "****************** Backtrace Start ******************"}); tracer_.foreach_pop([this](const log_msg &msg) { this->sink_it_(msg); }); diff --git a/include/spdlog/logger.h b/include/spdlog/logger.h index 0e4eaa00..43f39600 100644 --- a/include/spdlog/logger.h +++ b/include/spdlog/logger.h @@ -14,12 +14,12 @@ // The use of private formatter per sink provides the opportunity to cache some // formatted data, and support for different format per sink. -#include "spdlog/common.h" -#include "spdlog/details/log_msg.h" -#include "spdlog/details/backtracer.h" +#include +#include +#include #ifdef SPDLOG_WCHAR_TO_UTF8_SUPPORT -#include "spdlog/details/os.h" +#include #endif #include @@ -76,8 +76,9 @@ public: template void log(source_loc loc, level::level_enum lvl, string_view_t fmt, const Args &... args) { - auto level_enabled = should_log(lvl); - if (!level_enabled && !tracer_) + bool log_enabled = should_log(lvl); + bool traceback_enabled = tracer_.enabled(); + if (!log_enabled && !traceback_enabled) { return; } @@ -86,14 +87,7 @@ public: memory_buf_t buf; fmt::format_to(buf, fmt, args...); details::log_msg log_msg(loc, name_, lvl, string_view_t(buf.data(), buf.size())); - if (level_enabled) - { - sink_it_(log_msg); - } - if (tracer_) - { - tracer_.push_back(log_msg); - } + log_it_(log_msg, log_enabled, traceback_enabled); } SPDLOG_LOGGER_CATCH() } @@ -150,24 +144,15 @@ public: template::value, T>::type * = nullptr> void log(source_loc loc, level::level_enum lvl, const T &msg) { - auto level_enabled = should_log(lvl); - if (!level_enabled && !tracer_) + bool log_enabled = should_log(lvl); + bool traceback_enabled = tracer_.enabled(); + if (!log_enabled && !traceback_enabled) { return; } - SPDLOG_TRY - { - details::log_msg log_msg(loc, name_, lvl, msg); - if (level_enabled) - { - sink_it_(log_msg); - } - if (tracer_) - { - tracer_.push_back(log_msg); - } - } - SPDLOG_LOGGER_CATCH() + + 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) @@ -228,8 +213,9 @@ public: template void log(source_loc loc, level::level_enum lvl, wstring_view_t fmt, const Args &... args) { - auto level_enabled = should_log(lvl); - if (!level_enabled && !tracer_) + bool log_enabled = should_log(lvl); + bool traceback_enabled = tracer_.enabled(); + if (!log_enabled && !traceback_enabled) { return; } @@ -242,15 +228,7 @@ public: 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())); - - if (level_enabled) - { - sink_it_(log_msg); - } - if (tracer_) - { - tracer_.push_back(log_msg); - } + log_it_(log_msg, log_enabled, traceback_enabled); } SPDLOG_LOGGER_CATCH() } @@ -301,25 +279,36 @@ public: template::value, T>::type * = nullptr> void log(source_loc loc, level::level_enum lvl, const T &msg) { - if (!should_log(lvl)) + bool log_enabled = should_log(lvl); + bool traceback_enabled = tracer_.enabled(); + if (!log_enabled && !traceback_enabled) { return; } - try + SPDLOG_TRY { memory_buf_t buf; details::os::wstr_to_utf8buf(msg, buf); - details::log_msg log_msg(loc, name_, lvl, string_view_t(buf.data(), buf.size())); - sink_it_(log_msg); + log_it_(log_msg, log_enabled, traceback_enabled); } SPDLOG_LOGGER_CATCH() } #endif // _WIN32 #endif // SPDLOG_WCHAR_TO_UTF8_SUPPORT - bool should_log(level::level_enum msg_level) const; + // 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); @@ -328,7 +317,7 @@ public: const std::string &name() const; // set formatting for the sinks in this logger. - // each sink will get a seperate instance of the formatter object. + // each sink will get a separate instance of the formatter object. void set_formatter(std::unique_ptr f); void set_pattern(std::string pattern, pattern_time_type time_type = pattern_time_type::local); @@ -363,6 +352,9 @@ protected: err_handler custom_err_handler_{nullptr}; details::backtracer tracer_; + // 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_(); diff --git a/include/spdlog/sinks/android_sink.h b/include/spdlog/sinks/android_sink.h index d1e87f2d..bdbe542b 100644 --- a/include/spdlog/sinks/android_sink.h +++ b/include/spdlog/sinks/android_sink.h @@ -5,11 +5,11 @@ #ifdef __ANDROID__ -#include "spdlog/details/fmt_helper.h" -#include "spdlog/details/null_mutex.h" -#include "spdlog/details/os.h" -#include "spdlog/sinks/base_sink.h" -#include "spdlog/details/synchronous_factory.h" +#include +#include +#include +#include +#include #include #include diff --git a/include/spdlog/sinks/ansicolor_sink-inl.h b/include/spdlog/sinks/ansicolor_sink-inl.h index 280ad7cd..8480b06d 100644 --- a/include/spdlog/sinks/ansicolor_sink-inl.h +++ b/include/spdlog/sinks/ansicolor_sink-inl.h @@ -4,11 +4,11 @@ #pragma once #ifndef SPDLOG_HEADER_ONLY -#include "spdlog/sinks/ansicolor_sink.h" +#include #endif -#include "spdlog/details/pattern_formatter.h" -#include "spdlog/details/os.h" +#include +#include namespace spdlog { namespace sinks { diff --git a/include/spdlog/sinks/ansicolor_sink.h b/include/spdlog/sinks/ansicolor_sink.h index 6ef10e78..16433019 100644 --- a/include/spdlog/sinks/ansicolor_sink.h +++ b/include/spdlog/sinks/ansicolor_sink.h @@ -3,9 +3,9 @@ #pragma once -#include "spdlog/details/console_globals.h" -#include "spdlog/details/null_mutex.h" -#include "spdlog/sinks/sink.h" +#include +#include +#include #include #include #include diff --git a/include/spdlog/sinks/base_sink-inl.h b/include/spdlog/sinks/base_sink-inl.h index 565cdc17..2883c058 100644 --- a/include/spdlog/sinks/base_sink-inl.h +++ b/include/spdlog/sinks/base_sink-inl.h @@ -4,11 +4,11 @@ #pragma once #ifndef SPDLOG_HEADER_ONLY -#include "spdlog/sinks/base_sink.h" +#include #endif -#include "spdlog/common.h" -#include "spdlog/details/pattern_formatter.h" +#include +#include #include diff --git a/include/spdlog/sinks/base_sink.h b/include/spdlog/sinks/base_sink.h index be3956a7..bc832763 100644 --- a/include/spdlog/sinks/base_sink.h +++ b/include/spdlog/sinks/base_sink.h @@ -9,9 +9,9 @@ // implementers.. // -#include "spdlog/common.h" -#include "spdlog/details/log_msg.h" -#include "spdlog/sinks/sink.h" +#include +#include +#include namespace spdlog { namespace sinks { diff --git a/include/spdlog/sinks/basic_file_sink-inl.h b/include/spdlog/sinks/basic_file_sink-inl.h index 0e5275a9..1260d15c 100644 --- a/include/spdlog/sinks/basic_file_sink-inl.h +++ b/include/spdlog/sinks/basic_file_sink-inl.h @@ -4,11 +4,11 @@ #pragma once #ifndef SPDLOG_HEADER_ONLY -#include "spdlog/sinks/basic_file_sink.h" +#include #endif -#include "spdlog/common.h" -#include "spdlog/details/os.h" +#include +#include namespace spdlog { namespace sinks { diff --git a/include/spdlog/sinks/basic_file_sink.h b/include/spdlog/sinks/basic_file_sink.h index 899b89fa..0ab9a4a1 100644 --- a/include/spdlog/sinks/basic_file_sink.h +++ b/include/spdlog/sinks/basic_file_sink.h @@ -3,10 +3,10 @@ #pragma once -#include "spdlog/details/file_helper.h" -#include "spdlog/details/null_mutex.h" -#include "spdlog/sinks/base_sink.h" -#include "spdlog/details/synchronous_factory.h" +#include +#include +#include +#include #include #include diff --git a/include/spdlog/sinks/daily_file_sink.h b/include/spdlog/sinks/daily_file_sink.h index 8514f615..d3eb95a3 100644 --- a/include/spdlog/sinks/daily_file_sink.h +++ b/include/spdlog/sinks/daily_file_sink.h @@ -3,13 +3,13 @@ #pragma once -#include "spdlog/common.h" -#include "spdlog/details/file_helper.h" -#include "spdlog/details/null_mutex.h" -#include "spdlog/fmt/fmt.h" -#include "spdlog/sinks/base_sink.h" -#include "spdlog/details/os.h" -#include "spdlog/details/synchronous_factory.h" +#include +#include +#include +#include +#include +#include +#include #include #include @@ -78,12 +78,7 @@ public: protected: void sink_it_(const details::log_msg &msg) override { -#ifdef SPDLOG_NO_DATETIME - auto time = log_clock::now(); -#else auto time = msg.time; -#endif - bool should_rotate = time >= rotation_tp_; if (should_rotate) { @@ -95,7 +90,7 @@ protected: base_sink::formatter_->format(msg, formatted); file_helper_.write(formatted); - // Do the cleaning ony at the end because it might throw on failure. + // Do the cleaning only at the end because it might throw on failure. if (should_rotate && max_files_ > 0) { delete_old_(); diff --git a/include/spdlog/sinks/dist_sink.h b/include/spdlog/sinks/dist_sink.h index 8f931cf7..a6a33370 100644 --- a/include/spdlog/sinks/dist_sink.h +++ b/include/spdlog/sinks/dist_sink.h @@ -4,9 +4,9 @@ #pragma once #include "base_sink.h" -#include "spdlog/details/log_msg.h" -#include "spdlog/details/null_mutex.h" -#include "spdlog/details/pattern_formatter.h" +#include +#include +#include #include #include diff --git a/include/spdlog/sinks/dup_filter_sink.h b/include/spdlog/sinks/dup_filter_sink.h index ab116a05..8ee63e40 100644 --- a/include/spdlog/sinks/dup_filter_sink.h +++ b/include/spdlog/sinks/dup_filter_sink.h @@ -4,8 +4,8 @@ #pragma once #include "dist_sink.h" -#include "spdlog/details/null_mutex.h" -#include "spdlog/details/log_msg.h" +#include +#include #include #include @@ -16,7 +16,7 @@ // // Example: // -// #include "spdlog/sinks/dup_filter_sink.h" +// #include // // int main() { // auto dup_filter = std::make_shared(std::chrono::seconds(5)); @@ -33,10 +33,6 @@ // [2019-06-25 17:50:56.512] [logger] [info] Skipped 3 duplicate messages.. // [2019-06-25 17:50:56.512] [logger] [info] Different Hello -#ifdef SPDLOG_NO_DATETIME -#error "spdlog::sinks::dup_filter_sink: cannot work when SPDLOG_NO_DATETIME is defined" -#endif - namespace spdlog { namespace sinks { template diff --git a/include/spdlog/sinks/msvc_sink.h b/include/spdlog/sinks/msvc_sink.h index 39b2ce91..6db10bc9 100644 --- a/include/spdlog/sinks/msvc_sink.h +++ b/include/spdlog/sinks/msvc_sink.h @@ -5,8 +5,8 @@ #if defined(_WIN32) -#include "spdlog/details/null_mutex.h" -#include "spdlog/sinks/base_sink.h" +#include +#include #include diff --git a/include/spdlog/sinks/null_sink.h b/include/spdlog/sinks/null_sink.h index 44a45a3e..eb832801 100644 --- a/include/spdlog/sinks/null_sink.h +++ b/include/spdlog/sinks/null_sink.h @@ -3,9 +3,9 @@ #pragma once -#include "spdlog/details/null_mutex.h" -#include "spdlog/sinks/base_sink.h" -#include "spdlog/details/synchronous_factory.h" +#include +#include +#include #include diff --git a/include/spdlog/sinks/ostream_sink.h b/include/spdlog/sinks/ostream_sink.h index 8d47d770..95c1e962 100644 --- a/include/spdlog/sinks/ostream_sink.h +++ b/include/spdlog/sinks/ostream_sink.h @@ -3,8 +3,8 @@ #pragma once -#include "spdlog/details/null_mutex.h" -#include "spdlog/sinks/base_sink.h" +#include +#include #include #include diff --git a/include/spdlog/sinks/ringbuffer_sink.h b/include/spdlog/sinks/ringbuffer_sink.h new file mode 100644 index 00000000..16f7cb56 --- /dev/null +++ b/include/spdlog/sinks/ringbuffer_sink.h @@ -0,0 +1,72 @@ +// 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 n_items = lim > 0 ? (std::min)(lim, q_.size()) : q_.size(); + std::vector ret; + ret.reserve(n_items); + for (size_t i = 0; i < n_items; 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 n_items = lim > 0 ? (std::min)(lim, q_.size()) : q_.size(); + std::vector ret; + ret.reserve(n_items); + for (size_t i = 0; i < n_items; i++) + { + memory_buf_t formatted; + base_sink::formatter_->format(q_.at(i), formatted); + ret.push_back(fmt::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/include/spdlog/sinks/rotating_file_sink-inl.h b/include/spdlog/sinks/rotating_file_sink-inl.h index 15443c5a..bd2d175d 100644 --- a/include/spdlog/sinks/rotating_file_sink-inl.h +++ b/include/spdlog/sinks/rotating_file_sink-inl.h @@ -4,14 +4,14 @@ #pragma once #ifndef SPDLOG_HEADER_ONLY -#include "spdlog/sinks/rotating_file_sink.h" +#include #endif -#include "spdlog/common.h" +#include -#include "spdlog/details/file_helper.h" -#include "spdlog/details/null_mutex.h" -#include "spdlog/fmt/fmt.h" +#include +#include +#include #include #include @@ -88,11 +88,12 @@ 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 (!details::file_helper::file_exists(src)) + if (!path_exists(src)) { continue; } diff --git a/include/spdlog/sinks/rotating_file_sink.h b/include/spdlog/sinks/rotating_file_sink.h index f8c49e75..5be8583a 100644 --- a/include/spdlog/sinks/rotating_file_sink.h +++ b/include/spdlog/sinks/rotating_file_sink.h @@ -3,10 +3,10 @@ #pragma once -#include "spdlog/sinks/base_sink.h" -#include "spdlog/details/file_helper.h" -#include "spdlog/details/null_mutex.h" -#include "spdlog/details/synchronous_factory.h" +#include +#include +#include +#include #include #include diff --git a/include/spdlog/sinks/sink-inl.h b/include/spdlog/sinks/sink-inl.h index d1da94a0..a8dd6a6c 100644 --- a/include/spdlog/sinks/sink-inl.h +++ b/include/spdlog/sinks/sink-inl.h @@ -4,10 +4,10 @@ #pragma once #ifndef SPDLOG_HEADER_ONLY -#include "spdlog/sinks/sink.h" +#include #endif -#include "spdlog/common.h" +#include SPDLOG_INLINE bool spdlog::sinks::sink::should_log(spdlog::level::level_enum msg_level) const { diff --git a/include/spdlog/sinks/sink.h b/include/spdlog/sinks/sink.h index 6515f1f1..b2ca4db1 100644 --- a/include/spdlog/sinks/sink.h +++ b/include/spdlog/sinks/sink.h @@ -3,8 +3,8 @@ #pragma once -#include "spdlog/details/log_msg.h" -#include "spdlog/formatter.h" +#include +#include namespace spdlog { diff --git a/include/spdlog/sinks/stdout_color_sinks-inl.h b/include/spdlog/sinks/stdout_color_sinks-inl.h index 0effb4db..653aca80 100644 --- a/include/spdlog/sinks/stdout_color_sinks-inl.h +++ b/include/spdlog/sinks/stdout_color_sinks-inl.h @@ -4,11 +4,11 @@ #pragma once #ifndef SPDLOG_HEADER_ONLY -#include "spdlog/sinks/stdout_color_sinks.h" +#include #endif -#include "spdlog/logger.h" -#include "spdlog/common.h" +#include +#include namespace spdlog { diff --git a/include/spdlog/sinks/stdout_color_sinks.h b/include/spdlog/sinks/stdout_color_sinks.h index d11ec0a1..e67aa91b 100644 --- a/include/spdlog/sinks/stdout_color_sinks.h +++ b/include/spdlog/sinks/stdout_color_sinks.h @@ -4,12 +4,12 @@ #pragma once #ifdef _WIN32 -#include "spdlog/sinks/wincolor_sink.h" +#include #else -#include "spdlog/sinks/ansicolor_sink.h" +#include #endif -#include "spdlog/details/synchronous_factory.h" +#include namespace spdlog { namespace sinks { diff --git a/include/spdlog/sinks/stdout_sinks-inl.h b/include/spdlog/sinks/stdout_sinks-inl.h index e7894987..adbcb632 100644 --- a/include/spdlog/sinks/stdout_sinks-inl.h +++ b/include/spdlog/sinks/stdout_sinks-inl.h @@ -4,11 +4,11 @@ #pragma once #ifndef SPDLOG_HEADER_ONLY -#include "spdlog/sinks/stdout_sinks.h" +#include #endif -#include "spdlog/details/console_globals.h" -#include "spdlog/details/pattern_formatter.h" +#include +#include #include namespace spdlog { diff --git a/include/spdlog/sinks/stdout_sinks.h b/include/spdlog/sinks/stdout_sinks.h index 04d2fa42..1cc47bd0 100644 --- a/include/spdlog/sinks/stdout_sinks.h +++ b/include/spdlog/sinks/stdout_sinks.h @@ -3,9 +3,9 @@ #pragma once -#include "spdlog/details/console_globals.h" -#include "spdlog/details/synchronous_factory.h" -#include "spdlog/sinks/sink.h" +#include +#include +#include #include namespace spdlog { diff --git a/include/spdlog/sinks/syslog_sink.h b/include/spdlog/sinks/syslog_sink.h index 697ba241..2f4e3fde 100644 --- a/include/spdlog/sinks/syslog_sink.h +++ b/include/spdlog/sinks/syslog_sink.h @@ -3,8 +3,8 @@ #pragma once -#include "spdlog/sinks/base_sink.h" -#include "spdlog/details/null_mutex.h" +#include +#include #include #include diff --git a/include/spdlog/sinks/systemd_sink.h b/include/spdlog/sinks/systemd_sink.h index c45a9f66..d90edb22 100644 --- a/include/spdlog/sinks/systemd_sink.h +++ b/include/spdlog/sinks/systemd_sink.h @@ -3,10 +3,14 @@ #pragma once -#include "spdlog/sinks/base_sink.h" -#include "spdlog/details/null_mutex.h" -#include "spdlog/details/synchronous_factory.h" - +#include +#include +#include + +#include +#ifndef SD_JOURNAL_SUPPRESS_LOCATION +#define SD_JOURNAL_SUPPRESS_LOCATION +#endif #include namespace spdlog { @@ -56,13 +60,14 @@ protected: if (msg.source.empty()) { // Note: function call inside '()' to avoid macro expansion - err = (sd_journal_send)( - "MESSAGE=%.*s", static_cast(length), msg.payload.data(), "PRIORITY=%d", syslog_level(msg.level), nullptr); + err = (sd_journal_send)("MESSAGE=%.*s", static_cast(length), msg.payload.data(), "PRIORITY=%d", syslog_level(msg.level), + "SYSLOG_IDENTIFIER=%.*s", static_cast(msg.logger_name.size()), msg.logger_name.data(), nullptr); } else { err = (sd_journal_send)("MESSAGE=%.*s", static_cast(length), msg.payload.data(), "PRIORITY=%d", syslog_level(msg.level), - "SOURCE_FILE=%s", msg.source.filename, "SOURCE_LINE=%d", msg.source.line, "SOURCE_FUNC=%s", msg.source.funcname, nullptr); + "SYSLOG_IDENTIFIER=%.*s", static_cast(msg.logger_name.size()), msg.logger_name.data(), "CODE_FILE=%s", + msg.source.filename, "CODE_LINE=%d", msg.source.line, "CODE_FUNC=%s", msg.source.funcname, nullptr); } if (err) diff --git a/include/spdlog/sinks/wincolor_sink-inl.h b/include/spdlog/sinks/wincolor_sink-inl.h index 72225aac..6ce9cac3 100644 --- a/include/spdlog/sinks/wincolor_sink-inl.h +++ b/include/spdlog/sinks/wincolor_sink-inl.h @@ -4,11 +4,11 @@ #pragma once #ifndef SPDLOG_HEADER_ONLY -#include "spdlog/sinks/wincolor_sink.h" +#include #endif -#include "spdlog/common.h" -#include "spdlog/details/pattern_formatter.h" +#include +#include namespace spdlog { namespace sinks { @@ -140,7 +140,7 @@ void SPDLOG_INLINE wincolor_sink::print_range_(const memory_buf_t template void SPDLOG_INLINE wincolor_sink::write_to_file_(const memory_buf_t &formatted) { - if(out_handle_ == nullptr) // no console and no file redirect + if (out_handle_ == nullptr) // no console and no file redirect { return; } diff --git a/include/spdlog/sinks/wincolor_sink.h b/include/spdlog/sinks/wincolor_sink.h index 22099e28..743db5c6 100644 --- a/include/spdlog/sinks/wincolor_sink.h +++ b/include/spdlog/sinks/wincolor_sink.h @@ -3,10 +3,10 @@ #pragma once -#include "spdlog/common.h" -#include "spdlog/details/console_globals.h" -#include "spdlog/details/null_mutex.h" -#include "spdlog/sinks/sink.h" +#include +#include +#include +#include #include #include diff --git a/include/spdlog/spdlog-inl.h b/include/spdlog/spdlog-inl.h index bbfb6e24..43aa49ef 100644 --- a/include/spdlog/spdlog-inl.h +++ b/include/spdlog/spdlog-inl.h @@ -4,11 +4,11 @@ #pragma once #ifndef SPDLOG_HEADER_ONLY -#include "spdlog/spdlog.h" +#include #endif -#include "spdlog/common.h" -#include "spdlog/details/pattern_formatter.h" +#include +#include namespace spdlog { @@ -92,9 +92,9 @@ SPDLOG_INLINE void shutdown() details::registry::instance().shutdown(); } -SPDLOG_INLINE void set_automatic_registration(bool automatic_registation) +SPDLOG_INLINE void set_automatic_registration(bool automatic_registration) { - details::registry::instance().set_automatic_registration(automatic_registation); + details::registry::instance().set_automatic_registration(automatic_registration); } SPDLOG_INLINE std::shared_ptr default_logger() diff --git a/include/spdlog/spdlog.h b/include/spdlog/spdlog.h index 3638ba12..facb0b3f 100644 --- a/include/spdlog/spdlog.h +++ b/include/spdlog/spdlog.h @@ -9,11 +9,11 @@ #pragma once -#include "spdlog/common.h" -#include "spdlog/details/registry.h" -#include "spdlog/logger.h" -#include "spdlog/version.h" -#include "spdlog/details/synchronous_factory.h" +#include +#include +#include +#include +#include #include #include @@ -100,7 +100,7 @@ void drop_all(); void shutdown(); // Automatic registration of loggers when using spdlog::create() or spdlog::create_async -void set_automatic_registration(bool automatic_registation); +void set_automatic_registration(bool automatic_registration); // API for using default logger (stdout_color_mt), // e.g: spdlog::info("Message {}", 1); @@ -285,7 +285,7 @@ inline void critical(wstring_view_t fmt, const Args &... args) // SPDLOG_LEVEL_OFF // -#define SPDLOG_LOGGER_CALL(logger, level, ...) logger->log(spdlog::source_loc{__FILE__, __LINE__, SPDLOG_FUNCTION}, level, __VA_ARGS__) +#define SPDLOG_LOGGER_CALL(logger, level, ...) (logger)->log(spdlog::source_loc{__FILE__, __LINE__, SPDLOG_FUNCTION}, level, __VA_ARGS__) #if SPDLOG_ACTIVE_LEVEL <= SPDLOG_LEVEL_TRACE #define SPDLOG_LOGGER_TRACE(logger, ...) SPDLOG_LOGGER_CALL(logger, spdlog::level::trace, __VA_ARGS__) diff --git a/include/spdlog/tweakme.h b/include/spdlog/tweakme.h index 2f3241b8..b67043e0 100644 --- a/include/spdlog/tweakme.h +++ b/include/spdlog/tweakme.h @@ -19,19 +19,6 @@ // #define SPDLOG_CLOCK_COARSE /////////////////////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////////// -// Uncomment if date/time logging is not needed and never appear in the log -// pattern. -// This will prevent spdlog from querying the clock on each log call. -// -// WARNING: If the log pattern contains any date/time while this flag is on, the -// result is undefined. -// You must set new pattern(spdlog::set_pattern(..") without any -// date/time in it -// -// #define SPDLOG_NO_DATETIME -/////////////////////////////////////////////////////////////////////////////// - /////////////////////////////////////////////////////////////////////////////// // 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. diff --git a/include/spdlog/version.h b/include/spdlog/version.h index b1b114ab..8b4fa4e5 100644 --- a/include/spdlog/version.h +++ b/include/spdlog/version.h @@ -5,6 +5,6 @@ #define SPDLOG_VER_MAJOR 1 #define SPDLOG_VER_MINOR 4 -#define SPDLOG_VER_PATCH 1 +#define SPDLOG_VER_PATCH 3 #define SPDLOG_VERSION (SPDLOG_VER_MAJOR * 10000 + SPDLOG_VER_MINOR * 100 + SPDLOG_VER_PATCH) diff --git a/meson.build b/meson.build index 5d3ac101..e3d4f94f 100644 --- a/meson.build +++ b/meson.build @@ -1,12 +1,12 @@ project('spdlog', ['cpp'], - license : 'MIT', - version : run_command(find_program('scripts/extract_version.py')).stdout().strip(), - default_options : [ + license : 'MIT', + version : run_command(find_program('scripts/extract_version.py')).stdout().strip(), + default_options : [ 'warning_level=3', 'cpp_std=c++11', 'buildtype=release', 'b_colorout=always', - ], + ], ) # ------------------------ @@ -20,17 +20,57 @@ dep_list += dependency('threads') # Check for FMT if get_option('external_fmt') - if not meson.version().version_compare('>=0.49.0') - warning('Finding fmt can fail wit meson versions before 0.49.0') - endif - dep_list += dependency('fmt') - compile_args += '-DSPDLOG_FMT_EXTERNAL' + if not meson.version().version_compare('>=0.49.0') + warning('Finding fmt can fail with meson versions before 0.49.0') + endif + dep_list += dependency('fmt') + compile_args += '-DSPDLOG_FMT_EXTERNAL' endif if get_option('no_exceptions') compile_args += '-DSPDLOG_NO_EXCEPTIONS' endif +if get_option('wchar_support') + if build_machine.system() != 'windows' + error('wchar_support only supported under windows') + endif + compile_args += '-DSPDLOG_WCHAR_TO_UTF8_SUPPORT' +endif + +if get_option('wchar_filenames') + if build_machine.system() != 'windows' + error('wchar_filenames only supported under windows') + endif + compile_args += '-DSPDLOG_WCHAR_FILENAMES' +endif + +if get_option('clock_coarse') + if build_machine.system() != 'linux' + error('clock_coarse only supported under linux') + endif + compile_args += '-DSPDLOG_CLOCK_COARSE' +endif + +if get_option('prevent_child_fd') + compile_args += '-DSPDLOG_PREVENT_CHILD_FD' +endif + +if get_option('no_thread_id') + compile_args += '-DSPDLOG_NO_THREAD_ID' +endif + +if get_option('no_tls') + compile_args += '-DSPDLOG_NO_TLS' +endif + +if get_option('no_atomic_levels') + compile_args += '-DSPDLOG_NO_ATOMIC_LEVELS' +endif + +compile_args_compiled = compile_args + ['-DSPDLOG_COMPILED_LIB'] +compile_args_ho = compile_args + # ------------------------------------ # --- Compiled library version --- # ------------------------------------ @@ -41,47 +81,49 @@ spdlog_srcs = files([ 'src/async.cpp', 'src/color_sinks.cpp', 'src/file_sinks.cpp', - 'src/fmt.cpp', 'src/spdlog.cpp', 'src/stdout_sinks.cpp' ]) +if not get_option('external_fmt') + spdlog_srcs+= 'src/fmt.cpp' +endif + if get_option('library_type') == 'static' - spdlog = static_library( + spdlog = static_library( 'spdlog', spdlog_srcs, - cpp_args : [compile_args] + ['-DSPDLOG_COMPILED_LIB'], + cpp_args : compile_args_compiled, include_directories : spdlog_inc, dependencies : dep_list, install : not meson.is_subproject() ) else - spdlog = shared_library('spdlog', + spdlog = shared_library('spdlog', spdlog_srcs, - cpp_args : [compile_args] + ['-DSPDLOG_COMPILED_LIB'], + cpp_args : compile_args_compiled, include_directories : spdlog_inc, dependencies : dep_list, install : not meson.is_subproject(), - ) + ) endif spdlog_dep = declare_dependency( - link_with : spdlog, - include_directories : spdlog_inc, - compile_args : compile_args + ['-DSPDLOG_COMPILED_LIB'], - dependencies : dep_list, - version : meson.project_version(), + link_with : spdlog, + include_directories : spdlog_inc, + compile_args : compile_args_compiled, + dependencies : dep_list, + version : meson.project_version(), ) # ---------------------------------- # --- Header only dependency --- # ---------------------------------- - spdlog_headeronly_dep = declare_dependency( - include_directories : spdlog_inc, - compile_args : compile_args, - dependencies : dep_list, - version : meson.project_version(), + include_directories : spdlog_inc, + compile_args : compile_args_ho, + dependencies : dep_list, + version : meson.project_version(), ) # ------------------------ @@ -90,31 +132,31 @@ spdlog_headeronly_dep = declare_dependency( # Do not install when spdlog is used as a subproject if not meson.is_subproject() - install_subdir('include/spdlog', install_dir: get_option('includedir')) + install_subdir('include/spdlog', install_dir: get_option('includedir')) - pkg = import('pkgconfig') - pkg.generate(spdlog, + pkg = import('pkgconfig') + pkg.generate(spdlog, name : 'spdlog', description : 'Fast C++ logging library', url : 'https://github.com/gabime/spdlog', - extra_cflags : ['-DSPDLOG_COMPILED_LIB'] - ) + extra_cflags : compile_args_compiled + ) endif # ------------------------------------- # --- Conditionally add subdirs --- # ------------------------------------- -if get_option('enable_tests') - subdir('tests') +if get_option('enable_tests') or get_option('enable_tests-ho') + subdir('tests') endif if get_option('enable_examples') - subdir('example') + subdir('example') endif if get_option('enable_benchmarks') - subdir('bench') + subdir('bench') endif # ------------------- @@ -122,7 +164,6 @@ endif # ------------------- summary_str = '''spdlog build summary: - - using external fmt: @0@ - building tests: @1@ - building examples: @2@ diff --git a/meson_options.txt b/meson_options.txt index 3eea2b8f..711c7dd6 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -1,6 +1,15 @@ -option('external_fmt', type: 'boolean', value: false, description: 'Use external fmt package instead of the bundled') -option('enable_examples', type: 'boolean', value: true, description: 'Build examples') -option('enable_benchmarks', type: 'boolean', value: false, description: 'Build benchmarks') -option('enable_tests', type: 'boolean', value: false, description: 'Build tests') +option('external_fmt', type: 'boolean', value: false, description: 'Use external fmt package instead of the bundled') +option('enable_examples', type: 'boolean', value: true, description: 'Build examples') +option('enable_benchmarks', type: 'boolean', value: false, description: 'Build benchmarks') +option('enable_tests', type: 'boolean', value: true, description: 'Build tests') +option('enable_tests_ho', type: 'boolean', value: false, description: 'Build header-only tests') option('library_type', type: 'combo', choices: ['static', 'shared'], value: 'static', description: 'Library build type') -option('no_exceptions', type: 'boolean', value: false, description: 'Disabled exceptions - abort() instead any error') +option('no_exceptions', type: 'boolean', value: false, description: 'Disabled exceptions - abort() instead any error') + +option('wchar_support', type: 'boolean', value: false, description:'(Windows only) Support wchar api') +option('wchar_filenames', type: 'boolean', value: false, description: '(Windows only) Support wchar filenames') +option('clock_coarse', type: 'boolean', value: false, description: '(Linux only) Use the much faster (but much less accurate) CLOCK_REALTIME_COARSE instead of the regular clock') +option('prevent_child_fd', type: 'boolean', value: false, description: 'Prevent from child processes to inherit log file descriptors') +option('no_thread_id', type: 'boolean', value: false, description: 'prevent spdlog from querying the thread id on each log call if thread id is not needed') +option('no_tls', type: 'boolean', value: false, description: 'prevent spdlog from using thread local storage') +option('no_atomic_levels', type: 'boolean', value: false, description: 'prevent spdlog from using of std::atomic log levels (use only if your code never modifies log levels concurrently') diff --git a/scripts/.clang-tidy b/scripts/.clang-tidy index 6c4c87c2..c3802ca0 100644 --- a/scripts/.clang-tidy +++ b/scripts/.clang-tidy @@ -1,4 +1,17 @@ -Checks: 'modernize-*,modernize-use-override,google-*,-google-runtime-references,misc-*,clang-analyzer-*,-misc-non-private-member-variables-in-classes' +Checks: '\ +cppcoreguidelines-*,\ +performance-*,\ +-performance-unnecessary-value-param,\ +modernize-*,\ +-modernize-use-trailing-return-type,\ +google-*,\ +-google-runtime-references,\ +misc-*,\ +-misc-non-private-member-variables-in-classes,\ +cert-*,\ +readability-*,\ +clang-analyzer-*' + WarningsAsErrors: '' HeaderFilterRegex: 'async.h|async_logger.h|common.h|details|formatter.h|logger.h|sinks|spdlog.h|tweakme.h|version.h' AnalyzeTemporaryDtors: false diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 1cf8f805..3184e9b6 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -14,18 +14,16 @@ set(SPDLOG_UTESTS_SOURCES test_misc.cpp test_pattern_formatter.cpp test_async.cpp - includes.h test_registry.cpp test_macros.cpp utils.cpp - utils.h main.cpp test_mpmc_q.cpp - test_sink.h + test_dup_filter.cpp test_fmt_helper.cpp test_stdout_api.cpp - test_dup_filter.cpp - test_backtrace.cpp) + test_backtrace.cpp + test_create_dir.cpp) if(NOT SPDLOG_NO_EXCEPTIONS) list(APPEND SPDLOG_UTESTS_SOURCES test_errors.cpp) @@ -35,34 +33,28 @@ if(systemd_FOUND) list(APPEND SPDLOG_UTESTS_SOURCES test_systemd.cpp) endif() -file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/logs") -enable_testing() -# The compiled library tests -if(SPDLOG_BUILD_TESTS) - add_executable(spdlog-utests ${SPDLOG_UTESTS_SOURCES}) - spdlog_enable_warnings(spdlog-utests) - target_link_libraries(spdlog-utests PRIVATE spdlog) +enable_testing() +function(spdlog_prepare_test test_target spdlog_lib) + add_executable(${test_target} ${SPDLOG_UTESTS_SOURCES}) + spdlog_enable_warnings(${test_target}) + target_link_libraries(${test_target} PRIVATE ${spdlog_lib}) if(systemd_FOUND) - target_link_libraries(spdlog-utests PRIVATE ${systemd_LIBRARIES}) + target_link_libraries(${test_target} PRIVATE ${systemd_LIBRARIES}) endif() if(SPDLOG_SANITIZE_ADDRESS) - spdlog_enable_sanitizer(spdlog-utests) + spdlog_enable_sanitizer(${test_target}) endif() - add_test(NAME spdlog-utests COMMAND spdlog-utests) + add_test(NAME ${test_target} COMMAND ${test_target}) +endfunction() + +# The compiled library tests +if(SPDLOG_BUILD_TESTS) + spdlog_prepare_test(spdlog-utests spdlog::spdlog) endif() # The header-only library version tests if(SPDLOG_BUILD_TESTS_HO) - add_executable(spdlog-utests-ho ${SPDLOG_UTESTS_SOURCES}) - spdlog_enable_warnings(spdlog-utests-ho) - target_link_libraries(spdlog-utests-ho PRIVATE spdlog::spdlog_header_only) - if(systemd_FOUND) - target_link_libraries(spdlog-utests-ho PRIVATE ${systemd_LIBRARIES}) - endif() - if(SPDLOG_SANITIZE_ADDRESS) - spdlog_set_address_sanitizer(spdlog-utests-ho) - endif() - add_test(NAME spdlog-utests-ho COMMAND spdlog-utests-ho) + spdlog_prepare_test(spdlog-utests-ho spdlog::spdlog_header_only) endif() diff --git a/tests/meson.build b/tests/meson.build index 73d7b8f8..24feb0a6 100644 --- a/tests/meson.build +++ b/tests/meson.build @@ -5,19 +5,18 @@ test_sources = files([ 'test_misc.cpp', 'test_pattern_formatter.cpp', 'test_async.cpp', - 'includes.h', 'test_registry.cpp', 'test_macros.cpp', 'utils.cpp', 'main.cpp', 'test_mpmc_q.cpp', + 'test_dup_filter.cpp', 'test_fmt_helper.cpp', 'test_stdout_api.cpp', - 'test_dup_filter.cpp', - 'test_backtrace.cpp' + 'test_backtrace.cpp', + 'test_create_dir.cpp' ]) - if not get_option('no_exceptions') test_sources += 'test_errors.cpp' endif @@ -35,19 +34,15 @@ if systemd_dep.found() global_test_deps += systemd_dep endif -run_command('mkdir', 'logs') # -------------------------------------- # --- Build the test executables --- # -------------------------------------- +if get_option('enable_tests') + test_exe = executable('spdlog-utests', test_sources, dependencies: global_test_deps + [spdlog_dep]) + test('test_spdlog', test_exe, is_parallel : false) +endif -test_matrix = [ - ['spdlog-utests', spdlog_dep], - ['spdlog-utests-ho', spdlog_headeronly_dep], -] - -foreach i : test_matrix - test_exe = executable(i[0], test_sources, dependencies: global_test_deps + [i[1]]) - test('test_' + i[0], test_exe) -endforeach - -run_command(find_program('mkdir'), meson.current_build_dir() + '/logs') \ No newline at end of file +if get_option('enable_tests_ho') + test_exe = executable('spdlog-utests-ho', test_sources, dependencies: global_test_deps + [spdlog_headeronly_dep]) + test('test_spdlog-ho', test_exe, is_parallel : false) +endif \ No newline at end of file diff --git a/tests/test_async.cpp b/tests/test_async.cpp index 6f86cf6c..166ac21e 100644 --- a/tests/test_async.cpp +++ b/tests/test_async.cpp @@ -157,7 +157,7 @@ TEST_CASE("to_file", "[async]") prepare_logdir(); size_t messages = 1024; size_t tp_threads = 1; - std::string filename = "logs/async_test.log"; + std::string filename = "test_logs/async_test.log"; { auto file_sink = std::make_shared(filename, true); auto tp = std::make_shared(messages, tp_threads); @@ -179,7 +179,7 @@ TEST_CASE("to_file multi-workers", "[async]") prepare_logdir(); size_t messages = 1024 * 10; size_t tp_threads = 10; - std::string filename = "logs/async_test.log"; + std::string filename = "test_logs/async_test.log"; { auto file_sink = std::make_shared(filename, true); auto tp = std::make_shared(messages, tp_threads); diff --git a/tests/test_create_dir.cpp b/tests/test_create_dir.cpp new file mode 100644 index 00000000..b538e80e --- /dev/null +++ b/tests/test_create_dir.cpp @@ -0,0 +1,80 @@ +/* + * This content is released under the MIT License as specified in https://raw.githubusercontent.com/gabime/spdlog/master/LICENSE + */ +#include "includes.h" + +using spdlog::details::os::create_dir; +using spdlog::details::os::path_exists; + +bool try_create_dir(const char *path, const char *normalized_path) +{ + auto rv = create_dir(path); + REQUIRE(rv == true); + return path_exists(normalized_path); +} + +TEST_CASE("create_dir", "[create_dir]") +{ + prepare_logdir(); + + REQUIRE(try_create_dir("test_logs/dir1/dir1", "test_logs/dir1/dir1")); + REQUIRE(try_create_dir("test_logs/dir1/dir1", "test_logs/dir1/dir1")); // test existing + REQUIRE(try_create_dir("test_logs/dir1///dir2//", "test_logs/dir1/dir2")); + REQUIRE(try_create_dir("./test_logs/dir1/dir3", "test_logs/dir1/dir3")); + REQUIRE(try_create_dir("test_logs/../test_logs/dir1/dir4", "test_logs/dir1/dir4")); + +#ifdef WIN32 + // test backslash folder separator + REQUIRE(try_create_dir("test_logs\\dir1\\dir222", "test_logs\\dir1\\dir222")); + REQUIRE(try_create_dir("test_logs\\dir1\\dir223\\", "test_logs\\dir1\\dir223\\")); + REQUIRE(try_create_dir(".\\test_logs\\dir1\\dir2\\dir99\\..\\dir23", "test_logs\\dir1\\dir2\\dir23")); + REQUIRE(try_create_dir("test_logs\\..\\test_logs\\dir1\\dir5", "test_logs\\dir1\\dir5")); +#endif +} + +TEST_CASE("create_invalid_dir", "[create_dir]") +{ + REQUIRE(create_dir("") == false); + REQUIRE(create_dir(spdlog::filename_t{}) == false); +#ifdef __linux__ + REQUIRE(create_dir("/proc/spdlog-utest") == false); +#endif +} + +TEST_CASE("dir_name", "[create_dir]") +{ + using spdlog::details::os::dir_name; + REQUIRE(dir_name("").empty()); + REQUIRE(dir_name("dir").empty()); + +#ifdef WIN32 + REQUIRE(dir_name(R"(dir\)") == "dir"); + REQUIRE(dir_name(R"(dir\\\)") == R"(dir\\)"); + REQUIRE(dir_name(R"(dir\file)") == "dir"); + REQUIRE(dir_name(R"(dir/file)") == "dir"); + REQUIRE(dir_name(R"(dir\file.txt)") == "dir"); + REQUIRE(dir_name(R"(dir/file)") == "dir"); + REQUIRE(dir_name(R"(dir\file.txt\)") == R"(dir\file.txt)"); + REQUIRE(dir_name(R"(dir/file.txt/)") == R"(dir\file.txt)"); + REQUIRE(dir_name(R"(\dir\file.txt)") == R"(\dir)"); + REQUIRE(dir_name(R"(/dir/file.txt)") == R"(\dir)"); + REQUIRE(dir_name(R"(\\dir\file.txt)") == R"(\\dir)"); + REQUIRE(dir_name(R"(//dir/file.txt)") == R"(\\dir)"); + REQUIRE(dir_name(R"(..\file.txt)") == ".."); + REQUIRE(dir_name(R"(../file.txt)") == ".."); + REQUIRE(dir_name(R"(.\file.txt)") == "."); + REQUIRE(dir_name(R"(./file.txt)") == "."); + REQUIRE(dir_name(R"(c:\\a\b\c\d\file.txt)") == R"(c:\\a\b\c\d)"); + REQUIRE(dir_name(R"(c://a/b/c/d/file.txt)") == R"(c:\\a\b\c\d)"); +#else + REQUIRE(dir_name("dir/") == "dir"); + REQUIRE(dir_name("dir///") == "dir//"); + REQUIRE(dir_name("dir/file") == "dir"); + REQUIRE(dir_name("dir/file.txt") == "dir"); + REQUIRE(dir_name("dir/file.txt/") == "dir/file.txt"); + REQUIRE(dir_name("/dir/file.txt") == "/dir"); + REQUIRE(dir_name("//dir/file.txt") == "//dir"); + REQUIRE(dir_name("../file.txt") == ".."); + REQUIRE(dir_name("./file.txt") == "."); +#endif +} diff --git a/tests/test_daily_logger.cpp b/tests/test_daily_logger.cpp index c89ef171..cf2002a3 100644 --- a/tests/test_daily_logger.cpp +++ b/tests/test_daily_logger.cpp @@ -10,7 +10,7 @@ TEST_CASE("daily_logger with dateonly calculator", "[daily_logger]") prepare_logdir(); // calculate filename (time based) - std::string basename = "logs/daily_dateonly"; + std::string basename = "test_logs/daily_dateonly"; std::tm tm = spdlog::details::os::localtime(); spdlog::memory_buf_t w; fmt::format_to(w, "{}_{:04d}-{:02d}-{:02d}", basename, tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday); @@ -44,7 +44,7 @@ TEST_CASE("daily_logger with custom calculator", "[daily_logger]") prepare_logdir(); // calculate filename (time based) - std::string basename = "logs/daily_dateonly"; + std::string basename = "test_logs/daily_dateonly"; std::tm tm = spdlog::details::os::localtime(); spdlog::memory_buf_t w; fmt::format_to(w, "{}{:04d}{:02d}{:02d}", basename, tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday); @@ -119,7 +119,7 @@ static void test_rotate(int days_to_run, uint16_t max_days, uint16_t expected_n_ prepare_logdir(); - std::string basename = "logs/daily_rotate.txt"; + std::string basename = "test_logs/daily_rotate.txt"; daily_file_sink_st sink{basename, 2, 30, true, max_days}; // simulate messages with 24 intervals @@ -130,7 +130,7 @@ static void test_rotate(int days_to_run, uint16_t max_days, uint16_t expected_n_ sink.log(create_msg(offset)); } - REQUIRE(count_files("logs") == static_cast(expected_n_files)); + REQUIRE(count_files("test_logs") == static_cast(expected_n_files)); } TEST_CASE("daily_logger rotate", "[daily_file_sink]") diff --git a/tests/test_errors.cpp b/tests/test_errors.cpp index 65185d3c..4fc40594 100644 --- a/tests/test_errors.cpp +++ b/tests/test_errors.cpp @@ -26,7 +26,7 @@ protected: TEST_CASE("default_error_handler", "[errors]]") { prepare_logdir(); - std::string filename = "logs/simple_log.txt"; + std::string filename = "test_logs/simple_log.txt"; auto logger = spdlog::create("test-error", filename, true); logger->set_pattern("%v"); @@ -43,7 +43,7 @@ struct custom_ex TEST_CASE("custom_error_handler", "[errors]]") { prepare_logdir(); - std::string filename = "logs/simple_log.txt"; + std::string filename = "test_logs/simple_log.txt"; auto logger = spdlog::create("logger", filename, true); logger->flush_on(spdlog::level::info); logger->set_error_handler([=](const std::string &) { throw custom_ex(); }); @@ -75,15 +75,15 @@ TEST_CASE("async_error_handler", "[errors]]") prepare_logdir(); std::string err_msg("log failed with some msg"); - std::string filename = "logs/simple_async_log.txt"; + std::string filename = "test_logs/simple_async_log.txt"; { spdlog::init_thread_pool(128, 1); auto logger = spdlog::create_async("logger", filename, true); logger->set_error_handler([=](const std::string &) { - std::ofstream ofs("logs/custom_err.txt"); + std::ofstream ofs("test_logs/custom_err.txt"); if (!ofs) { - throw std::runtime_error("Failed open logs/custom_err.txt"); + throw std::runtime_error("Failed open test_logs/custom_err.txt"); } ofs << err_msg; }); @@ -94,7 +94,7 @@ TEST_CASE("async_error_handler", "[errors]]") } spdlog::init_thread_pool(128, 1); REQUIRE(count_lines(filename) == 2); - REQUIRE(file_contents("logs/custom_err.txt") == err_msg); + REQUIRE(file_contents("test_logs/custom_err.txt") == err_msg); } // Make sure async error handler is executed @@ -103,12 +103,13 @@ TEST_CASE("async_error_handler2", "[errors]]") prepare_logdir(); std::string err_msg("This is async handler error message"); { + spdlog::details::os::create_dir("test_logs"); spdlog::init_thread_pool(128, 1); auto logger = spdlog::create_async("failed_logger"); logger->set_error_handler([=](const std::string &) { - std::ofstream ofs("logs/custom_err2.txt"); + std::ofstream ofs("test_logs/custom_err2.txt"); if (!ofs) - throw std::runtime_error("Failed open logs/custom_err2.txt"); + throw std::runtime_error("Failed open test_logs/custom_err2.txt"); ofs << err_msg; }); logger->info("Hello failure"); @@ -116,5 +117,5 @@ TEST_CASE("async_error_handler2", "[errors]]") } spdlog::init_thread_pool(128, 1); - REQUIRE(file_contents("logs/custom_err2.txt") == err_msg); + REQUIRE(file_contents("test_logs/custom_err2.txt") == err_msg); } diff --git a/tests/test_file_helper.cpp b/tests/test_file_helper.cpp index 74e3744e..3a3545fe 100644 --- a/tests/test_file_helper.cpp +++ b/tests/test_file_helper.cpp @@ -6,7 +6,7 @@ using spdlog::details::file_helper; using spdlog::details::log_msg; -static const std::string target_filename = "logs/file_helper_test.txt"; +static const std::string target_filename = "test_logs/file_helper_test.txt"; static void write_with_helper(file_helper &helper, size_t howmany) { @@ -38,15 +38,6 @@ TEST_CASE("file_helper_size", "[file_helper::size()]]") REQUIRE(get_filesize(target_filename) == expected_size); } -TEST_CASE("file_helper_exists", "[file_helper::file_exists()]]") -{ - prepare_logdir(); - REQUIRE(!file_helper::file_exists(target_filename)); - file_helper helper; - helper.open(target_filename); - REQUIRE(file_helper::file_exists(target_filename)); -} - TEST_CASE("file_helper_reopen", "[file_helper::reopen()]]") { prepare_logdir(); diff --git a/tests/test_file_logging.cpp b/tests/test_file_logging.cpp index 7563cf65..a8f9b2bb 100644 --- a/tests/test_file_logging.cpp +++ b/tests/test_file_logging.cpp @@ -6,7 +6,7 @@ TEST_CASE("simple_file_logger", "[simple_logger]]") { prepare_logdir(); - std::string filename = "logs/simple_log"; + std::string filename = "test_logs/simple_log"; auto logger = spdlog::create("logger", filename); logger->set_pattern("%v"); @@ -22,7 +22,7 @@ TEST_CASE("simple_file_logger", "[simple_logger]]") TEST_CASE("flush_on", "[flush_on]]") { prepare_logdir(); - std::string filename = "logs/simple_log"; + std::string filename = "test_logs/simple_log"; auto logger = spdlog::create("logger", filename); logger->set_pattern("%v"); @@ -42,7 +42,7 @@ TEST_CASE("rotating_file_logger1", "[rotating_logger]]") { prepare_logdir(); size_t max_size = 1024 * 10; - std::string basename = "logs/rotating_log"; + std::string basename = "test_logs/rotating_log"; auto logger = spdlog::rotating_logger_mt("logger", basename, max_size, 0); for (int i = 0; i < 10; ++i) @@ -59,7 +59,7 @@ TEST_CASE("rotating_file_logger2", "[rotating_logger]]") { prepare_logdir(); size_t max_size = 1024 * 10; - std::string basename = "logs/rotating_log"; + std::string basename = "test_logs/rotating_log"; { // make an initial logger to create the first output file diff --git a/tests/test_macros.cpp b/tests/test_macros.cpp index 22a5ccbf..4c621bb3 100644 --- a/tests/test_macros.cpp +++ b/tests/test_macros.cpp @@ -12,7 +12,7 @@ TEST_CASE("debug and trace w/o format string", "[macros]]") { prepare_logdir(); - std::string filename = "logs/simple_log"; + std::string filename = "test_logs/simple_log"; auto logger = spdlog::create("logger", filename); logger->set_pattern("%v"); @@ -39,3 +39,21 @@ TEST_CASE("disable param evaluation", "[macros]") { SPDLOG_TRACE("Test message {}", throw std::runtime_error("Should not be evaluated")); } + +TEST_CASE("pass logger pointer", "[macros]") +{ + auto logger = spdlog::create("refmacro"); + auto &ref = *logger; + SPDLOG_LOGGER_TRACE(&ref, "Test message 1"); + SPDLOG_LOGGER_DEBUG(&ref, "Test message 2"); +} + +// ensure that even if right macro level is on- don't evaluate if the logger's level is not high enough +// TEST_CASE("disable param evaluation2", "[macros]") +//{ +// auto logger = std::make_shared("test-macro"); +// logger->set_level(spdlog::level::off); +// int x = 0; +// SPDLOG_LOGGER_DEBUG(logger, "Test message {}", ++x); +// REQUIRE(x == 0); +//} diff --git a/tests/test_pattern_formatter.cpp b/tests/test_pattern_formatter.cpp index 9bf8d4b1..6aff454c 100644 --- a/tests/test_pattern_formatter.cpp +++ b/tests/test_pattern_formatter.cpp @@ -1,4 +1,5 @@ #include "includes.h" +#include "test_sink.h" using spdlog::memory_buf_t; @@ -138,58 +139,111 @@ TEST_CASE("color range test6", "[pattern_formatter]") TEST_CASE("level_left_padded", "[pattern_formatter]") { REQUIRE(log_to_str("Some message", "[%8l] %v", spdlog::pattern_time_type::local, "\n") == "[ info] Some message\n"); + REQUIRE(log_to_str("Some message", "[%8!l] %v", spdlog::pattern_time_type::local, "\n") == "[ info] Some message\n"); } TEST_CASE("level_right_padded", "[pattern_formatter]") { REQUIRE(log_to_str("Some message", "[%-8l] %v", spdlog::pattern_time_type::local, "\n") == "[info ] Some message\n"); + REQUIRE(log_to_str("Some message", "[%-8!l] %v", spdlog::pattern_time_type::local, "\n") == "[info ] Some message\n"); } TEST_CASE("level_center_padded", "[pattern_formatter]") { REQUIRE(log_to_str("Some message", "[%=8l] %v", spdlog::pattern_time_type::local, "\n") == "[ info ] Some message\n"); + REQUIRE(log_to_str("Some message", "[%=8!l] %v", spdlog::pattern_time_type::local, "\n") == "[ info ] Some message\n"); } TEST_CASE("short level_left_padded", "[pattern_formatter]") { REQUIRE(log_to_str("Some message", "[%3L] %v", spdlog::pattern_time_type::local, "\n") == "[ I] Some message\n"); + REQUIRE(log_to_str("Some message", "[%3!L] %v", spdlog::pattern_time_type::local, "\n") == "[ I] Some message\n"); } TEST_CASE("short level_right_padded", "[pattern_formatter]") { REQUIRE(log_to_str("Some message", "[%-3L] %v", spdlog::pattern_time_type::local, "\n") == "[I ] Some message\n"); + REQUIRE(log_to_str("Some message", "[%-3!L] %v", spdlog::pattern_time_type::local, "\n") == "[I ] Some message\n"); } TEST_CASE("short level_center_padded", "[pattern_formatter]") { REQUIRE(log_to_str("Some message", "[%=3L] %v", spdlog::pattern_time_type::local, "\n") == "[ I ] Some message\n"); + REQUIRE(log_to_str("Some message", "[%=3!L] %v", spdlog::pattern_time_type::local, "\n") == "[ I ] Some message\n"); } TEST_CASE("left_padded_short", "[pattern_formatter]") { REQUIRE(log_to_str("Some message", "[%3n] %v", spdlog::pattern_time_type::local, "\n") == "[pattern_tester] Some message\n"); + REQUIRE(log_to_str("Some message", "[%3!n] %v", spdlog::pattern_time_type::local, "\n") == "[pat] Some message\n"); } TEST_CASE("right_padded_short", "[pattern_formatter]") { REQUIRE(log_to_str("Some message", "[%-3n] %v", spdlog::pattern_time_type::local, "\n") == "[pattern_tester] Some message\n"); + REQUIRE(log_to_str("Some message", "[%-3!n] %v", spdlog::pattern_time_type::local, "\n") == "[pat] Some message\n"); } TEST_CASE("center_padded_short", "[pattern_formatter]") { REQUIRE(log_to_str("Some message", "[%=3n] %v", spdlog::pattern_time_type::local, "\n") == "[pattern_tester] Some message\n"); + REQUIRE(log_to_str("Some message", "[%=3!n] %v", spdlog::pattern_time_type::local, "\n") == "[pat] Some message\n"); } TEST_CASE("left_padded_huge", "[pattern_formatter]") { REQUIRE(log_to_str("Some message", "[%-300n] %v", spdlog::pattern_time_type::local, "\n") == - "[pattern_tester ] Some message\n"); + "[pattern_tester ] Some message\n"); + + REQUIRE(log_to_str("Some message", "[%-300!n] %v", spdlog::pattern_time_type::local, "\n") == + "[pattern_tester ] Some message\n"); } TEST_CASE("left_padded_max", "[pattern_formatter]") { REQUIRE(log_to_str("Some message", "[%-64n] %v", spdlog::pattern_time_type::local, "\n") == - "[pattern_tester ] Some message\n"); + "[pattern_tester ] Some message\n"); + + REQUIRE(log_to_str("Some message", "[%-64!n] %v", spdlog::pattern_time_type::local, "\n") == + "[pattern_tester ] Some message\n"); +} + +// Test padding + truncate flag + +TEST_CASE("paddinng_truncate", "[pattern_formatter]") +{ + REQUIRE(log_to_str("123456", "%6!v", spdlog::pattern_time_type::local, "\n") == "123456\n"); + REQUIRE(log_to_str("123456", "%5!v", spdlog::pattern_time_type::local, "\n") == "12345\n"); + REQUIRE(log_to_str("123456", "%7!v", spdlog::pattern_time_type::local, "\n") == " 123456\n"); + + REQUIRE(log_to_str("123456", "%-6!v", spdlog::pattern_time_type::local, "\n") == "123456\n"); + REQUIRE(log_to_str("123456", "%-5!v", spdlog::pattern_time_type::local, "\n") == "12345\n"); + REQUIRE(log_to_str("123456", "%-7!v", spdlog::pattern_time_type::local, "\n") == "123456 \n"); + + REQUIRE(log_to_str("123456", "%=6!v", spdlog::pattern_time_type::local, "\n") == "123456\n"); + REQUIRE(log_to_str("123456", "%=5!v", spdlog::pattern_time_type::local, "\n") == "12345\n"); + REQUIRE(log_to_str("123456", "%=7!v", spdlog::pattern_time_type::local, "\n") == "123456 \n"); + + REQUIRE(log_to_str("123456", "%0!v", spdlog::pattern_time_type::local, "\n") == "\n"); +} + +TEST_CASE("paddinng_truncate_funcname", "[pattern_formatter]") +{ + spdlog::sinks::test_sink_st test_sink; + + const char* pattern = "%v [%5!!]"; + auto formatter = std::unique_ptr(new spdlog::pattern_formatter(pattern)); + test_sink.set_formatter(std::move(formatter)); + + spdlog::details::log_msg msg1{spdlog::source_loc{"ignored", 1, "func"}, "test_logger", spdlog::level::info, "message"}; + test_sink.log(msg1); + + spdlog::details::log_msg msg2{spdlog::source_loc{"ignored", 1, "function"}, "test_logger", spdlog::level::info, "message"}; + test_sink.log(msg2); + + auto lines = test_sink.lines(); + REQUIRE(lines[0] == "message [ func]"); + REQUIRE(lines[1] == "message [funct]"); } TEST_CASE("clone-default-formatter", "[pattern_formatter]") diff --git a/tests/test_registry.cpp b/tests/test_registry.cpp index 6a4639af..0f92b069 100644 --- a/tests/test_registry.cpp +++ b/tests/test_registry.cpp @@ -9,7 +9,7 @@ TEST_CASE("register_drop", "[registry]") spdlog::drop_all(); spdlog::create(tested_logger_name); REQUIRE(spdlog::get(tested_logger_name) != nullptr); - // Throw if registring existing name + // Throw if registering existing name REQUIRE_THROWS_AS(spdlog::create(tested_logger_name), spdlog::spdlog_ex); } @@ -19,7 +19,7 @@ TEST_CASE("explicit register", "[registry]") auto logger = std::make_shared(tested_logger_name, std::make_shared()); spdlog::register_logger(logger); REQUIRE(spdlog::get(tested_logger_name) != nullptr); - // Throw if registring existing name + // Throw if registering existing name REQUIRE_THROWS_AS(spdlog::create(tested_logger_name), spdlog::spdlog_ex); } #endif diff --git a/tests/utils.cpp b/tests/utils.cpp index 6c7f3662..255a4fec 100644 --- a/tests/utils.cpp +++ b/tests/utils.cpp @@ -9,18 +9,12 @@ void prepare_logdir() { spdlog::drop_all(); #ifdef _WIN32 - system("if not exist logs mkdir logs"); - system("del /F /Q logs\\*"); + system("rmdir /S /Q test_logs"); #else - auto rv = system("mkdir -p logs"); + auto rv = system("rm -rf test_logs"); if (rv != 0) { - throw std::runtime_error("Failed to mkdir -p logs"); - } - rv = system("rm -f logs/*"); - if (rv != 0) - { - throw std::runtime_error("Failed to rm -f logs/*"); + throw std::runtime_error("Failed to rm -rf test_logs"); } #endif }