Merged v1.x from upstream

pull/1322/head
Stefano Caiazza 6 years ago
commit f6a5bdde65

@ -63,31 +63,39 @@ option(SPDLOG_SANITIZE_ADDRESS "Enable address sanitizer in tests" OFF)
# install options # install options
option(SPDLOG_INSTALL "Generate the install target" ${SPDLOG_MASTER_PROJECT}) option(SPDLOG_INSTALL "Generate the install target" ${SPDLOG_MASTER_PROJECT})
option(SPDLOG_FMT_EXTERNAL "Use external fmt library instead of bundled" OFF) 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) if(WIN32)
option(SPDLOG_WCHAR_SUPPORT "Support wchar api" OFF) option(SPDLOG_WCHAR_SUPPORT "Support wchar api" OFF)
option(SPDLOG_WCHAR_FILENAMES "Support wchar filenames" OFF) option(SPDLOG_WCHAR_FILENAMES "Support wchar filenames" OFF)
endif() 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) find_package(Threads REQUIRED)
message(STATUS "Build type: " ${CMAKE_BUILD_TYPE}) message(STATUS "Build type: " ${CMAKE_BUILD_TYPE})
#--------------------------------------------------------------------------------------- #---------------------------------------------------------------------------------------
# Static/Shared library (shared not supported in windows yet) # Static/Shared library (shared not supported in windows yet)
#--------------------------------------------------------------------------------------- #---------------------------------------------------------------------------------------
set(SPDLOG_SRCS set(SPDLOG_SRCS
src/spdlog.cpp src/spdlog.cpp
src/stdout_sinks.cpp src/stdout_sinks.cpp
src/fmt.cpp
src/color_sinks.cpp src/color_sinks.cpp
src/file_sinks.cpp src/file_sinks.cpp
src/async.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 (SPDLOG_BUILD_SHARED)
if(WIN32) 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(SPDLOG_FMT_EXTERNAL)
if (NOT TARGET fmt::fmt) if (NOT TARGET fmt::fmt)
find_package(fmt REQUIRED) find_package(fmt REQUIRED)
endif () endif ()
set(SPDLOG_CFLAGS "${SPDLOG_CFLAGS} -DSPDLOG_FMT_EXTERNAL")
target_compile_definitions(spdlog PUBLIC SPDLOG_FMT_EXTERNAL) target_compile_definitions(spdlog PUBLIC SPDLOG_FMT_EXTERNAL)
target_link_libraries(spdlog PUBLIC fmt::fmt) target_link_libraries(spdlog PUBLIC fmt::fmt)
target_compile_definitions(spdlog_header_only INTERFACE SPDLOG_FMT_EXTERNAL) target_compile_definitions(spdlog_header_only INTERFACE SPDLOG_FMT_EXTERNAL)
target_link_libraries(spdlog_header_only INTERFACE fmt::fmt) target_link_libraries(spdlog_header_only INTERFACE fmt::fmt)
set(PKG_CONFIG_REQUIRES fmt) # add dependency to pkg-config
endif() endif()
#---------------------------------------------------------------------------------------
# Misc definitions according to tweak options
#---------------------------------------------------------------------------------------
if(SPDLOG_WCHAR_SUPPORT) if(SPDLOG_WCHAR_SUPPORT)
target_compile_definitions(spdlog PUBLIC SPDLOG_WCHAR_TO_UTF8_SUPPORT) target_compile_definitions(spdlog PUBLIC SPDLOG_WCHAR_TO_UTF8_SUPPORT)
target_compile_definitions(spdlog_header_only INTERFACE 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()
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 # Build binaries
@ -188,7 +223,7 @@ if (SPDLOG_INSTALL)
set(project_config_out "${CMAKE_CURRENT_BINARY_DIR}/spdlogConfig.cmake") set(project_config_out "${CMAKE_CURRENT_BINARY_DIR}/spdlogConfig.cmake")
set(config_targets_file "spdlogConfigTargets.cmake") set(config_targets_file "spdlogConfigTargets.cmake")
set(version_config_file "${CMAKE_CURRENT_BINARY_DIR}/spdlogConfigVersion.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(pkgconfig_install_dir "${CMAKE_INSTALL_LIBDIR}/pkgconfig")
set(pkg_config "${CMAKE_BINARY_DIR}/${PROJECT_NAME}.pc") set(pkg_config "${CMAKE_BINARY_DIR}/${PROJECT_NAME}.pc")
@ -204,11 +239,17 @@ if (SPDLOG_INSTALL)
endif() 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) configure_file("cmake/${PROJECT_NAME}.pc.in" "${pkg_config}" @ONLY)
install(FILES "${pkg_config}" DESTINATION "${pkgconfig_install_dir}") install(FILES "${pkg_config}" DESTINATION "${pkgconfig_install_dir}")
#---------------------------------------------------------------------------------------
# Install CMake config files
#---------------------------------------------------------------------------------------
install(EXPORT spdlog install(EXPORT spdlog
DESTINATION ${export_dest_dir} DESTINATION ${export_dest_dir}
NAMESPACE spdlog:: NAMESPACE spdlog::
@ -216,6 +257,7 @@ if (SPDLOG_INSTALL)
include(CMakePackageConfigHelpers) include(CMakePackageConfigHelpers)
configure_file("${project_config_in}" "${project_config_out}" @ONLY) configure_file("${project_config_in}" "${project_config_out}" @ONLY)
write_basic_package_version_file("${version_config_file}" COMPATIBILITY SameMajorVersion) write_basic_package_version_file("${version_config_file}" COMPATIBILITY SameMajorVersion)
install(FILES install(FILES
"${project_config_out}" "${project_config_out}"
@ -227,3 +269,4 @@ if (SPDLOG_INSTALL)
include(cmake/spdlogCPack.cmake) include(cmake/spdlogCPack.cmake)
endif () endif ()

@ -30,6 +30,8 @@ $ cmake .. && make -j
* Gentoo: `emerge dev-libs/spdlog` * Gentoo: `emerge dev-libs/spdlog`
* Arch Linux: `yaourt -S spdlog-git` * Arch Linux: `yaourt -S spdlog-git`
* vcpkg: `vcpkg install spdlog` * vcpkg: `vcpkg install spdlog`
* conan: `spdlog/[>=1.4.1]@bincrafters/stable`
## Features ## Features
* Very fast (see [benchmarks](#benchmarks) below). * Very fast (see [benchmarks](#benchmarks) below).

@ -24,5 +24,3 @@ target_link_libraries(latency PRIVATE benchmark::benchmark spdlog::spdlog)
add_executable(formatter-bench formatter-bench.cpp) add_executable(formatter-bench formatter-bench.cpp)
target_link_libraries(formatter-bench PRIVATE benchmark::benchmark spdlog::spdlog) target_link_libraries(formatter-bench PRIVATE benchmark::benchmark spdlog::spdlog)
file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/logs")

@ -16,26 +16,6 @@
#include "spdlog/sinks/null_sink.h" #include "spdlog/sinks/null_sink.h"
#include "spdlog/sinks/rotating_file_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<spdlog::logger> logger) void bench_c_string(benchmark::State &state, std::shared_ptr<spdlog::logger> logger)
{ {
const char *msg = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum pharetra metus cursus " 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; size_t rotating_files = 5;
int n_threads = benchmark::CPUInfo::Get().num_cpus; int n_threads = benchmark::CPUInfo::Get().num_cpus;
prepare_logdir();
// disabled loggers // disabled loggers
auto disabled_logger = std::make_shared<spdlog::logger>("bench", std::make_shared<null_sink_mt>()); auto disabled_logger = std::make_shared<spdlog::logger>("bench", std::make_shared<null_sink_mt>());
disabled_logger->set_level(spdlog::level::off); disabled_logger->set_level(spdlog::level::off);

@ -12,4 +12,3 @@ foreach i : bench_matrix
benchmark('bench_' + i[0], bench_exe, args: i[2]) benchmark('bench_' + i[0], bench_exe, args: i[2])
endforeach endforeach
run_command(find_program('mkdir'), meson.current_build_dir() + '/logs')

@ -7,5 +7,7 @@ Name: lib@PROJECT_NAME@
Description: Fast C++ logging library. Description: Fast C++ logging library.
URL: https://github.com/gabime/@PROJECT_NAME@ URL: https://github.com/gabime/@PROJECT_NAME@
Version: @SPDLOG_VERSION@ Version: @SPDLOG_VERSION@
CFlags: -I${includedir}/@SPDLOG_CFLAGS@ CFlags: -I${includedir} @PKG_CONFIG_DEFINES@
Libs: -L${libdir}/@PROJECT_NAME@ -l@PROJECT_NAME@ Libs: -L${libdir} -lspdlog -pthread
Requires: @PKG_CONFIG_REQUIRES@

@ -25,5 +25,3 @@ if(SPDLOG_BUILD_EXAMPLE_HO)
target_link_libraries(example_header_only PRIVATE spdlog::spdlog_header_only) target_link_libraries(example_header_only PRIVATE spdlog::spdlog_header_only)
endif() endif()
# Create logs directory
file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/logs")

@ -143,7 +143,7 @@ void async_example()
#include "spdlog/fmt/bin_to_hex.h" #include "spdlog/fmt/bin_to_hex.h"
void binary_example() void binary_example()
{ {
std::vector<char> buf; std::vector<char> buf(80);
for (int i = 0; i < 80; i++) for (int i = 0; i < 80; i++)
{ {
buf.push_back(static_cast<char>(i & 0xff)); buf.push_back(static_cast<char>(i & 0xff));

@ -1,5 +1,4 @@
executable('example', 'example.cpp', dependencies: spdlog_dep) executable('example', 'example.cpp', dependencies: spdlog_dep)
executable('example_header_only', 'example.cpp', dependencies: spdlog_headeronly_dep) executable('example_header_only', 'example.cpp', dependencies: spdlog_headeronly_dep)
run_command(find_program('mkdir'), meson.current_build_dir() + '/logs')

@ -6,7 +6,7 @@
// //
// Async logging using global thread pool // Async logging using global thread pool
// All loggers created here share same 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. // logger.
// If a logger deleted while having pending messages in the queue, it's actual // If a logger deleted while having pending messages in the queue, it's actual
// destruction will defer // destruction will defer
@ -14,9 +14,9 @@
// This is because each message in the queue holds a shared_ptr to the // This is because each message in the queue holds a shared_ptr to the
// originating logger. // originating logger.
#include "spdlog/async_logger.h" #include <spdlog/async_logger.h>
#include "spdlog/details/registry.h" #include <spdlog/details/registry.h>
#include "spdlog/details/thread_pool.h" #include <spdlog/details/thread_pool.h>
#include <memory> #include <memory>
#include <mutex> #include <mutex>

@ -4,11 +4,11 @@
#pragma once #pragma once
#ifndef SPDLOG_HEADER_ONLY #ifndef SPDLOG_HEADER_ONLY
#include "spdlog/async_logger.h" #include <spdlog/async_logger.h>
#endif #endif
#include "spdlog/sinks/sink.h" #include <spdlog/sinks/sink.h>
#include "spdlog/details/thread_pool.h" #include <spdlog/details/thread_pool.h>
#include <memory> #include <memory>
#include <string> #include <string>

@ -14,7 +14,7 @@
// Upon destruction, logs all remaining messages in the queue before // Upon destruction, logs all remaining messages in the queue before
// destructing.. // destructing..
#include "spdlog/logger.h" #include <spdlog/logger.h>
namespace spdlog { namespace spdlog {

@ -4,7 +4,7 @@
#pragma once #pragma once
#ifndef SPDLOG_HEADER_ONLY #ifndef SPDLOG_HEADER_ONLY
#include "spdlog/common.h" #include <spdlog/common.h>
#endif #endif
namespace spdlog { namespace spdlog {

@ -3,8 +3,8 @@
#pragma once #pragma once
#include "spdlog/tweakme.h" #include <spdlog/tweakme.h>
#include "spdlog/details/null_mutex.h" #include <spdlog/details/null_mutex.h>
#include <atomic> #include <atomic>
#include <chrono> #include <chrono>
@ -35,7 +35,7 @@
#define SPDLOG_INLINE inline #define SPDLOG_INLINE inline
#endif #endif
#include "spdlog/fmt/fmt.h" #include <spdlog/fmt/fmt.h>
// visual studio upto 2013 does not support noexcept nor constexpr // visual studio upto 2013 does not support noexcept nor constexpr
#if defined(_MSC_VER) && (_MSC_VER < 1900) #if defined(_MSC_VER) && (_MSC_VER < 1900)
@ -62,7 +62,7 @@
#endif #endif
#ifndef SPDLOG_FUNCTION #ifndef SPDLOG_FUNCTION
#define SPDLOG_FUNCTION __FUNCTION__ #define SPDLOG_FUNCTION static_cast<const char *>(__FUNCTION__)
#endif #endif
#ifdef SPDLOG_NO_EXCEPTIONS #ifdef SPDLOG_NO_EXCEPTIONS

@ -4,7 +4,7 @@
#pragma once #pragma once
#ifndef SPDLOG_HEADER_ONLY #ifndef SPDLOG_HEADER_ONLY
#include "spdlog/details/backtracer.h" #include <spdlog/details/backtracer.h>
#endif #endif
namespace spdlog { namespace spdlog {
namespace details { namespace details {
@ -26,7 +26,7 @@ SPDLOG_INLINE backtracer &backtracer::operator=(backtracer other)
{ {
std::lock_guard<std::mutex> lock(mutex_); std::lock_guard<std::mutex> lock(mutex_);
enabled_ = other.enabled(); enabled_ = other.enabled();
messages_ = other.messages_; messages_ = std::move(other.messages_);
return *this; return *this;
} }
@ -48,11 +48,6 @@ SPDLOG_INLINE bool backtracer::enabled() const
return enabled_.load(std::memory_order_relaxed); 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) SPDLOG_INLINE void backtracer::push_back(const log_msg &msg)
{ {
std::lock_guard<std::mutex> lock{mutex_}; std::lock_guard<std::mutex> lock{mutex_};

@ -3,8 +3,8 @@
#pragma once #pragma once
#include "spdlog/details/log_msg_buffer.h" #include <spdlog/details/log_msg_buffer.h>
#include "spdlog/details/circular_q.h" #include <spdlog/details/circular_q.h>
#include <atomic> #include <atomic>
#include <mutex> #include <mutex>
@ -31,7 +31,6 @@ public:
void enable(size_t size); void enable(size_t size);
void disable(); void disable();
bool enabled() const; bool enabled() const;
explicit operator bool() const;
void push_back(const log_msg &msg); void push_back(const log_msg &msg);
// pop all items in the q and apply the given fun on each of them. // pop all items in the q and apply the given fun on each of them.

@ -1,7 +1,7 @@
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. // Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
// Distributed under the MIT License (http://opensource.org/licenses/MIT) // Distributed under the MIT License (http://opensource.org/licenses/MIT)
// cirucal q view of std::vector. // circular q view of std::vector.
#pragma once #pragma once
#include <vector> #include <vector>
@ -72,6 +72,27 @@ public:
return v_[head_]; 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. // Pop item from front.
// If there are no elements in the container, the behavior is undefined. // If there are no elements in the container, the behavior is undefined.
void pop_front() void pop_front()

@ -3,7 +3,7 @@
#pragma once #pragma once
#include "spdlog/details/null_mutex.h" #include <spdlog/details/null_mutex.h>
#include <mutex> #include <mutex>
namespace spdlog { namespace spdlog {

@ -4,11 +4,11 @@
#pragma once #pragma once
#ifndef SPDLOG_HEADER_ONLY #ifndef SPDLOG_HEADER_ONLY
#include "spdlog/details/file_helper.h" #include <spdlog/details/file_helper.h>
#endif #endif
#include "spdlog/details/os.h" #include <spdlog/details/os.h>
#include "spdlog/common.h" #include <spdlog/common.h>
#include <cerrno> #include <cerrno>
#include <chrono> #include <chrono>
@ -28,28 +28,31 @@ SPDLOG_INLINE file_helper::~file_helper()
SPDLOG_INLINE void file_helper::open(const filename_t &fname, bool truncate) SPDLOG_INLINE void file_helper::open(const filename_t &fname, bool truncate)
{ {
close(); close();
filename_ = fname;
auto *mode = truncate ? SPDLOG_FILENAME_T("wb") : SPDLOG_FILENAME_T("ab"); 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)) if (!os::fopen_s(&fd_, fname, mode))
{ {
return; 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) 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")); 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() 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(); auto data = buf.data();
if (std::fwrite(data, 1, msg_size, fd_) != msg_size) 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) 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_); return os::filesize(fd_);
} }
SPDLOG_INLINE const filename_t &file_helper::filename() const SPDLOG_INLINE const filename_t &file_helper::filename() const
{ {
return _filename; return filename_;
}
SPDLOG_INLINE bool file_helper::file_exists(const filename_t &fname)
{
return os::file_exists(fname);
} }
// //
@ -119,7 +117,7 @@ SPDLOG_INLINE std::tuple<filename_t, filename_t> file_helper::split_by_extension
return std::make_tuple(fname, filename_t()); 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); auto folder_index = fname.rfind(details::os::folder_sep);
if (folder_index != filename_t::npos && folder_index >= ext_index - 1) if (folder_index != filename_t::npos && folder_index >= ext_index - 1)
{ {
@ -129,5 +127,6 @@ SPDLOG_INLINE std::tuple<filename_t, filename_t> file_helper::split_by_extension
// finally - return a valid base and extension tuple // finally - return a valid base and extension tuple
return std::make_tuple(fname.substr(0, ext_index), fname.substr(ext_index)); return std::make_tuple(fname.substr(0, ext_index), fname.substr(ext_index));
} }
} // namespace details } // namespace details
} // namespace spdlog } // namespace spdlog

@ -3,7 +3,7 @@
#pragma once #pragma once
#include "spdlog/common.h" #include <spdlog/common.h>
#include <tuple> #include <tuple>
namespace spdlog { namespace spdlog {
@ -29,7 +29,6 @@ public:
void write(const memory_buf_t &buf); void write(const memory_buf_t &buf);
size_t size() const; size_t size() const;
const filename_t &filename() const; const filename_t &filename() const;
static bool file_exists(const filename_t &fname);
// //
// return file path and its extension: // return file path and its extension:
@ -47,10 +46,10 @@ public:
static std::tuple<filename_t, filename_t> split_by_extension(const filename_t &fname); static std::tuple<filename_t, filename_t> split_by_extension(const filename_t &fname);
private: private:
const int open_tries = 5; const int open_tries_ = 5;
const int open_interval = 10; const int open_interval_ = 10;
std::FILE *fd_{nullptr}; std::FILE *fd_{nullptr};
filename_t _filename; filename_t filename_;
}; };
} // namespace details } // namespace details
} // namespace spdlog } // namespace spdlog

@ -4,8 +4,8 @@
#include <chrono> #include <chrono>
#include <type_traits> #include <type_traits>
#include "spdlog/fmt/fmt.h" #include <spdlog/fmt/fmt.h>
#include "spdlog/common.h" #include <spdlog/common.h>
// Some fmt helpers to efficiently format and pad ints and strings // Some fmt helpers to efficiently format and pad ints and strings
namespace spdlog { namespace spdlog {

@ -4,10 +4,10 @@
#pragma once #pragma once
#ifndef SPDLOG_HEADER_ONLY #ifndef SPDLOG_HEADER_ONLY
#include "spdlog/details/log_msg.h" #include <spdlog/details/log_msg.h>
#endif #endif
#include "spdlog/details/os.h" #include <spdlog/details/os.h>
namespace spdlog { namespace spdlog {
namespace details { 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) 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) : logger_name(logger_name)
, level(lvl) , level(lvl)
#ifndef SPDLOG_NO_DATETIME
, time(os::now()) , time(os::now())
#endif
#ifndef SPDLOG_NO_THREAD_ID #ifndef SPDLOG_NO_THREAD_ID
, thread_id(os::thread_id()) , thread_id(os::thread_id())
#endif #endif

@ -3,7 +3,7 @@
#pragma once #pragma once
#include "spdlog/common.h" #include <spdlog/common.h>
#include <string> #include <string>
namespace spdlog { namespace spdlog {

@ -4,7 +4,7 @@
#pragma once #pragma once
#ifndef SPDLOG_HEADER_ONLY #ifndef SPDLOG_HEADER_ONLY
#include "spdlog/details/log_msg_buffer.h" #include <spdlog/details/log_msg_buffer.h>
#endif #endif
namespace spdlog { namespace spdlog {
@ -26,9 +26,7 @@ SPDLOG_INLINE log_msg_buffer::log_msg_buffer(const log_msg_buffer &other)
update_string_views(); update_string_views();
} }
SPDLOG_INLINE log_msg_buffer::log_msg_buffer(log_msg_buffer &&other) SPDLOG_INLINE log_msg_buffer::log_msg_buffer(log_msg_buffer &&other) SPDLOG_NOEXCEPT : log_msg{other}, buffer{std::move(other.buffer)}
: log_msg{std::move(other)}
, buffer{std::move(other.buffer)}
{ {
update_string_views(); update_string_views();
} }
@ -42,9 +40,9 @@ SPDLOG_INLINE log_msg_buffer &log_msg_buffer::operator=(const log_msg_buffer &ot
return *this; 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); buffer = std::move(other.buffer);
update_string_views(); update_string_views();
return *this; return *this;

@ -3,7 +3,7 @@
#pragma once #pragma once
#include "spdlog/details/log_msg.h" #include <spdlog/details/log_msg.h>
namespace spdlog { namespace spdlog {
namespace details { namespace details {
@ -20,9 +20,9 @@ public:
log_msg_buffer() = default; log_msg_buffer() = default;
explicit log_msg_buffer(const log_msg &orig_msg); explicit log_msg_buffer(const log_msg &orig_msg);
log_msg_buffer(const log_msg_buffer &other); 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=(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 } // namespace details

@ -10,7 +10,7 @@
// dequeue_for(..) - will block until the queue is not empty or timeout have // dequeue_for(..) - will block until the queue is not empty or timeout have
// passed. // passed.
#include "spdlog/details/circular_q.h" #include <spdlog/details/circular_q.h>
#include <condition_variable> #include <condition_variable>
#include <mutex> #include <mutex>

@ -4,10 +4,10 @@
#pragma once #pragma once
#ifndef SPDLOG_HEADER_ONLY #ifndef SPDLOG_HEADER_ONLY
#include "spdlog/details/os.h" #include <spdlog/details/os.h>
#endif #endif
#include "spdlog/common.h" #include <spdlog/common.h>
#include <algorithm> #include <algorithm>
#include <chrono> #include <chrono>
@ -42,6 +42,8 @@
#include <limits> #include <limits>
#endif #endif
#include <direct.h> // for _mkdir/_wmkdir
#else // unix #else // unix
#include <fcntl.h> #include <fcntl.h>
@ -91,17 +93,17 @@ SPDLOG_INLINE std::tm localtime(const std::time_t &time_tt) SPDLOG_NOEXCEPT
#ifdef _WIN32 #ifdef _WIN32
std::tm tm; std::tm tm;
localtime_s(&tm, &time_tt); ::localtime_s(&tm, &time_tt);
#else #else
std::tm tm; std::tm tm;
localtime_r(&time_tt, &tm); ::localtime_r(&time_tt, &tm);
#endif #endif
return tm; return tm;
} }
SPDLOG_INLINE std::tm localtime() SPDLOG_NOEXCEPT 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); return localtime(now_t);
} }
@ -110,52 +112,52 @@ SPDLOG_INLINE std::tm gmtime(const std::time_t &time_tt) SPDLOG_NOEXCEPT
#ifdef _WIN32 #ifdef _WIN32
std::tm tm; std::tm tm;
gmtime_s(&tm, &time_tt); ::gmtime_s(&tm, &time_tt);
#else #else
std::tm tm; std::tm tm;
gmtime_r(&time_tt, &tm); ::gmtime_r(&time_tt, &tm);
#endif #endif
return tm; return tm;
} }
SPDLOG_INLINE std::tm gmtime() SPDLOG_NOEXCEPT 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); return gmtime(now_t);
} }
#ifdef SPDLOG_PREVENT_CHILD_FD
SPDLOG_INLINE void prevent_child_fd(FILE *f) SPDLOG_INLINE void prevent_child_fd(FILE *f)
{ {
#ifdef _WIN32 #ifdef _WIN32
#if !defined(__cplusplus_winrt) auto file_handle = reinterpret_cast<HANDLE>(_get_osfhandle(::_fileno(f)));
auto file_handle = reinterpret_cast<HANDLE>(_get_osfhandle(_fileno(f)));
if (!::SetHandleInformation(file_handle, HANDLE_FLAG_INHERIT, 0)) if (!::SetHandleInformation(file_handle, HANDLE_FLAG_INHERIT, 0))
SPDLOG_THROW(spdlog_ex("SetHandleInformation failed", errno)); SPDLOG_THROW(spdlog_ex("SetHandleInformation failed", errno));
#endif
#else #else
auto fd = fileno(f); auto fd = ::fileno(f);
if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1) if (::fcntl(fd, F_SETFD, FD_CLOEXEC) == -1)
{ {
SPDLOG_THROW(spdlog_ex("fcntl with FD_CLOEXEC failed", errno)); SPDLOG_THROW(spdlog_ex("fcntl with FD_CLOEXEC failed", errno));
} }
#endif #endif
} }
#endif // SPDLOG_PREVENT_CHILD_FD
// fopen_s on non windows for writing // fopen_s on non windows for writing
SPDLOG_INLINE bool fopen_s(FILE **fp, const filename_t &filename, const filename_t &mode) SPDLOG_INLINE bool fopen_s(FILE **fp, const filename_t &filename, const filename_t &mode)
{ {
#ifdef _WIN32 #ifdef _WIN32
#ifdef SPDLOG_WCHAR_FILENAMES #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 #else
*fp = _fsopen((filename.c_str()), mode.c_str(), _SH_DENYNO); *fp = ::_fsopen((filename.c_str()), mode.c_str(), _SH_DENYNO);
#endif #endif
#else // unix #else // unix
*fp = fopen((filename.c_str()), mode.c_str()); *fp = ::fopen((filename.c_str()), mode.c_str());
#endif #endif
#ifdef SPDLOG_PREVENT_CHILD_FD #ifdef SPDLOG_PREVENT_CHILD_FD
// prevent child processes from inheriting log file descriptors
if (*fp != nullptr) if (*fp != nullptr)
{ {
prevent_child_fd(*fp); 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 SPDLOG_INLINE int remove(const filename_t &filename) SPDLOG_NOEXCEPT
{ {
#if defined(_WIN32) && defined(SPDLOG_WCHAR_FILENAMES) #if defined(_WIN32) && defined(SPDLOG_WCHAR_FILENAMES)
return _wremove(filename.c_str()); return ::_wremove(filename.c_str());
#else #else
return std::remove(filename.c_str()); return std::remove(filename.c_str());
#endif #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 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 SPDLOG_INLINE int rename(const filename_t &filename1, const filename_t &filename2) SPDLOG_NOEXCEPT
{ {
#if defined(_WIN32) && defined(SPDLOG_WCHAR_FILENAMES) #if defined(_WIN32) && defined(SPDLOG_WCHAR_FILENAMES)
return _wrename(filename1.c_str(), filename2.c_str()); return ::_wrename(filename1.c_str(), filename2.c_str());
#else #else
return std::rename(filename1.c_str(), filename2.c_str()); return std::rename(filename1.c_str(), filename2.c_str());
#endif #endif
} }
// Return true if file exists // Return true if path exists (file or directory)
SPDLOG_INLINE bool file_exists(const filename_t &filename) SPDLOG_NOEXCEPT SPDLOG_INLINE bool path_exists(const filename_t &filename) SPDLOG_NOEXCEPT
{ {
#ifdef _WIN32 #ifdef _WIN32
#ifdef SPDLOG_WCHAR_FILENAMES #ifdef SPDLOG_WCHAR_FILENAMES
auto attribs = GetFileAttributesW(filename.c_str()); auto attribs = ::GetFileAttributesW(filename.c_str());
#else #else
auto attribs = GetFileAttributesA(filename.c_str()); auto attribs = ::GetFileAttributesA(filename.c_str());
#endif #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 #else // common linux/unix all have the stat system call
struct stat buffer; struct stat buffer;
return (::stat(filename.c_str(), &buffer) == 0); 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")); SPDLOG_THROW(spdlog_ex("Failed getting file size. fd is null"));
} }
#if defined(_WIN32) && !defined(__CYGWIN__) #if defined(_WIN32) && !defined(__CYGWIN__)
int fd = _fileno(f); int fd = ::_fileno(f);
#if _WIN64 // 64 bits #if _WIN64 // 64 bits
__int64 ret = _filelengthi64(fd); __int64 ret = ::_filelengthi64(fd);
if (ret >= 0) if (ret >= 0)
{ {
return static_cast<size_t>(ret); return static_cast<size_t>(ret);
} }
#else // windows 32 bits #else // windows 32 bits
long ret = _filelength(fd); long ret = ::_filelength(fd);
if (ret >= 0) if (ret >= 0)
{ {
return static_cast<size_t>(ret); return static_cast<size_t>(ret);
@ -228,7 +230,7 @@ SPDLOG_INLINE size_t filesize(FILE *f)
#endif #endif
#else // unix #else // unix
int fd = fileno(f); int fd = ::fileno(f);
// 64 bits(but not in osx or cygwin, where fstat64 is deprecated) // 64 bits(but not in osx or cygwin, where fstat64 is deprecated)
#if (defined(__linux__) || defined(__sun) || defined(_AIX)) && (defined(__LP64__) || defined(_LP64)) #if (defined(__linux__) || defined(__sun) || defined(_AIX)) && (defined(__LP64__) || defined(_LP64))
struct stat64 st; struct stat64 st;
@ -236,9 +238,8 @@ SPDLOG_INLINE size_t filesize(FILE *f)
{ {
return static_cast<size_t>(st.st_size); return static_cast<size_t>(st.st_size);
} }
#else // unix 32 bits or cygwin #else // other unix or linux 32 bits or cygwin
struct stat st; struct stat st;
if (::fstat(fd, &st) == 0) if (::fstat(fd, &st) == 0)
{ {
return static_cast<size_t>(st.st_size); return static_cast<size_t>(st.st_size);
@ -255,10 +256,10 @@ SPDLOG_INLINE int utc_minutes_offset(const std::tm &tm)
#ifdef _WIN32 #ifdef _WIN32
#if _WIN32_WINNT < _WIN32_WINNT_WS08 #if _WIN32_WINNT < _WIN32_WINNT_WS08
TIME_ZONE_INFORMATION tzinfo; TIME_ZONE_INFORMATION tzinfo;
auto rv = GetTimeZoneInformation(&tzinfo); auto rv = ::GetTimeZoneInformation(&tzinfo);
#else #else
DYNAMIC_TIME_ZONE_INFORMATION tzinfo; DYNAMIC_TIME_ZONE_INFORMATION tzinfo;
auto rv = GetDynamicTimeZoneInformation(&tzinfo); auto rv = ::GetDynamicTimeZoneInformation(&tzinfo);
#endif #endif
if (rv == TIME_ZONE_ID_INVALID) if (rv == TIME_ZONE_ID_INVALID)
SPDLOG_THROW(spdlog::spdlog_ex("Failed getting timezone info. ", errno)); 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; return offset;
#else #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 // 'tm_gmtoff' field is BSD extension and it's missing on SunOS/Solaris
struct helper struct helper
{ {
@ -324,15 +325,15 @@ SPDLOG_INLINE size_t _thread_id() SPDLOG_NOEXCEPT
#if defined(__ANDROID__) && defined(__ANDROID_API__) && (__ANDROID_API__ < 21) #if defined(__ANDROID__) && defined(__ANDROID_API__) && (__ANDROID_API__ < 21)
#define SYS_gettid __NR_gettid #define SYS_gettid __NR_gettid
#endif #endif
return static_cast<size_t>(syscall(SYS_gettid)); return static_cast<size_t>(::syscall(SYS_gettid));
#elif defined(_AIX) || defined(__DragonFly__) || defined(__FreeBSD__) #elif defined(_AIX) || defined(__DragonFly__) || defined(__FreeBSD__)
return static_cast<size_t>(pthread_getthreadid_np()); return static_cast<size_t>(::pthread_getthreadid_np());
#elif defined(__NetBSD__) #elif defined(__NetBSD__)
return static_cast<size_t>(_lwp_self()); return static_cast<size_t>(::_lwp_self());
#elif defined(__OpenBSD__) #elif defined(__OpenBSD__)
return static_cast<size_t>(getthrid()); return static_cast<size_t>(::getthrid());
#elif defined(__sun) #elif defined(__sun)
return static_cast<size_t>(thr_self()); return static_cast<size_t>(::thr_self());
#elif __APPLE__ #elif __APPLE__
uint64_t tid; uint64_t tid;
pthread_threadid_np(nullptr, &tid); pthread_threadid_np(nullptr, &tid);
@ -417,16 +418,16 @@ SPDLOG_INLINE bool in_terminal(FILE *file) SPDLOG_NOEXCEPT
{ {
#ifdef _WIN32 #ifdef _WIN32
return _isatty(_fileno(file)) != 0; return ::_isatty(_fileno(file)) != 0;
#else #else
return isatty(fileno(file)) != 0; return ::isatty(fileno(file)) != 0;
#endif #endif
} }
#if (defined(SPDLOG_WCHAR_TO_UTF8_SUPPORT) || defined(SPDLOG_WCHAR_FILENAMES)) && defined(_WIN32) #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) SPDLOG_INLINE void wstr_to_utf8buf(wstring_view_t wstr, memory_buf_t &target)
{ {
if (wstr.size() > static_cast<size_t>(std::numeric_limits<int>::max())) if (wstr.size() > static_cast<size_t>((std::numeric_limits<int>::max)()))
{ {
SPDLOG_THROW(spdlog::spdlog_ex("UTF-16 string is too big to be converted to UTF-8")); 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) #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 os
} // namespace details } // namespace details
} // namespace spdlog } // namespace spdlog

@ -3,7 +3,7 @@
#pragma once #pragma once
#include "spdlog/common.h" #include <spdlog/common.h>
#include <ctime> // std::time_t #include <ctime> // std::time_t
namespace spdlog { namespace spdlog {
@ -33,12 +33,14 @@ SPDLOG_CONSTEXPR static const char *default_eol = SPDLOG_EOL;
// folder separator // folder separator
#ifdef _WIN32 #ifdef _WIN32
const char folder_sep = '\\'; static const char folder_sep = '\\';
#else #else
SPDLOG_CONSTEXPR static const char folder_sep = '/'; SPDLOG_CONSTEXPR static const char folder_sep = '/';
#endif #endif
#ifdef SPDLOG_PREVENT_CHILD_FD
void prevent_child_fd(FILE *f); void prevent_child_fd(FILE *f);
#endif
// fopen_s on non windows for writing // fopen_s on non windows for writing
bool fopen_s(FILE **fp, const filename_t &filename, const filename_t &mode); 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; int rename(const filename_t &filename1, const filename_t &filename2) SPDLOG_NOEXCEPT;
// Return if file exists. // 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 // Return file size according to open FILE* object
size_t filesize(FILE *f); size_t filesize(FILE *f);
@ -81,7 +83,7 @@ int pid() SPDLOG_NOEXCEPT;
// Source: https://github.com/agauniyal/rang/ // Source: https://github.com/agauniyal/rang/
bool is_color_terminal() SPDLOG_NOEXCEPT; bool is_color_terminal() SPDLOG_NOEXCEPT;
// Detrmine if the terminal attached // Determine if the terminal attached
// Source: https://github.com/agauniyal/rang/ // Source: https://github.com/agauniyal/rang/
bool in_terminal(FILE *file) SPDLOG_NOEXCEPT; 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); void wstr_to_utf8buf(wstring_view_t wstr, memory_buf_t &target);
#endif #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 os
} // namespace details } // namespace details
} // namespace spdlog } // namespace spdlog

@ -4,14 +4,14 @@
#pragma once #pragma once
#ifndef SPDLOG_HEADER_ONLY #ifndef SPDLOG_HEADER_ONLY
#include "spdlog/details/pattern_formatter.h" #include <spdlog/details/pattern_formatter.h>
#endif #endif
#include "spdlog/details/fmt_helper.h" #include <spdlog/details/fmt_helper.h>
#include "spdlog/details/log_msg.h" #include <spdlog/details/log_msg.h>
#include "spdlog/details/os.h" #include <spdlog/details/os.h>
#include "spdlog/fmt/fmt.h" #include <spdlog/fmt/fmt.h>
#include "spdlog/formatter.h" #include <spdlog/formatter.h>
#include <array> #include <array>
#include <chrono> #include <chrono>
@ -39,47 +39,50 @@ public:
: padinfo_(padinfo) : padinfo_(padinfo)
, dest_(dest) , dest_(dest)
{ {
remaining_pad_ = static_cast<long>(padinfo.width_) - static_cast<long>(wrapped_size);
if (padinfo_.width_ <= wrapped_size) if (remaining_pad_ <= 0)
{ {
total_pad_ = 0;
return; return;
} }
total_pad_ = padinfo.width_ - wrapped_size;
if (padinfo_.side_ == padding_info::left) if (padinfo_.side_ == padding_info::left)
{ {
pad_it(total_pad_); pad_it(remaining_pad_);
total_pad_ = 0; remaining_pad_ = 0;
} }
else if (padinfo_.side_ == padding_info::center) else if (padinfo_.side_ == padding_info::center)
{ {
auto half_pad = total_pad_ / 2; auto half_pad = remaining_pad_ / 2;
auto reminder = total_pad_ & 1; auto reminder = remaining_pad_ & 1;
pad_it(half_pad); pad_it(half_pad);
total_pad_ = half_pad + reminder; // for the right side remaining_pad_ = half_pad + reminder; // for the right side
} }
} }
~scoped_padder() ~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<long>(dest_.size()) + remaining_pad_;
dest_.resize(static_cast<size_t>(new_size));
} }
} }
private: private:
void pad_it(size_t count) void pad_it(long count)
{ {
// count = std::min(count, spaces_.size()); // 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_); fmt_helper::append_string_view(string_view_t(spaces_.data(), count), dest_);
} }
const padding_info &padinfo_; const padding_info &padinfo_;
memory_buf_t &dest_; memory_buf_t &dest_;
size_t total_pad_; long remaining_pad_;
string_view_t spaces_{" ", 64}; string_view_t spaces_{" ", 64};
}; };
@ -593,14 +596,7 @@ public:
const size_t field_size = 6; const size_t field_size = 6;
ScopedPadder p(field_size, padinfo_, dest); ScopedPadder p(field_size, padinfo_, dest);
#ifdef _WIN32 auto total_minutes = get_cached_offset(msg, tm_time);
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
bool is_negative = total_minutes < 0; bool is_negative = total_minutes < 0;
if (is_negative) if (is_negative)
{ {
@ -619,7 +615,6 @@ public:
private: private:
log_clock::time_point last_update_{std::chrono::seconds(0)}; log_clock::time_point last_update_{std::chrono::seconds(0)};
#ifdef _WIN32
int offset_minutes_{0}; int offset_minutes_{0};
int get_cached_offset(const log_msg &msg, const std::tm &tm_time) int get_cached_offset(const log_msg &msg, const std::tm &tm_time)
@ -632,7 +627,6 @@ private:
} }
return offset_minutes_; return offset_minutes_;
} }
#endif
}; };
// Thread id // Thread id
@ -885,7 +879,7 @@ public:
fmt_helper::pad6(static_cast<size_t>(delta_units.count()), dest); fmt_helper::pad6(static_cast<size_t>(delta_units.count()), dest);
} }
protected: private:
log_clock::time_point last_message_time_; log_clock::time_point last_message_time_;
}; };
@ -904,8 +898,6 @@ public:
using std::chrono::milliseconds; using std::chrono::milliseconds;
using std::chrono::seconds; using std::chrono::seconds;
#ifndef SPDLOG_NO_DATETIME
// cache the date/time part for the next second. // cache the date/time part for the next second.
auto duration = msg.time.time_since_epoch(); auto duration = msg.time.time_since_epoch();
auto secs = duration_cast<seconds>(duration); auto secs = duration_cast<seconds>(duration);
@ -941,10 +933,6 @@ public:
dest.push_back(']'); dest.push_back(']');
dest.push_back(' '); dest.push_back(' ');
#else // no datetime needed
(void)tm_time;
#endif
#ifndef SPDLOG_NO_NAME #ifndef SPDLOG_NO_NAME
if (msg.logger_name.size() > 0) if (msg.logger_name.size() > 0)
{ {
@ -1014,14 +1002,13 @@ SPDLOG_INLINE std::unique_ptr<formatter> pattern_formatter::clone() const
SPDLOG_INLINE void pattern_formatter::format(const details::log_msg &msg, memory_buf_t &dest) 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<std::chrono::seconds>(msg.time.time_since_epoch()); auto secs = std::chrono::duration_cast<std::chrono::seconds>(msg.time.time_since_epoch());
if (secs != last_log_secs_) if (secs != last_log_secs_)
{ {
cached_tm_ = get_time_(msg); cached_tm_ = get_time_(msg);
last_log_secs_ = secs; last_log_secs_ = secs;
} }
#endif
for (auto &f : formatters_) for (auto &f : formatters_)
{ {
f->format(msg, cached_tm_, dest); 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) // Advance the given it pass the end of the padding spec found (if any)
// Return padding. // Return padding.
SPDLOG_INLINE details::padding_info pattern_formatter::handle_padspec_(std::string::const_iterator &it, std::string::const_iterator end) 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<unsigned char>(*it))) if (it == end || !std::isdigit(static_cast<unsigned char>(*it)))
{ {
return padding_info{0, side}; return padding_info{}; // no padding if no digit found here
} }
auto width = static_cast<size_t>(*it) - '0'; auto width = static_cast<size_t>(*it) - '0';
@ -1265,7 +1252,20 @@ SPDLOG_INLINE details::padding_info pattern_formatter::handle_padspec_(std::stri
auto digit = static_cast<size_t>(*it) - '0'; auto digit = static_cast<size_t>(*it) - '0';
width = width * 10 + digit; width = width * 10 + digit;
} }
return details::padding_info{std::min<size_t>(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<size_t>(width, max_width), side, truncate};
} }
SPDLOG_INLINE void pattern_formatter::compile_pattern_(const std::string &pattern) SPDLOG_INLINE void pattern_formatter::compile_pattern_(const std::string &pattern)

@ -3,10 +3,10 @@
#pragma once #pragma once
#include "spdlog/common.h" #include <spdlog/common.h>
#include "spdlog/details/log_msg.h" #include <spdlog/details/log_msg.h>
#include "spdlog/details/os.h" #include <spdlog/details/os.h>
#include "spdlog/formatter.h" #include <spdlog/formatter.h>
#include <chrono> #include <chrono>
#include <ctime> #include <ctime>
@ -29,17 +29,21 @@ struct padding_info
}; };
padding_info() = default; 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) : width_(width)
, side_(side) , side_(side)
, truncate_(truncate)
, enabled_(true)
{} {}
bool enabled() const bool enabled() const
{ {
return width_ != 0; return enabled_;
} }
const size_t width_ = 0; const size_t width_ = 0;
const pad_side side_ = left; const pad_side side_ = left;
bool truncate_ = false;
bool enabled_ = false;
}; };
class flag_formatter class flag_formatter

@ -4,7 +4,7 @@
#pragma once #pragma once
#ifndef SPDLOG_HEADER_ONLY #ifndef SPDLOG_HEADER_ONLY
#include "spdlog/details/periodic_worker.h" #include <spdlog/details/periodic_worker.h>
#endif #endif
namespace spdlog { namespace spdlog {

@ -7,16 +7,17 @@
#include "spdlog/details/registry.h" #include "spdlog/details/registry.h"
#endif #endif
#include "spdlog/common.h" #include <spdlog/common.h>
#include "spdlog/logger.h" #include <spdlog/details/periodic_worker.h>
#include "spdlog/details/pattern_formatter.h" #include <spdlog/logger.h>
#include <spdlog/details/pattern_formatter.h>
#ifndef SPDLOG_DISABLE_DEFAULT_LOGGER #ifndef SPDLOG_DISABLE_DEFAULT_LOGGER
// support for the default stdout color logger // support for the default stdout color logger
#ifdef _WIN32 #ifdef _WIN32
#include "spdlog/sinks/wincolor_sink.h" #include <spdlog/sinks/wincolor_sink.h>
#else #else
#include "spdlog/sinks/ansicolor_sink.h" #include <spdlog/sinks/ansicolor_sink.h>
#endif #endif
#endif // SPDLOG_DISABLE_DEFAULT_LOGGER #endif // SPDLOG_DISABLE_DEFAULT_LOGGER
@ -256,10 +257,10 @@ SPDLOG_INLINE std::recursive_mutex &registry::tp_mutex()
return 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<std::mutex> lock(logger_map_mutex_); std::lock_guard<std::mutex> lock(logger_map_mutex_);
automatic_registration_ = automatic_regsistration; automatic_registration_ = automatic_registration;
} }
SPDLOG_INLINE registry &registry::instance() SPDLOG_INLINE registry &registry::instance()

@ -8,8 +8,7 @@
// If user requests a non existing logger, nullptr will be returned // If user requests a non existing logger, nullptr will be returned
// This class is thread safe // This class is thread safe
#include "spdlog/common.h" #include <spdlog/common.h>
#include "spdlog/details/periodic_worker.h"
#include <chrono> #include <chrono>
#include <functional> #include <functional>
@ -82,7 +81,7 @@ public:
std::recursive_mutex &tp_mutex(); 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 // Factory function to create a new logger and register it in this registry
template<typename Sink, typename... SinkArgs> template<typename Sink, typename... SinkArgs>

@ -4,10 +4,10 @@
#pragma once #pragma once
#ifndef SPDLOG_HEADER_ONLY #ifndef SPDLOG_HEADER_ONLY
#include "spdlog/details/thread_pool.h" #include <spdlog/details/thread_pool.h>
#endif #endif
#include "spdlog/common.h" #include <spdlog/common.h>
namespace spdlog { namespace spdlog {
namespace details { namespace details {
@ -98,24 +98,20 @@ bool SPDLOG_INLINE thread_pool::process_next_msg_()
switch (incoming_async_msg.msg_type) 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); incoming_async_msg.worker_ptr->backend_sink_it_(incoming_async_msg);
return true; return true;
} }
case async_msg_type::flush: case async_msg_type::flush: {
{
incoming_async_msg.worker_ptr->backend_flush_(); incoming_async_msg.worker_ptr->backend_flush_();
return true; return true;
} }
case async_msg_type::terminate: case async_msg_type::terminate: {
{
return false; return false;
} }
default: default: {
{
assert(false && "Unexpected async_msg_type"); assert(false && "Unexpected async_msg_type");
} }
} }

@ -3,9 +3,9 @@
#pragma once #pragma once
#include "spdlog/details/log_msg_buffer.h" #include <spdlog/details/log_msg_buffer.h>
#include "spdlog/details/mpmc_blocking_q.h" #include <spdlog/details/mpmc_blocking_q.h>
#include "spdlog/details/os.h" #include <spdlog/details/os.h>
#include <chrono> #include <chrono>
#include <memory> #include <memory>
@ -27,7 +27,7 @@ enum class async_msg_type
terminate terminate
}; };
#include "spdlog/details/log_msg_buffer.h" #include <spdlog/details/log_msg_buffer.h>
// Async msg to move to/from the queue // Async msg to move to/from the queue
// Movable only. should never be copied // Movable only. should never be copied
struct async_msg : log_msg_buffer struct async_msg : log_msg_buffer

@ -22,6 +22,6 @@
#include "bundled/core.h" #include "bundled/core.h"
#include "bundled/format.h" #include "bundled/format.h"
#else // SPDLOG_FMT_EXTERNAL is defined - use external fmtlib #else // SPDLOG_FMT_EXTERNAL is defined - use external fmtlib
#include "fmt/core.h" #include <fmt/core.h>
#include "fmt/format.h" #include <fmt/format.h>
#endif #endif

@ -3,8 +3,8 @@
#pragma once #pragma once
#include "fmt/fmt.h" #include <spdlog/fmt/fmt.h>
#include "spdlog/details/log_msg.h" #include <spdlog/details/log_msg.h>
namespace spdlog { namespace spdlog {

@ -4,12 +4,12 @@
#pragma once #pragma once
#ifndef SPDLOG_HEADER_ONLY #ifndef SPDLOG_HEADER_ONLY
#include "spdlog/logger.h" #include <spdlog/logger.h>
#endif #endif
#include "spdlog/sinks/sink.h" #include <spdlog/sinks/sink.h>
#include "spdlog/details/backtracer.h" #include <spdlog/details/backtracer.h>
#include "spdlog/details/pattern_formatter.h" #include <spdlog/details/pattern_formatter.h>
#include <cstdio> #include <cstdio>
@ -64,11 +64,6 @@ SPDLOG_INLINE void swap(logger &a, logger &b)
a.swap(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) SPDLOG_INLINE void logger::set_level(level::level_enum log_level)
{ {
level_.store(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. // 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<formatter> f) SPDLOG_INLINE void logger::set_formatter(std::unique_ptr<formatter> f)
{ {
for (auto it = sinks_.begin(); it != sinks_.end(); ++it) for (auto it = sinks_.begin(); it != sinks_.end(); ++it)
@ -155,7 +150,7 @@ SPDLOG_INLINE std::vector<sink_ptr> &logger::sinks()
// error handler // error handler
SPDLOG_INLINE void logger::set_error_handler(err_handler 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. // create new logger with same sinks and configuration.
@ -167,6 +162,18 @@ SPDLOG_INLINE std::shared_ptr<logger> logger::clone(std::string logger_name)
} }
// protected methods // 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) SPDLOG_INLINE void logger::sink_it_(const details::log_msg &msg)
{ {
for (auto &sink : sinks_) for (auto &sink : sinks_)
@ -202,7 +209,7 @@ SPDLOG_INLINE void logger::flush_()
SPDLOG_INLINE void logger::dump_backtrace_() SPDLOG_INLINE void logger::dump_backtrace_()
{ {
using details::log_msg; using details::log_msg;
if (tracer_) if (tracer_.enabled())
{ {
sink_it_(log_msg{name(), level::info, "****************** Backtrace Start ******************"}); sink_it_(log_msg{name(), level::info, "****************** Backtrace Start ******************"});
tracer_.foreach_pop([this](const log_msg &msg) { this->sink_it_(msg); }); tracer_.foreach_pop([this](const log_msg &msg) { this->sink_it_(msg); });

@ -14,12 +14,12 @@
// The use of private formatter per sink provides the opportunity to cache some // The use of private formatter per sink provides the opportunity to cache some
// formatted data, and support for different format per sink. // formatted data, and support for different format per sink.
#include "spdlog/common.h" #include <spdlog/common.h>
#include "spdlog/details/log_msg.h" #include <spdlog/details/log_msg.h>
#include "spdlog/details/backtracer.h" #include <spdlog/details/backtracer.h>
#ifdef SPDLOG_WCHAR_TO_UTF8_SUPPORT #ifdef SPDLOG_WCHAR_TO_UTF8_SUPPORT
#include "spdlog/details/os.h" #include <spdlog/details/os.h>
#endif #endif
#include <vector> #include <vector>
@ -76,8 +76,9 @@ public:
template<typename... Args> template<typename... Args>
void log(source_loc loc, level::level_enum lvl, string_view_t fmt, const Args &... args) void log(source_loc loc, level::level_enum lvl, string_view_t fmt, const Args &... args)
{ {
auto level_enabled = should_log(lvl); bool log_enabled = should_log(lvl);
if (!level_enabled && !tracer_) bool traceback_enabled = tracer_.enabled();
if (!log_enabled && !traceback_enabled)
{ {
return; return;
} }
@ -86,14 +87,7 @@ public:
memory_buf_t buf; memory_buf_t buf;
fmt::format_to(buf, fmt, args...); fmt::format_to(buf, fmt, args...);
details::log_msg log_msg(loc, name_, lvl, string_view_t(buf.data(), buf.size())); details::log_msg log_msg(loc, name_, lvl, string_view_t(buf.data(), buf.size()));
if (level_enabled) log_it_(log_msg, log_enabled, traceback_enabled);
{
sink_it_(log_msg);
}
if (tracer_)
{
tracer_.push_back(log_msg);
}
} }
SPDLOG_LOGGER_CATCH() SPDLOG_LOGGER_CATCH()
} }
@ -150,24 +144,15 @@ public:
template<class T, typename std::enable_if<std::is_convertible<const T &, spdlog::string_view_t>::value, T>::type * = nullptr> template<class T, typename std::enable_if<std::is_convertible<const T &, spdlog::string_view_t>::value, T>::type * = nullptr>
void log(source_loc loc, level::level_enum lvl, const T &msg) void log(source_loc loc, level::level_enum lvl, const T &msg)
{ {
auto level_enabled = should_log(lvl); bool log_enabled = should_log(lvl);
if (!level_enabled && !tracer_) bool traceback_enabled = tracer_.enabled();
if (!log_enabled && !traceback_enabled)
{ {
return; return;
} }
SPDLOG_TRY
{
details::log_msg log_msg(loc, name_, lvl, msg); details::log_msg log_msg(loc, name_, lvl, msg);
if (level_enabled) log_it_(log_msg, log_enabled, traceback_enabled);
{
sink_it_(log_msg);
}
if (tracer_)
{
tracer_.push_back(log_msg);
}
}
SPDLOG_LOGGER_CATCH()
} }
void log(level::level_enum lvl, string_view_t msg) void log(level::level_enum lvl, string_view_t msg)
@ -228,8 +213,9 @@ public:
template<typename... Args> template<typename... Args>
void log(source_loc loc, level::level_enum lvl, wstring_view_t fmt, const Args &... args) void log(source_loc loc, level::level_enum lvl, wstring_view_t fmt, const Args &... args)
{ {
auto level_enabled = should_log(lvl); bool log_enabled = should_log(lvl);
if (!level_enabled && !tracer_) bool traceback_enabled = tracer_.enabled();
if (!log_enabled && !traceback_enabled)
{ {
return; return;
} }
@ -242,15 +228,7 @@ public:
memory_buf_t buf; memory_buf_t buf;
details::os::wstr_to_utf8buf(wstring_view_t(wbuf.data(), wbuf.size()), 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())); details::log_msg log_msg(loc, name_, lvl, string_view_t(buf.data(), buf.size()));
log_it_(log_msg, log_enabled, traceback_enabled);
if (level_enabled)
{
sink_it_(log_msg);
}
if (tracer_)
{
tracer_.push_back(log_msg);
}
} }
SPDLOG_LOGGER_CATCH() SPDLOG_LOGGER_CATCH()
} }
@ -301,25 +279,36 @@ public:
template<class T, typename std::enable_if<is_convertible_to_wstring_view<const T &>::value, T>::type * = nullptr> template<class T, typename std::enable_if<is_convertible_to_wstring_view<const T &>::value, T>::type * = nullptr>
void log(source_loc loc, level::level_enum lvl, const T &msg) 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; return;
} }
try SPDLOG_TRY
{ {
memory_buf_t buf; memory_buf_t buf;
details::os::wstr_to_utf8buf(msg, buf); details::os::wstr_to_utf8buf(msg, buf);
details::log_msg log_msg(loc, name_, lvl, string_view_t(buf.data(), buf.size())); 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() SPDLOG_LOGGER_CATCH()
} }
#endif // _WIN32 #endif // _WIN32
#endif // SPDLOG_WCHAR_TO_UTF8_SUPPORT #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); void set_level(level::level_enum log_level);
@ -328,7 +317,7 @@ public:
const std::string &name() const; const std::string &name() const;
// set formatting for the sinks in this logger. // 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<formatter> f); void set_formatter(std::unique_ptr<formatter> f);
void set_pattern(std::string pattern, pattern_time_type time_type = pattern_time_type::local); 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}; err_handler custom_err_handler_{nullptr};
details::backtracer tracer_; 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 sink_it_(const details::log_msg &msg);
virtual void flush_(); virtual void flush_();
void dump_backtrace_(); void dump_backtrace_();

@ -5,11 +5,11 @@
#ifdef __ANDROID__ #ifdef __ANDROID__
#include "spdlog/details/fmt_helper.h" #include <spdlog/details/fmt_helper.h>
#include "spdlog/details/null_mutex.h" #include <spdlog/details/null_mutex.h>
#include "spdlog/details/os.h" #include <spdlog/details/os.h>
#include "spdlog/sinks/base_sink.h" #include <spdlog/sinks/base_sink.h>
#include "spdlog/details/synchronous_factory.h" #include <spdlog/details/synchronous_factory.h>
#include <android/log.h> #include <android/log.h>
#include <chrono> #include <chrono>

@ -4,11 +4,11 @@
#pragma once #pragma once
#ifndef SPDLOG_HEADER_ONLY #ifndef SPDLOG_HEADER_ONLY
#include "spdlog/sinks/ansicolor_sink.h" #include <spdlog/sinks/ansicolor_sink.h>
#endif #endif
#include "spdlog/details/pattern_formatter.h" #include <spdlog/details/pattern_formatter.h>
#include "spdlog/details/os.h" #include <spdlog/details/os.h>
namespace spdlog { namespace spdlog {
namespace sinks { namespace sinks {

@ -3,9 +3,9 @@
#pragma once #pragma once
#include "spdlog/details/console_globals.h" #include <spdlog/details/console_globals.h>
#include "spdlog/details/null_mutex.h" #include <spdlog/details/null_mutex.h>
#include "spdlog/sinks/sink.h" #include <spdlog/sinks/sink.h>
#include <memory> #include <memory>
#include <mutex> #include <mutex>
#include <string> #include <string>

@ -4,11 +4,11 @@
#pragma once #pragma once
#ifndef SPDLOG_HEADER_ONLY #ifndef SPDLOG_HEADER_ONLY
#include "spdlog/sinks/base_sink.h" #include <spdlog/sinks/base_sink.h>
#endif #endif
#include "spdlog/common.h" #include <spdlog/common.h>
#include "spdlog/details/pattern_formatter.h" #include <spdlog/details/pattern_formatter.h>
#include <memory> #include <memory>

@ -9,9 +9,9 @@
// implementers.. // implementers..
// //
#include "spdlog/common.h" #include <spdlog/common.h>
#include "spdlog/details/log_msg.h" #include <spdlog/details/log_msg.h>
#include "spdlog/sinks/sink.h" #include <spdlog/sinks/sink.h>
namespace spdlog { namespace spdlog {
namespace sinks { namespace sinks {

@ -4,11 +4,11 @@
#pragma once #pragma once
#ifndef SPDLOG_HEADER_ONLY #ifndef SPDLOG_HEADER_ONLY
#include "spdlog/sinks/basic_file_sink.h" #include <spdlog/sinks/basic_file_sink.h>
#endif #endif
#include "spdlog/common.h" #include <spdlog/common.h>
#include "spdlog/details/os.h" #include <spdlog/details/os.h>
namespace spdlog { namespace spdlog {
namespace sinks { namespace sinks {

@ -3,10 +3,10 @@
#pragma once #pragma once
#include "spdlog/details/file_helper.h" #include <spdlog/details/file_helper.h>
#include "spdlog/details/null_mutex.h" #include <spdlog/details/null_mutex.h>
#include "spdlog/sinks/base_sink.h" #include <spdlog/sinks/base_sink.h>
#include "spdlog/details/synchronous_factory.h" #include <spdlog/details/synchronous_factory.h>
#include <mutex> #include <mutex>
#include <string> #include <string>

@ -3,13 +3,13 @@
#pragma once #pragma once
#include "spdlog/common.h" #include <spdlog/common.h>
#include "spdlog/details/file_helper.h" #include <spdlog/details/file_helper.h>
#include "spdlog/details/null_mutex.h" #include <spdlog/details/null_mutex.h>
#include "spdlog/fmt/fmt.h" #include <spdlog/fmt/fmt.h>
#include "spdlog/sinks/base_sink.h" #include <spdlog/sinks/base_sink.h>
#include "spdlog/details/os.h" #include <spdlog/details/os.h>
#include "spdlog/details/synchronous_factory.h" #include <spdlog/details/synchronous_factory.h>
#include <chrono> #include <chrono>
#include <cstdio> #include <cstdio>
@ -78,12 +78,7 @@ public:
protected: protected:
void sink_it_(const details::log_msg &msg) override void sink_it_(const details::log_msg &msg) override
{ {
#ifdef SPDLOG_NO_DATETIME
auto time = log_clock::now();
#else
auto time = msg.time; auto time = msg.time;
#endif
bool should_rotate = time >= rotation_tp_; bool should_rotate = time >= rotation_tp_;
if (should_rotate) if (should_rotate)
{ {
@ -95,7 +90,7 @@ protected:
base_sink<Mutex>::formatter_->format(msg, formatted); base_sink<Mutex>::formatter_->format(msg, formatted);
file_helper_.write(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) if (should_rotate && max_files_ > 0)
{ {
delete_old_(); delete_old_();

@ -4,9 +4,9 @@
#pragma once #pragma once
#include "base_sink.h" #include "base_sink.h"
#include "spdlog/details/log_msg.h" #include <spdlog/details/log_msg.h>
#include "spdlog/details/null_mutex.h" #include <spdlog/details/null_mutex.h>
#include "spdlog/details/pattern_formatter.h" #include <spdlog/details/pattern_formatter.h>
#include <algorithm> #include <algorithm>
#include <memory> #include <memory>

@ -4,8 +4,8 @@
#pragma once #pragma once
#include "dist_sink.h" #include "dist_sink.h"
#include "spdlog/details/null_mutex.h" #include <spdlog/details/null_mutex.h>
#include "spdlog/details/log_msg.h" #include <spdlog/details/log_msg.h>
#include <mutex> #include <mutex>
#include <string> #include <string>
@ -16,7 +16,7 @@
// //
// Example: // Example:
// //
// #include "spdlog/sinks/dup_filter_sink.h" // #include <spdlog/sinks/dup_filter_sink.h>
// //
// int main() { // int main() {
// auto dup_filter = std::make_shared<dup_filter_sink_st>(std::chrono::seconds(5)); // auto dup_filter = std::make_shared<dup_filter_sink_st>(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] Skipped 3 duplicate messages..
// [2019-06-25 17:50:56.512] [logger] [info] Different Hello // [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 spdlog {
namespace sinks { namespace sinks {
template<typename Mutex> template<typename Mutex>

@ -5,8 +5,8 @@
#if defined(_WIN32) #if defined(_WIN32)
#include "spdlog/details/null_mutex.h" #include <spdlog/details/null_mutex.h>
#include "spdlog/sinks/base_sink.h" #include <spdlog/sinks/base_sink.h>
#include <winbase.h> #include <winbase.h>

@ -3,9 +3,9 @@
#pragma once #pragma once
#include "spdlog/details/null_mutex.h" #include <spdlog/details/null_mutex.h>
#include "spdlog/sinks/base_sink.h" #include <spdlog/sinks/base_sink.h>
#include "spdlog/details/synchronous_factory.h" #include <spdlog/details/synchronous_factory.h>
#include <mutex> #include <mutex>

@ -3,8 +3,8 @@
#pragma once #pragma once
#include "spdlog/details/null_mutex.h" #include <spdlog/details/null_mutex.h>
#include "spdlog/sinks/base_sink.h" #include <spdlog/sinks/base_sink.h>
#include <mutex> #include <mutex>
#include <ostream> #include <ostream>

@ -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 <mutex>
#include <string>
#include <vector>
namespace spdlog {
namespace sinks {
/*
* Ring buffer sink
*/
template<typename Mutex>
class ringbuffer_sink final : public base_sink<Mutex>
{
public:
explicit ringbuffer_sink(size_t n_items)
: q_{n_items}
{}
std::vector<details::log_msg_buffer> last_raw(size_t lim = 0)
{
std::lock_guard<Mutex> lock(base_sink<Mutex>::mutex_);
auto n_items = lim > 0 ? (std::min)(lim, q_.size()) : q_.size();
std::vector<details::log_msg_buffer> ret;
ret.reserve(n_items);
for (size_t i = 0; i < n_items; i++)
{
ret.push_back(q_.at(i));
}
return ret;
}
std::vector<std::string> last_formatted(size_t lim = 0)
{
std::lock_guard<Mutex> lock(base_sink<Mutex>::mutex_);
auto n_items = lim > 0 ? (std::min)(lim, q_.size()) : q_.size();
std::vector<std::string> ret;
ret.reserve(n_items);
for (size_t i = 0; i < n_items; i++)
{
memory_buf_t formatted;
base_sink<Mutex>::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<details::log_msg_buffer> q_;
};
using ringbuffer_sink_mt = ringbuffer_sink<std::mutex>;
using ringbuffer_sink_st = ringbuffer_sink<details::null_mutex>;
} // namespace sinks
} // namespace spdlog

@ -4,14 +4,14 @@
#pragma once #pragma once
#ifndef SPDLOG_HEADER_ONLY #ifndef SPDLOG_HEADER_ONLY
#include "spdlog/sinks/rotating_file_sink.h" #include <spdlog/sinks/rotating_file_sink.h>
#endif #endif
#include "spdlog/common.h" #include <spdlog/common.h>
#include "spdlog/details/file_helper.h" #include <spdlog/details/file_helper.h>
#include "spdlog/details/null_mutex.h" #include <spdlog/details/null_mutex.h>
#include "spdlog/fmt/fmt.h" #include <spdlog/fmt/fmt.h>
#include <cerrno> #include <cerrno>
#include <chrono> #include <chrono>
@ -88,11 +88,12 @@ template<typename Mutex>
SPDLOG_INLINE void rotating_file_sink<Mutex>::rotate_() SPDLOG_INLINE void rotating_file_sink<Mutex>::rotate_()
{ {
using details::os::filename_to_str; using details::os::filename_to_str;
using details::os::path_exists;
file_helper_.close(); file_helper_.close();
for (auto i = max_files_; i > 0; --i) for (auto i = max_files_; i > 0; --i)
{ {
filename_t src = calc_filename(base_filename_, i - 1); filename_t src = calc_filename(base_filename_, i - 1);
if (!details::file_helper::file_exists(src)) if (!path_exists(src))
{ {
continue; continue;
} }

@ -3,10 +3,10 @@
#pragma once #pragma once
#include "spdlog/sinks/base_sink.h" #include <spdlog/sinks/base_sink.h>
#include "spdlog/details/file_helper.h" #include <spdlog/details/file_helper.h>
#include "spdlog/details/null_mutex.h" #include <spdlog/details/null_mutex.h>
#include "spdlog/details/synchronous_factory.h" #include <spdlog/details/synchronous_factory.h>
#include <chrono> #include <chrono>
#include <mutex> #include <mutex>

@ -4,10 +4,10 @@
#pragma once #pragma once
#ifndef SPDLOG_HEADER_ONLY #ifndef SPDLOG_HEADER_ONLY
#include "spdlog/sinks/sink.h" #include <spdlog/sinks/sink.h>
#endif #endif
#include "spdlog/common.h" #include <spdlog/common.h>
SPDLOG_INLINE bool spdlog::sinks::sink::should_log(spdlog::level::level_enum msg_level) const SPDLOG_INLINE bool spdlog::sinks::sink::should_log(spdlog::level::level_enum msg_level) const
{ {

@ -3,8 +3,8 @@
#pragma once #pragma once
#include "spdlog/details/log_msg.h" #include <spdlog/details/log_msg.h>
#include "spdlog/formatter.h" #include <spdlog/formatter.h>
namespace spdlog { namespace spdlog {

@ -4,11 +4,11 @@
#pragma once #pragma once
#ifndef SPDLOG_HEADER_ONLY #ifndef SPDLOG_HEADER_ONLY
#include "spdlog/sinks/stdout_color_sinks.h" #include <spdlog/sinks/stdout_color_sinks.h>
#endif #endif
#include "spdlog/logger.h" #include <spdlog/logger.h>
#include "spdlog/common.h" #include <spdlog/common.h>
namespace spdlog { namespace spdlog {

@ -4,12 +4,12 @@
#pragma once #pragma once
#ifdef _WIN32 #ifdef _WIN32
#include "spdlog/sinks/wincolor_sink.h" #include <spdlog/sinks/wincolor_sink.h>
#else #else
#include "spdlog/sinks/ansicolor_sink.h" #include <spdlog/sinks/ansicolor_sink.h>
#endif #endif
#include "spdlog/details/synchronous_factory.h" #include <spdlog/details/synchronous_factory.h>
namespace spdlog { namespace spdlog {
namespace sinks { namespace sinks {

@ -4,11 +4,11 @@
#pragma once #pragma once
#ifndef SPDLOG_HEADER_ONLY #ifndef SPDLOG_HEADER_ONLY
#include "spdlog/sinks/stdout_sinks.h" #include <spdlog/sinks/stdout_sinks.h>
#endif #endif
#include "spdlog/details/console_globals.h" #include <spdlog/details/console_globals.h>
#include "spdlog/details/pattern_formatter.h" #include <spdlog/details/pattern_formatter.h>
#include <memory> #include <memory>
namespace spdlog { namespace spdlog {

@ -3,9 +3,9 @@
#pragma once #pragma once
#include "spdlog/details/console_globals.h" #include <spdlog/details/console_globals.h>
#include "spdlog/details/synchronous_factory.h" #include <spdlog/details/synchronous_factory.h>
#include "spdlog/sinks/sink.h" #include <spdlog/sinks/sink.h>
#include <cstdio> #include <cstdio>
namespace spdlog { namespace spdlog {

@ -3,8 +3,8 @@
#pragma once #pragma once
#include "spdlog/sinks/base_sink.h" #include <spdlog/sinks/base_sink.h>
#include "spdlog/details/null_mutex.h" #include <spdlog/details/null_mutex.h>
#include <array> #include <array>
#include <string> #include <string>

@ -3,10 +3,14 @@
#pragma once #pragma once
#include "spdlog/sinks/base_sink.h" #include <spdlog/sinks/base_sink.h>
#include "spdlog/details/null_mutex.h" #include <spdlog/details/null_mutex.h>
#include "spdlog/details/synchronous_factory.h" #include <spdlog/details/synchronous_factory.h>
#include <array>
#ifndef SD_JOURNAL_SUPPRESS_LOCATION
#define SD_JOURNAL_SUPPRESS_LOCATION
#endif
#include <systemd/sd-journal.h> #include <systemd/sd-journal.h>
namespace spdlog { namespace spdlog {
@ -56,13 +60,14 @@ protected:
if (msg.source.empty()) if (msg.source.empty())
{ {
// Note: function call inside '()' to avoid macro expansion // Note: function call inside '()' to avoid macro expansion
err = (sd_journal_send)( err = (sd_journal_send)("MESSAGE=%.*s", static_cast<int>(length), msg.payload.data(), "PRIORITY=%d", syslog_level(msg.level),
"MESSAGE=%.*s", static_cast<int>(length), msg.payload.data(), "PRIORITY=%d", syslog_level(msg.level), nullptr); "SYSLOG_IDENTIFIER=%.*s", static_cast<int>(msg.logger_name.size()), msg.logger_name.data(), nullptr);
} }
else else
{ {
err = (sd_journal_send)("MESSAGE=%.*s", static_cast<int>(length), msg.payload.data(), "PRIORITY=%d", syslog_level(msg.level), err = (sd_journal_send)("MESSAGE=%.*s", static_cast<int>(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<int>(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) if (err)

@ -4,11 +4,11 @@
#pragma once #pragma once
#ifndef SPDLOG_HEADER_ONLY #ifndef SPDLOG_HEADER_ONLY
#include "spdlog/sinks/wincolor_sink.h" #include <spdlog/sinks/wincolor_sink.h>
#endif #endif
#include "spdlog/common.h" #include <spdlog/common.h>
#include "spdlog/details/pattern_formatter.h" #include <spdlog/details/pattern_formatter.h>
namespace spdlog { namespace spdlog {
namespace sinks { namespace sinks {

@ -3,10 +3,10 @@
#pragma once #pragma once
#include "spdlog/common.h" #include <spdlog/common.h>
#include "spdlog/details/console_globals.h" #include <spdlog/details/console_globals.h>
#include "spdlog/details/null_mutex.h" #include <spdlog/details/null_mutex.h>
#include "spdlog/sinks/sink.h" #include <spdlog/sinks/sink.h>
#include <memory> #include <memory>
#include <mutex> #include <mutex>

@ -4,11 +4,11 @@
#pragma once #pragma once
#ifndef SPDLOG_HEADER_ONLY #ifndef SPDLOG_HEADER_ONLY
#include "spdlog/spdlog.h" #include <spdlog/spdlog.h>
#endif #endif
#include "spdlog/common.h" #include <spdlog/common.h>
#include "spdlog/details/pattern_formatter.h" #include <spdlog/details/pattern_formatter.h>
namespace spdlog { namespace spdlog {
@ -92,9 +92,9 @@ SPDLOG_INLINE void shutdown()
details::registry::instance().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<spdlog::logger> default_logger() SPDLOG_INLINE std::shared_ptr<spdlog::logger> default_logger()

@ -9,11 +9,11 @@
#pragma once #pragma once
#include "spdlog/common.h" #include <spdlog/common.h>
#include "spdlog/details/registry.h" #include <spdlog/details/registry.h>
#include "spdlog/logger.h" #include <spdlog/logger.h>
#include "spdlog/version.h" #include <spdlog/version.h>
#include "spdlog/details/synchronous_factory.h" #include <spdlog/details/synchronous_factory.h>
#include <chrono> #include <chrono>
#include <functional> #include <functional>
@ -100,7 +100,7 @@ void drop_all();
void shutdown(); void shutdown();
// Automatic registration of loggers when using spdlog::create() or spdlog::create_async // 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), // API for using default logger (stdout_color_mt),
// e.g: spdlog::info("Message {}", 1); // e.g: spdlog::info("Message {}", 1);
@ -285,7 +285,7 @@ inline void critical(wstring_view_t fmt, const Args &... args)
// SPDLOG_LEVEL_OFF // 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 #if SPDLOG_ACTIVE_LEVEL <= SPDLOG_LEVEL_TRACE
#define SPDLOG_LOGGER_TRACE(logger, ...) SPDLOG_LOGGER_CALL(logger, spdlog::level::trace, __VA_ARGS__) #define SPDLOG_LOGGER_TRACE(logger, ...) SPDLOG_LOGGER_CALL(logger, spdlog::level::trace, __VA_ARGS__)

@ -19,19 +19,6 @@
// #define SPDLOG_CLOCK_COARSE // #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). // 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. // This will prevent spdlog from querying the thread id on each log call.

@ -5,6 +5,6 @@
#define SPDLOG_VER_MAJOR 1 #define SPDLOG_VER_MAJOR 1
#define SPDLOG_VER_MINOR 4 #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) #define SPDLOG_VERSION (SPDLOG_VER_MAJOR * 10000 + SPDLOG_VER_MINOR * 100 + SPDLOG_VER_PATCH)

@ -21,7 +21,7 @@ dep_list += dependency('threads')
# Check for FMT # Check for FMT
if get_option('external_fmt') if get_option('external_fmt')
if not meson.version().version_compare('>=0.49.0') if not meson.version().version_compare('>=0.49.0')
warning('Finding fmt can fail wit meson versions before 0.49.0') warning('Finding fmt can fail with meson versions before 0.49.0')
endif endif
dep_list += dependency('fmt') dep_list += dependency('fmt')
compile_args += '-DSPDLOG_FMT_EXTERNAL' compile_args += '-DSPDLOG_FMT_EXTERNAL'
@ -31,6 +31,46 @@ if get_option('no_exceptions')
compile_args += '-DSPDLOG_NO_EXCEPTIONS' compile_args += '-DSPDLOG_NO_EXCEPTIONS'
endif 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 --- # --- Compiled library version ---
# ------------------------------------ # ------------------------------------
@ -41,16 +81,19 @@ spdlog_srcs = files([
'src/async.cpp', 'src/async.cpp',
'src/color_sinks.cpp', 'src/color_sinks.cpp',
'src/file_sinks.cpp', 'src/file_sinks.cpp',
'src/fmt.cpp',
'src/spdlog.cpp', 'src/spdlog.cpp',
'src/stdout_sinks.cpp' 'src/stdout_sinks.cpp'
]) ])
if not get_option('external_fmt')
spdlog_srcs+= 'src/fmt.cpp'
endif
if get_option('library_type') == 'static' if get_option('library_type') == 'static'
spdlog = static_library( spdlog = static_library(
'spdlog', 'spdlog',
spdlog_srcs, spdlog_srcs,
cpp_args : [compile_args] + ['-DSPDLOG_COMPILED_LIB'], cpp_args : compile_args_compiled,
include_directories : spdlog_inc, include_directories : spdlog_inc,
dependencies : dep_list, dependencies : dep_list,
install : not meson.is_subproject() install : not meson.is_subproject()
@ -58,7 +101,7 @@ if get_option('library_type') == 'static'
else else
spdlog = shared_library('spdlog', spdlog = shared_library('spdlog',
spdlog_srcs, spdlog_srcs,
cpp_args : [compile_args] + ['-DSPDLOG_COMPILED_LIB'], cpp_args : compile_args_compiled,
include_directories : spdlog_inc, include_directories : spdlog_inc,
dependencies : dep_list, dependencies : dep_list,
install : not meson.is_subproject(), install : not meson.is_subproject(),
@ -68,7 +111,7 @@ endif
spdlog_dep = declare_dependency( spdlog_dep = declare_dependency(
link_with : spdlog, link_with : spdlog,
include_directories : spdlog_inc, include_directories : spdlog_inc,
compile_args : compile_args + ['-DSPDLOG_COMPILED_LIB'], compile_args : compile_args_compiled,
dependencies : dep_list, dependencies : dep_list,
version : meson.project_version(), version : meson.project_version(),
) )
@ -76,10 +119,9 @@ spdlog_dep = declare_dependency(
# ---------------------------------- # ----------------------------------
# --- Header only dependency --- # --- Header only dependency ---
# ---------------------------------- # ----------------------------------
spdlog_headeronly_dep = declare_dependency( spdlog_headeronly_dep = declare_dependency(
include_directories : spdlog_inc, include_directories : spdlog_inc,
compile_args : compile_args, compile_args : compile_args_ho,
dependencies : dep_list, dependencies : dep_list,
version : meson.project_version(), version : meson.project_version(),
) )
@ -97,7 +139,7 @@ if not meson.is_subproject()
name : 'spdlog', name : 'spdlog',
description : 'Fast C++ logging library', description : 'Fast C++ logging library',
url : 'https://github.com/gabime/spdlog', url : 'https://github.com/gabime/spdlog',
extra_cflags : ['-DSPDLOG_COMPILED_LIB'] extra_cflags : compile_args_compiled
) )
endif endif
@ -105,7 +147,7 @@ endif
# --- Conditionally add subdirs --- # --- Conditionally add subdirs ---
# ------------------------------------- # -------------------------------------
if get_option('enable_tests') if get_option('enable_tests') or get_option('enable_tests-ho')
subdir('tests') subdir('tests')
endif endif
@ -122,7 +164,6 @@ endif
# ------------------- # -------------------
summary_str = '''spdlog build summary: summary_str = '''spdlog build summary:
- using external fmt: @0@ - using external fmt: @0@
- building tests: @1@ - building tests: @1@
- building examples: @2@ - building examples: @2@

@ -1,6 +1,15 @@
option('external_fmt', type: 'boolean', value: false, description: 'Use external fmt package instead of the bundled') 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_examples', type: 'boolean', value: true, description: 'Build examples')
option('enable_benchmarks', type: 'boolean', value: false, description: 'Build benchmarks') option('enable_benchmarks', type: 'boolean', value: false, description: 'Build benchmarks')
option('enable_tests', type: 'boolean', value: false, description: 'Build tests') 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('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')

@ -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: '' WarningsAsErrors: ''
HeaderFilterRegex: 'async.h|async_logger.h|common.h|details|formatter.h|logger.h|sinks|spdlog.h|tweakme.h|version.h' HeaderFilterRegex: 'async.h|async_logger.h|common.h|details|formatter.h|logger.h|sinks|spdlog.h|tweakme.h|version.h'
AnalyzeTemporaryDtors: false AnalyzeTemporaryDtors: false

@ -14,18 +14,16 @@ set(SPDLOG_UTESTS_SOURCES
test_misc.cpp test_misc.cpp
test_pattern_formatter.cpp test_pattern_formatter.cpp
test_async.cpp test_async.cpp
includes.h
test_registry.cpp test_registry.cpp
test_macros.cpp test_macros.cpp
utils.cpp utils.cpp
utils.h
main.cpp main.cpp
test_mpmc_q.cpp test_mpmc_q.cpp
test_sink.h test_dup_filter.cpp
test_fmt_helper.cpp test_fmt_helper.cpp
test_stdout_api.cpp test_stdout_api.cpp
test_dup_filter.cpp test_backtrace.cpp
test_backtrace.cpp) test_create_dir.cpp)
if(NOT SPDLOG_NO_EXCEPTIONS) if(NOT SPDLOG_NO_EXCEPTIONS)
list(APPEND SPDLOG_UTESTS_SOURCES test_errors.cpp) list(APPEND SPDLOG_UTESTS_SOURCES test_errors.cpp)
@ -35,34 +33,28 @@ if(systemd_FOUND)
list(APPEND SPDLOG_UTESTS_SOURCES test_systemd.cpp) list(APPEND SPDLOG_UTESTS_SOURCES test_systemd.cpp)
endif() endif()
file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/logs")
enable_testing()
# The compiled library tests enable_testing()
if(SPDLOG_BUILD_TESTS)
add_executable(spdlog-utests ${SPDLOG_UTESTS_SOURCES})
spdlog_enable_warnings(spdlog-utests)
target_link_libraries(spdlog-utests PRIVATE spdlog)
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) if(systemd_FOUND)
target_link_libraries(spdlog-utests PRIVATE ${systemd_LIBRARIES}) target_link_libraries(${test_target} PRIVATE ${systemd_LIBRARIES})
endif() endif()
if(SPDLOG_SANITIZE_ADDRESS) if(SPDLOG_SANITIZE_ADDRESS)
spdlog_enable_sanitizer(spdlog-utests) spdlog_enable_sanitizer(${test_target})
endif() 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() endif()
# The header-only library version tests # The header-only library version tests
if(SPDLOG_BUILD_TESTS_HO) if(SPDLOG_BUILD_TESTS_HO)
add_executable(spdlog-utests-ho ${SPDLOG_UTESTS_SOURCES}) spdlog_prepare_test(spdlog-utests-ho spdlog::spdlog_header_only)
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)
endif() endif()

@ -5,19 +5,18 @@ test_sources = files([
'test_misc.cpp', 'test_misc.cpp',
'test_pattern_formatter.cpp', 'test_pattern_formatter.cpp',
'test_async.cpp', 'test_async.cpp',
'includes.h',
'test_registry.cpp', 'test_registry.cpp',
'test_macros.cpp', 'test_macros.cpp',
'utils.cpp', 'utils.cpp',
'main.cpp', 'main.cpp',
'test_mpmc_q.cpp', 'test_mpmc_q.cpp',
'test_dup_filter.cpp',
'test_fmt_helper.cpp', 'test_fmt_helper.cpp',
'test_stdout_api.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') if not get_option('no_exceptions')
test_sources += 'test_errors.cpp' test_sources += 'test_errors.cpp'
endif endif
@ -35,19 +34,15 @@ if systemd_dep.found()
global_test_deps += systemd_dep global_test_deps += systemd_dep
endif endif
run_command('mkdir', 'logs')
# -------------------------------------- # --------------------------------------
# --- Build the test executables --- # --- 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 = [ if get_option('enable_tests_ho')
['spdlog-utests', spdlog_dep], test_exe = executable('spdlog-utests-ho', test_sources, dependencies: global_test_deps + [spdlog_headeronly_dep])
['spdlog-utests-ho', spdlog_headeronly_dep], test('test_spdlog-ho', test_exe, is_parallel : false)
] endif
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')

@ -157,7 +157,7 @@ TEST_CASE("to_file", "[async]")
prepare_logdir(); prepare_logdir();
size_t messages = 1024; size_t messages = 1024;
size_t tp_threads = 1; 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<spdlog::sinks::basic_file_sink_mt>(filename, true); auto file_sink = std::make_shared<spdlog::sinks::basic_file_sink_mt>(filename, true);
auto tp = std::make_shared<spdlog::details::thread_pool>(messages, tp_threads); auto tp = std::make_shared<spdlog::details::thread_pool>(messages, tp_threads);
@ -179,7 +179,7 @@ TEST_CASE("to_file multi-workers", "[async]")
prepare_logdir(); prepare_logdir();
size_t messages = 1024 * 10; size_t messages = 1024 * 10;
size_t tp_threads = 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<spdlog::sinks::basic_file_sink_mt>(filename, true); auto file_sink = std::make_shared<spdlog::sinks::basic_file_sink_mt>(filename, true);
auto tp = std::make_shared<spdlog::details::thread_pool>(messages, tp_threads); auto tp = std::make_shared<spdlog::details::thread_pool>(messages, tp_threads);

@ -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
}

@ -10,7 +10,7 @@ TEST_CASE("daily_logger with dateonly calculator", "[daily_logger]")
prepare_logdir(); prepare_logdir();
// calculate filename (time based) // calculate filename (time based)
std::string basename = "logs/daily_dateonly"; std::string basename = "test_logs/daily_dateonly";
std::tm tm = spdlog::details::os::localtime(); std::tm tm = spdlog::details::os::localtime();
spdlog::memory_buf_t w; spdlog::memory_buf_t w;
fmt::format_to(w, "{}_{:04d}-{:02d}-{:02d}", basename, tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday); 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(); prepare_logdir();
// calculate filename (time based) // calculate filename (time based)
std::string basename = "logs/daily_dateonly"; std::string basename = "test_logs/daily_dateonly";
std::tm tm = spdlog::details::os::localtime(); std::tm tm = spdlog::details::os::localtime();
spdlog::memory_buf_t w; spdlog::memory_buf_t w;
fmt::format_to(w, "{}{:04d}{:02d}{:02d}", basename, tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday); 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(); 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}; daily_file_sink_st sink{basename, 2, 30, true, max_days};
// simulate messages with 24 intervals // 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)); sink.log(create_msg(offset));
} }
REQUIRE(count_files("logs") == static_cast<size_t>(expected_n_files)); REQUIRE(count_files("test_logs") == static_cast<size_t>(expected_n_files));
} }
TEST_CASE("daily_logger rotate", "[daily_file_sink]") TEST_CASE("daily_logger rotate", "[daily_file_sink]")

@ -26,7 +26,7 @@ protected:
TEST_CASE("default_error_handler", "[errors]]") TEST_CASE("default_error_handler", "[errors]]")
{ {
prepare_logdir(); prepare_logdir();
std::string filename = "logs/simple_log.txt"; std::string filename = "test_logs/simple_log.txt";
auto logger = spdlog::create<spdlog::sinks::basic_file_sink_mt>("test-error", filename, true); auto logger = spdlog::create<spdlog::sinks::basic_file_sink_mt>("test-error", filename, true);
logger->set_pattern("%v"); logger->set_pattern("%v");
@ -43,7 +43,7 @@ struct custom_ex
TEST_CASE("custom_error_handler", "[errors]]") TEST_CASE("custom_error_handler", "[errors]]")
{ {
prepare_logdir(); prepare_logdir();
std::string filename = "logs/simple_log.txt"; std::string filename = "test_logs/simple_log.txt";
auto logger = spdlog::create<spdlog::sinks::basic_file_sink_mt>("logger", filename, true); auto logger = spdlog::create<spdlog::sinks::basic_file_sink_mt>("logger", filename, true);
logger->flush_on(spdlog::level::info); logger->flush_on(spdlog::level::info);
logger->set_error_handler([=](const std::string &) { throw custom_ex(); }); logger->set_error_handler([=](const std::string &) { throw custom_ex(); });
@ -75,15 +75,15 @@ TEST_CASE("async_error_handler", "[errors]]")
prepare_logdir(); prepare_logdir();
std::string err_msg("log failed with some msg"); 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); spdlog::init_thread_pool(128, 1);
auto logger = spdlog::create_async<spdlog::sinks::basic_file_sink_mt>("logger", filename, true); auto logger = spdlog::create_async<spdlog::sinks::basic_file_sink_mt>("logger", filename, true);
logger->set_error_handler([=](const std::string &) { logger->set_error_handler([=](const std::string &) {
std::ofstream ofs("logs/custom_err.txt"); std::ofstream ofs("test_logs/custom_err.txt");
if (!ofs) 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; ofs << err_msg;
}); });
@ -94,7 +94,7 @@ TEST_CASE("async_error_handler", "[errors]]")
} }
spdlog::init_thread_pool(128, 1); spdlog::init_thread_pool(128, 1);
REQUIRE(count_lines(filename) == 2); 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 // Make sure async error handler is executed
@ -103,12 +103,13 @@ TEST_CASE("async_error_handler2", "[errors]]")
prepare_logdir(); prepare_logdir();
std::string err_msg("This is async handler error message"); std::string err_msg("This is async handler error message");
{ {
spdlog::details::os::create_dir("test_logs");
spdlog::init_thread_pool(128, 1); spdlog::init_thread_pool(128, 1);
auto logger = spdlog::create_async<failing_sink>("failed_logger"); auto logger = spdlog::create_async<failing_sink>("failed_logger");
logger->set_error_handler([=](const std::string &) { logger->set_error_handler([=](const std::string &) {
std::ofstream ofs("logs/custom_err2.txt"); std::ofstream ofs("test_logs/custom_err2.txt");
if (!ofs) 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; ofs << err_msg;
}); });
logger->info("Hello failure"); logger->info("Hello failure");
@ -116,5 +117,5 @@ TEST_CASE("async_error_handler2", "[errors]]")
} }
spdlog::init_thread_pool(128, 1); 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);
} }

@ -6,7 +6,7 @@
using spdlog::details::file_helper; using spdlog::details::file_helper;
using spdlog::details::log_msg; 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) 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); 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()]]") TEST_CASE("file_helper_reopen", "[file_helper::reopen()]]")
{ {
prepare_logdir(); prepare_logdir();

@ -6,7 +6,7 @@
TEST_CASE("simple_file_logger", "[simple_logger]]") TEST_CASE("simple_file_logger", "[simple_logger]]")
{ {
prepare_logdir(); prepare_logdir();
std::string filename = "logs/simple_log"; std::string filename = "test_logs/simple_log";
auto logger = spdlog::create<spdlog::sinks::basic_file_sink_mt>("logger", filename); auto logger = spdlog::create<spdlog::sinks::basic_file_sink_mt>("logger", filename);
logger->set_pattern("%v"); logger->set_pattern("%v");
@ -22,7 +22,7 @@ TEST_CASE("simple_file_logger", "[simple_logger]]")
TEST_CASE("flush_on", "[flush_on]]") TEST_CASE("flush_on", "[flush_on]]")
{ {
prepare_logdir(); prepare_logdir();
std::string filename = "logs/simple_log"; std::string filename = "test_logs/simple_log";
auto logger = spdlog::create<spdlog::sinks::basic_file_sink_mt>("logger", filename); auto logger = spdlog::create<spdlog::sinks::basic_file_sink_mt>("logger", filename);
logger->set_pattern("%v"); logger->set_pattern("%v");
@ -42,7 +42,7 @@ TEST_CASE("rotating_file_logger1", "[rotating_logger]]")
{ {
prepare_logdir(); prepare_logdir();
size_t max_size = 1024 * 10; 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); auto logger = spdlog::rotating_logger_mt("logger", basename, max_size, 0);
for (int i = 0; i < 10; ++i) for (int i = 0; i < 10; ++i)
@ -59,7 +59,7 @@ TEST_CASE("rotating_file_logger2", "[rotating_logger]]")
{ {
prepare_logdir(); prepare_logdir();
size_t max_size = 1024 * 10; 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 // make an initial logger to create the first output file

@ -12,7 +12,7 @@ TEST_CASE("debug and trace w/o format string", "[macros]]")
{ {
prepare_logdir(); prepare_logdir();
std::string filename = "logs/simple_log"; std::string filename = "test_logs/simple_log";
auto logger = spdlog::create<spdlog::sinks::basic_file_sink_mt>("logger", filename); auto logger = spdlog::create<spdlog::sinks::basic_file_sink_mt>("logger", filename);
logger->set_pattern("%v"); 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")); SPDLOG_TRACE("Test message {}", throw std::runtime_error("Should not be evaluated"));
} }
TEST_CASE("pass logger pointer", "[macros]")
{
auto logger = spdlog::create<spdlog::sinks::null_sink_mt>("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<spdlog::logger>("test-macro");
// logger->set_level(spdlog::level::off);
// int x = 0;
// SPDLOG_LOGGER_DEBUG(logger, "Test message {}", ++x);
// REQUIRE(x == 0);
//}

@ -1,4 +1,5 @@
#include "includes.h" #include "includes.h"
#include "test_sink.h"
using spdlog::memory_buf_t; using spdlog::memory_buf_t;
@ -138,58 +139,111 @@ TEST_CASE("color range test6", "[pattern_formatter]")
TEST_CASE("level_left_padded", "[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", "[%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]") 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", "[%-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]") 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", "[%=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]") 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", "[%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]") 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", "[%-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]") 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", "[%=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]") 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", "[%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]") 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", "[%-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]") 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", "[%=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]") TEST_CASE("left_padded_huge", "[pattern_formatter]")
{ {
REQUIRE(log_to_str("Some message", "[%-300n] %v", spdlog::pattern_time_type::local, "\n") == 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]") TEST_CASE("left_padded_max", "[pattern_formatter]")
{ {
REQUIRE(log_to_str("Some message", "[%-64n] %v", spdlog::pattern_time_type::local, "\n") == 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<spdlog::formatter>(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]") TEST_CASE("clone-default-formatter", "[pattern_formatter]")

@ -9,7 +9,7 @@ TEST_CASE("register_drop", "[registry]")
spdlog::drop_all(); spdlog::drop_all();
spdlog::create<spdlog::sinks::null_sink_mt>(tested_logger_name); spdlog::create<spdlog::sinks::null_sink_mt>(tested_logger_name);
REQUIRE(spdlog::get(tested_logger_name) != nullptr); REQUIRE(spdlog::get(tested_logger_name) != nullptr);
// Throw if registring existing name // Throw if registering existing name
REQUIRE_THROWS_AS(spdlog::create<spdlog::sinks::null_sink_mt>(tested_logger_name), spdlog::spdlog_ex); REQUIRE_THROWS_AS(spdlog::create<spdlog::sinks::null_sink_mt>(tested_logger_name), spdlog::spdlog_ex);
} }
@ -19,7 +19,7 @@ TEST_CASE("explicit register", "[registry]")
auto logger = std::make_shared<spdlog::logger>(tested_logger_name, std::make_shared<spdlog::sinks::null_sink_st>()); auto logger = std::make_shared<spdlog::logger>(tested_logger_name, std::make_shared<spdlog::sinks::null_sink_st>());
spdlog::register_logger(logger); spdlog::register_logger(logger);
REQUIRE(spdlog::get(tested_logger_name) != nullptr); REQUIRE(spdlog::get(tested_logger_name) != nullptr);
// Throw if registring existing name // Throw if registering existing name
REQUIRE_THROWS_AS(spdlog::create<spdlog::sinks::null_sink_mt>(tested_logger_name), spdlog::spdlog_ex); REQUIRE_THROWS_AS(spdlog::create<spdlog::sinks::null_sink_mt>(tested_logger_name), spdlog::spdlog_ex);
} }
#endif #endif

@ -9,18 +9,12 @@ void prepare_logdir()
{ {
spdlog::drop_all(); spdlog::drop_all();
#ifdef _WIN32 #ifdef _WIN32
system("if not exist logs mkdir logs"); system("rmdir /S /Q test_logs");
system("del /F /Q logs\\*");
#else #else
auto rv = system("mkdir -p logs"); auto rv = system("rm -rf test_logs");
if (rv != 0) if (rv != 0)
{ {
throw std::runtime_error("Failed to mkdir -p logs"); throw std::runtime_error("Failed to rm -rf test_logs");
}
rv = system("rm -f logs/*");
if (rv != 0)
{
throw std::runtime_error("Failed to rm -f logs/*");
} }
#endif #endif
} }

Loading…
Cancel
Save