Merge branch 'gabime:v1.x' into v1.x

This commit is contained in:
mmanoj 2023-05-04 14:20:40 +05:30 committed by GitHub
commit a406f27c65
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
30 changed files with 356 additions and 18162 deletions

View File

@ -9,14 +9,13 @@ jobs:
run: run:
shell: bash shell: bash
strategy: strategy:
fail-fast: false
matrix: matrix:
config: config:
- { compiler: gcc, version: 4.9, build_type: Release, cppstd: 11, examples: OFF, asan: OFF }
- { compiler: gcc, version: 7, build_type: Release, cppstd: 11 } - { compiler: gcc, version: 7, build_type: Release, cppstd: 11 }
- { compiler: gcc, version: 9, build_type: Release, cppstd: 17 } - { compiler: gcc, version: 9, build_type: Release, cppstd: 17 }
- { compiler: gcc, version: 11, build_type: Debug, cppstd: 20 } - { compiler: gcc, version: 11, build_type: Debug, cppstd: 20 }
- { compiler: gcc, version: 12, build_type: Release, cppstd: 20 } - { compiler: gcc, version: 12, build_type: Release, cppstd: 20 }
- { compiler: clang, version: 3.5, build_type: Release, cppstd: 11, asan: OFF }
- { compiler: clang, version: 10, build_type: Release, cppstd: 11 } - { compiler: clang, version: 10, build_type: Release, cppstd: 11 }
- { compiler: clang, version: 10, build_type: Debug, cppstd: 17, asan: OFF } - { compiler: clang, version: 10, build_type: Debug, cppstd: 17, asan: OFF }
- { compiler: clang, version: 12, build_type: Debug, cppstd: 17, asan: OFF } - { compiler: clang, version: 12, build_type: Debug, cppstd: 17, asan: OFF }
@ -28,7 +27,7 @@ jobs:
- uses: actions/checkout@main - uses: actions/checkout@main
- name: Setup - name: Setup
run: | run: |
apt-get update && apt-get install -y curl apt-get update && apt-get install -y curl git pkg-config libsystemd-dev
CMAKE_VERSION="3.24.2" CMAKE_VERSION="3.24.2"
curl -sSL https://github.com/Kitware/CMake/releases/download/v${CMAKE_VERSION}/cmake-${CMAKE_VERSION}-linux-x86_64.sh -o install-cmake.sh curl -sSL https://github.com/Kitware/CMake/releases/download/v${CMAKE_VERSION}/cmake-${CMAKE_VERSION}-linux-x86_64.sh -o install-cmake.sh
chmod +x install-cmake.sh chmod +x install-cmake.sh

View File

@ -25,7 +25,10 @@ endif()
# --------------------------------------------------------------------------------------- # ---------------------------------------------------------------------------------------
# Compiler config # Compiler config
# --------------------------------------------------------------------------------------- # ---------------------------------------------------------------------------------------
if(NOT CMAKE_CXX_STANDARD) if(SPDLOG_USE_STD_FORMAT)
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
elseif(NOT CMAKE_CXX_STANDARD)
set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_STANDARD_REQUIRED ON)
endif() endif()
@ -176,7 +179,6 @@ if(SPDLOG_SYSTEM_INCLUDES)
set(SPDLOG_INCLUDES_LEVEL "SYSTEM") set(SPDLOG_INCLUDES_LEVEL "SYSTEM")
endif() endif()
target_compile_definitions(spdlog PUBLIC SPDLOG_COMPILED_LIB) target_compile_definitions(spdlog PUBLIC SPDLOG_COMPILED_LIB)
target_include_directories(spdlog ${SPDLOG_INCLUDES_LEVEL} PUBLIC "$<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/include>" target_include_directories(spdlog ${SPDLOG_INCLUDES_LEVEL} PUBLIC "$<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/include>"
"$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>") "$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>")
@ -257,11 +259,6 @@ if(SPDLOG_NO_EXCEPTIONS AND NOT MSVC)
target_compile_options(spdlog PRIVATE -fno-exceptions) target_compile_options(spdlog PRIVATE -fno-exceptions)
endif() endif()
if(SPDLOG_USE_STD_FORMAT)
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
endif()
# --------------------------------------------------------------------------------------- # ---------------------------------------------------------------------------------------
# Build binaries # Build binaries
# --------------------------------------------------------------------------------------- # ---------------------------------------------------------------------------------------

View File

@ -2,42 +2,6 @@ version: 1.0.{build}
image: Visual Studio 2017 image: Visual Studio 2017
environment: environment:
matrix: matrix:
- GENERATOR: '"Visual Studio 14 2015"'
BUILD_TYPE: Debug
BUILD_SHARED: 'OFF'
FATAL_ERRORS: 'ON'
WCHAR: 'OFF'
WCHAR_FILES: 'OFF'
BUILD_EXAMPLE: 'ON'
USE_STD_FORMAT: 'OFF'
CXX_STANDARD: 11
- GENERATOR: '"Visual Studio 14 2015"'
BUILD_TYPE: Release
BUILD_SHARED: 'OFF'
FATAL_ERRORS: 'ON'
WCHAR: 'ON'
WCHAR_FILES: 'OFF'
BUILD_EXAMPLE: 'ON'
USE_STD_FORMAT: 'OFF'
CXX_STANDARD: 11
- GENERATOR: '"Visual Studio 14 2015 Win64"'
BUILD_TYPE: Debug
BUILD_SHARED: 'OFF'
FATAL_ERRORS: 'ON'
WCHAR: 'ON'
WCHAR_FILES: 'OFF'
BUILD_EXAMPLE: 'ON'
USE_STD_FORMAT: 'OFF'
CXX_STANDARD: 11
- GENERATOR: '"Visual Studio 14 2015 Win64"'
BUILD_TYPE: Release
BUILD_SHARED: 'OFF'
FATAL_ERRORS: 'ON'
WCHAR: 'ON'
WCHAR_FILES: 'OFF'
BUILD_EXAMPLE: 'ON'
USE_STD_FORMAT: 'OFF'
CXX_STANDARD: 11
- GENERATOR: '"Visual Studio 15 2017 Win64"' - GENERATOR: '"Visual Studio 15 2017 Win64"'
BUILD_TYPE: Debug BUILD_TYPE: Debug
BUILD_SHARED: 'OFF' BUILD_SHARED: 'OFF'
@ -119,7 +83,7 @@ build_script:
cmake --build . --config %BUILD_TYPE% cmake --build . --config %BUILD_TYPE%
before_test: before_test:
- set PATH=%PATH%;C:\projects\spdlog\build\%BUILD_TYPE% - set PATH=%PATH%;C:\projects\spdlog\build\_deps\catch2-build\src\%BUILD_TYPE%;C:\projects\spdlog\build\%BUILD_TYPE%
test_script: test_script:
- C:\projects\spdlog\build\tests\%BUILD_TYPE%\spdlog-utests.exe - C:\projects\spdlog\build\tests\%BUILD_TYPE%\spdlog-utests.exe

View File

@ -12,7 +12,7 @@ endif()
# Example of using pre-compiled library # Example of using pre-compiled library
# --------------------------------------------------------------------------------------- # ---------------------------------------------------------------------------------------
add_executable(example example.cpp) add_executable(example example.cpp)
target_link_libraries(example PRIVATE spdlog::spdlog) target_link_libraries(example PRIVATE spdlog::spdlog $<$<BOOL:${MINGW}>:ws2_32>)
# --------------------------------------------------------------------------------------- # ---------------------------------------------------------------------------------------
# Example of using header-only library # Example of using header-only library

View File

@ -279,7 +279,7 @@ struct fmt::formatter<my_type> : fmt::formatter<std::string>
{ {
auto format(my_type my, format_context &ctx) -> decltype(ctx.out()) auto format(my_type my, format_context &ctx) -> decltype(ctx.out())
{ {
return format_to(ctx.out(), "[my_type i={}]", my.i); return fmt::format_to(ctx.out(), "[my_type i={}]", my.i);
} }
}; };

View File

@ -173,12 +173,19 @@ using format_string_t = fmt::format_string<Args...>;
template<class T> template<class T>
using remove_cvref_t = typename std::remove_cv<typename std::remove_reference<T>::type>::type; using remove_cvref_t = typename std::remove_cv<typename std::remove_reference<T>::type>::type;
template <typename Char>
#if FMT_VERSION >= 90101
using fmt_runtime_string = fmt::runtime_format_string<Char>;
#else
using fmt_runtime_string = fmt::basic_runtime<Char>;
#endif
// clang doesn't like SFINAE disabled constructor in std::is_convertible<> so have to repeat the condition from basic_format_string here, // clang doesn't like SFINAE disabled constructor in std::is_convertible<> so have to repeat the condition from basic_format_string here,
// in addition, fmt::basic_runtime<Char> is only convertible to basic_format_string<Char> but not basic_string_view<Char> // in addition, fmt::basic_runtime<Char> is only convertible to basic_format_string<Char> but not basic_string_view<Char>
template<class T, class Char = char> template<class T, class Char = char>
struct is_convertible_to_basic_format_string struct is_convertible_to_basic_format_string
: std::integral_constant<bool, : std::integral_constant<bool,
std::is_convertible<T, fmt::basic_string_view<Char>>::value || std::is_same<remove_cvref_t<T>, fmt::basic_runtime<Char>>::value> std::is_convertible<T, fmt::basic_string_view<Char>>::value || std::is_same<remove_cvref_t<T>, fmt_runtime_string<Char>>::value>
{}; {};
# if defined(SPDLOG_WCHAR_FILENAMES) || defined(SPDLOG_WCHAR_TO_UTF8_SUPPORT) # if defined(SPDLOG_WCHAR_FILENAMES) || defined(SPDLOG_WCHAR_TO_UTF8_SUPPORT)

View File

@ -34,6 +34,7 @@
# if defined(SPDLOG_WCHAR_TO_UTF8_SUPPORT) || defined(SPDLOG_WCHAR_FILENAMES) # if defined(SPDLOG_WCHAR_TO_UTF8_SUPPORT) || defined(SPDLOG_WCHAR_FILENAMES)
# include <limits> # include <limits>
# include <cassert>
# endif # endif
# include <direct.h> // for _mkdir/_wmkdir # include <direct.h> // for _mkdir/_wmkdir
@ -61,6 +62,10 @@
#endif // unix #endif // unix
#if defined __APPLE__
# include <AvailabilityMacros.h>
#endif
#ifndef __has_feature // Clang - feature checking macros. #ifndef __has_feature // Clang - feature checking macros.
# define __has_feature(x) 0 // Compatibility with non-clang compilers. # define __has_feature(x) 0 // Compatibility with non-clang compilers.
#endif #endif
@ -354,7 +359,19 @@ SPDLOG_INLINE size_t _thread_id() SPDLOG_NOEXCEPT
return static_cast<size_t>(::thr_self()); return static_cast<size_t>(::thr_self());
#elif __APPLE__ #elif __APPLE__
uint64_t tid; uint64_t tid;
// There is no pthread_threadid_np prior to 10.6, and it is not supported on any PPC,
// including 10.6.8 Rosetta. __POWERPC__ is Apple-specific define encompassing ppc and ppc64.
# if (MAC_OS_X_VERSION_MAX_ALLOWED < 1060) || defined(__POWERPC__)
tid = pthread_mach_thread_np(pthread_self());
# elif MAC_OS_X_VERSION_MIN_REQUIRED < 1060
if (&pthread_threadid_np) {
pthread_threadid_np(nullptr, &tid); pthread_threadid_np(nullptr, &tid);
} else {
tid = pthread_mach_thread_np(pthread_self());
}
# else
pthread_threadid_np(nullptr, &tid);
# endif
return static_cast<size_t>(tid); return static_cast<size_t>(tid);
#else // Default to standard C++11 (other Unix) #else // Default to standard C++11 (other Unix)
return static_cast<size_t>(std::hash<std::thread::id>()(std::this_thread::get_id())); return static_cast<size_t>(std::hash<std::thread::id>()(std::this_thread::get_id()));
@ -501,20 +518,16 @@ SPDLOG_INLINE void utf8_to_wstrbuf(string_view_t str, wmemory_buf_t &target)
return; return;
} }
int result_size = static_cast<int>(target.capacity()); // find the size to allocate for the result buffer
if (str_size + 1 > result_size) int result_size = ::MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, str.data(), str_size, NULL, 0);
{
result_size = ::MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, str.data(), str_size, NULL, 0);
}
if (result_size > 0) if (result_size > 0)
{ {
target.resize(result_size); target.resize(result_size);
result_size = ::MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, str.data(), str_size, target.data(), result_size); result_size = ::MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, str.data(), str_size, target.data(), result_size);
if (result_size > 0) if (result_size > 0)
{ {
target.resize(result_size); assert(result_size == target.size());
return; return;
} }
} }

View File

@ -219,8 +219,9 @@ SPDLOG_INLINE void registry::flush_all()
SPDLOG_INLINE void registry::drop(const std::string &logger_name) SPDLOG_INLINE void registry::drop(const std::string &logger_name)
{ {
std::lock_guard<std::mutex> lock(logger_map_mutex_); std::lock_guard<std::mutex> lock(logger_map_mutex_);
auto is_default_logger = default_logger_ && default_logger_->name() == logger_name;
loggers_.erase(logger_name); loggers_.erase(logger_name);
if (default_logger_ && default_logger_->name() == logger_name) if (is_default_logger)
{ {
default_logger_.reset(); default_logger_.reset();
} }
@ -287,6 +288,14 @@ SPDLOG_INLINE registry &registry::instance()
return s_instance; return s_instance;
} }
SPDLOG_INLINE void registry::apply_logger_env_levels(std::shared_ptr<logger> new_logger)
{
std::lock_guard<std::mutex> lock(logger_map_mutex_);
auto it = log_levels_.find(new_logger->name());
auto new_level = it != log_levels_.end() ? it->second : global_log_level_;
new_logger->set_level(new_level);
}
SPDLOG_INLINE void registry::throw_if_exists_(const std::string &logger_name) SPDLOG_INLINE void registry::throw_if_exists_(const std::string &logger_name)
{ {
if (loggers_.find(logger_name) != loggers_.end()) if (loggers_.find(logger_name) != loggers_.end())

View File

@ -91,6 +91,8 @@ public:
static registry &instance(); static registry &instance();
void apply_logger_env_levels(std::shared_ptr<logger> new_logger);
private: private:
registry(); registry();
~registry(); ~registry();

View File

@ -15,9 +15,11 @@
#include <stdio.h> #include <stdio.h>
#include <string> #include <string>
#if defined(_MSC_VER)
# pragma comment(lib, "Ws2_32.lib") # pragma comment(lib, "Ws2_32.lib")
# pragma comment(lib, "Mswsock.lib") # pragma comment(lib, "Mswsock.lib")
# pragma comment(lib, "AdvApi32.lib") # pragma comment(lib, "AdvApi32.lib")
#endif
namespace spdlog { namespace spdlog {
namespace details { namespace details {
@ -25,7 +27,7 @@ class udp_client
{ {
static constexpr int TX_BUFFER_SIZE = 1024 * 10; static constexpr int TX_BUFFER_SIZE = 1024 * 10;
SOCKET socket_ = INVALID_SOCKET; SOCKET socket_ = INVALID_SOCKET;
sockaddr_in addr_ = {0}; sockaddr_in addr_ = {};
static void init_winsock_() static void init_winsock_()
{ {

View File

@ -196,7 +196,7 @@ struct formatter<spdlog::details::dump_info<T>, char>
continue; continue;
} }
if (put_delimiters) if (put_delimiters && i != the_range.get_begin())
{ {
*inserter++ = delimiter; *inserter++ = delimiter;
} }

View File

@ -0,0 +1,133 @@
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
#pragma once
//
// Custom sink for kafka
// Building and using requires librdkafka library.
// For building librdkafka library check the url below
// https://github.com/confluentinc/librdkafka
//
#include <spdlog/common.h>
#include "spdlog/details/log_msg.h"
#include "spdlog/sinks/base_sink.h"
#include "spdlog/details/synchronous_factory.h"
#include "spdlog/details/null_mutex.h"
#include "spdlog/async.h"
#include <mutex>
// kafka header
#include <librdkafka/rdkafkacpp.h>
namespace spdlog {
namespace sinks {
struct kafka_sink_config
{
std::string server_addr;
std::string produce_topic;
int32_t flush_timeout_ms = 1000;
kafka_sink_config(std::string addr, std::string topic, int flush_timeout_ms = 1000)
: server_addr{std::move(addr)}
,produce_topic{std::move(topic)}
,flush_timeout_ms(flush_timeout_ms)
{}
};
template<typename Mutex>
class kafka_sink : public base_sink<Mutex>
{
public:
kafka_sink(kafka_sink_config config)
: config_{std::move(config)}
{
try
{
std::string errstr;
conf_.reset(RdKafka::Conf::create(RdKafka::Conf::CONF_GLOBAL));
RdKafka::Conf::ConfResult confRes = conf_->set("bootstrap.servers", config_.server_addr, errstr);
if (confRes != RdKafka::Conf::CONF_OK)
{
throw_spdlog_ex(fmt_lib::format("conf set bootstrap.servers failed err:{}", errstr));
}
tconf_.reset(RdKafka::Conf::create(RdKafka::Conf::CONF_TOPIC));
if (tconf_ == nullptr)
{
throw_spdlog_ex(fmt_lib::format("create topic config failed"));
}
producer_.reset(RdKafka::Producer::create(conf_.get(), errstr));
if (producer_ == nullptr)
{
throw_spdlog_ex(fmt_lib::format("create producer failed err:{}", errstr));
}
topic_.reset(RdKafka::Topic::create(producer_.get(), config_.produce_topic, tconf_.get(), errstr));
if (topic_ == nullptr)
{
throw_spdlog_ex(fmt_lib::format("create topic failed err:{}", errstr));
}
}
catch (const std::exception &e)
{
throw_spdlog_ex(fmt_lib::format("error create kafka instance: {}", e.what()));
}
}
~kafka_sink()
{
producer_->flush(config_.flush_timeout_ms);
}
protected:
void sink_it_(const details::log_msg &msg) override
{
producer_->produce(topic_.get(), 0, RdKafka::Producer::RK_MSG_COPY, (void *)msg.payload.data(), msg.payload.size(), NULL, NULL);
}
void flush_() override
{
producer_->flush(config_.flush_timeout_ms);
}
private:
kafka_sink_config config_;
std::unique_ptr<RdKafka::Producer> producer_ = nullptr;
std::unique_ptr<RdKafka::Conf> conf_ = nullptr;
std::unique_ptr<RdKafka::Conf> tconf_ = nullptr;
std::unique_ptr<RdKafka::Topic> topic_ = nullptr;
};
using kafka_sink_mt = kafka_sink<std::mutex>;
using kafka_sink_st = kafka_sink<spdlog::details::null_mutex>;
} // namespace sinks
template<typename Factory = spdlog::synchronous_factory>
inline std::shared_ptr<logger> kafka_logger_mt(const std::string &logger_name, spdlog::sinks::kafka_sink_config config)
{
return Factory::template create<sinks::kafka_sink_mt>(logger_name, config);
}
template<typename Factory = spdlog::synchronous_factory>
inline std::shared_ptr<logger> kafka_logger_st(const std::string &logger_name, spdlog::sinks::kafka_sink_config config)
{
return Factory::template create<sinks::kafka_sink_st>(logger_name, config);
}
template<typename Factory = spdlog::async_factory>
inline std::shared_ptr<spdlog::logger> kafka_logger_async_mt(std::string logger_name, spdlog::sinks::kafka_sink_config config)
{
return Factory::template create<sinks::kafka_sink_mt>(logger_name, config);
}
template<typename Factory = spdlog::async_factory>
inline std::shared_ptr<spdlog::logger> kafka_logger_async_st(std::string logger_name, spdlog::sinks::kafka_sink_config config)
{
return Factory::template create<sinks::kafka_sink_st>(logger_name, config);
}
} // namespace spdlog

View File

@ -7,13 +7,20 @@
#if defined(_WIN32) #if defined(_WIN32)
# include <spdlog/details/null_mutex.h> # include <spdlog/details/null_mutex.h>
# if defined(SPDLOG_WCHAR_TO_UTF8_SUPPORT)
# include <spdlog/details/os.h>
# endif
# include <spdlog/sinks/base_sink.h> # include <spdlog/sinks/base_sink.h>
# include <mutex> # include <mutex>
# include <string> # include <string>
// Avoid including windows.h (https://stackoverflow.com/a/30741042) // Avoid including windows.h (https://stackoverflow.com/a/30741042)
#if defined(SPDLOG_WCHAR_TO_UTF8_SUPPORT)
extern "C" __declspec(dllimport) void __stdcall OutputDebugStringW(const wchar_t *lpOutputString);
#else
extern "C" __declspec(dllimport) void __stdcall OutputDebugStringA(const char *lpOutputString); extern "C" __declspec(dllimport) void __stdcall OutputDebugStringA(const char *lpOutputString);
#endif
extern "C" __declspec(dllimport) int __stdcall IsDebuggerPresent(); extern "C" __declspec(dllimport) int __stdcall IsDebuggerPresent();
namespace spdlog { namespace spdlog {
@ -38,8 +45,14 @@ protected:
} }
memory_buf_t formatted; memory_buf_t formatted;
base_sink<Mutex>::formatter_->format(msg, formatted); base_sink<Mutex>::formatter_->format(msg, formatted);
formatted.push_back('\0'); // add a null terminator for OutputDebugStringA formatted.push_back('\0'); // add a null terminator for OutputDebugString
#if defined(SPDLOG_WCHAR_TO_UTF8_SUPPORT)
wmemory_buf_t wformatted;
details::os::utf8_to_wstrbuf(string_view_t(formatted.data(), formatted.size()), wformatted);
OutputDebugStringW(wformatted.data());
#else
OutputDebugStringA(formatted.data()); OutputDebugStringA(formatted.data());
#endif
} }
void flush_() override {} void flush_() override {}

View File

@ -50,7 +50,7 @@ public:
{ {
memory_buf_t formatted; memory_buf_t formatted;
base_sink<Mutex>::formatter_->format(q_.at(i), formatted); base_sink<Mutex>::formatter_->format(q_.at(i), formatted);
ret.push_back(std::move(SPDLOG_BUF_TO_STRING(formatted))); ret.push_back(SPDLOG_BUF_TO_STRING(formatted));
} }
return ret; return ret;
} }

View File

@ -60,7 +60,6 @@ SPDLOG_INLINE void stdout_sink_base<ConsoleMutex>::log(const details::log_msg &m
std::lock_guard<mutex_t> lock(mutex_); std::lock_guard<mutex_t> lock(mutex_);
memory_buf_t formatted; memory_buf_t formatted;
formatter_->format(msg, formatted); formatter_->format(msg, formatted);
::fflush(file_); // flush in case there is something in this file_ already
auto size = static_cast<DWORD>(formatted.size()); auto size = static_cast<DWORD>(formatted.size());
DWORD bytes_written = 0; DWORD bytes_written = 0;
bool ok = ::WriteFile(handle_, formatted.data(), size, &bytes_written, nullptr) != 0; bool ok = ::WriteFile(handle_, formatted.data(), size, &bytes_written, nullptr) != 0;
@ -73,8 +72,8 @@ SPDLOG_INLINE void stdout_sink_base<ConsoleMutex>::log(const details::log_msg &m
memory_buf_t formatted; memory_buf_t formatted;
formatter_->format(msg, formatted); formatter_->format(msg, formatted);
::fwrite(formatted.data(), sizeof(char), formatted.size(), file_); ::fwrite(formatted.data(), sizeof(char), formatted.size(), file_);
::fflush(file_); // flush every line to terminal
#endif // WIN32 #endif // WIN32
::fflush(file_); // flush every line to terminal
} }
template<typename ConsoleMutex> template<typename ConsoleMutex>

View File

@ -4,6 +4,7 @@
#pragma once #pragma once
#include <spdlog/sinks/base_sink.h> #include <spdlog/sinks/base_sink.h>
#include <spdlog/details/os.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>
@ -75,11 +76,17 @@ protected:
{ {
// Note: function call inside '()' to avoid macro expansion // Note: function call inside '()' to avoid macro expansion
err = (sd_journal_send)("MESSAGE=%.*s", static_cast<int>(length), payload.data(), "PRIORITY=%d", syslog_level(msg.level), err = (sd_journal_send)("MESSAGE=%.*s", static_cast<int>(length), payload.data(), "PRIORITY=%d", syslog_level(msg.level),
#ifndef SPDLOG_NO_THREAD_ID
"TID=%zu", details::os::thread_id(),
#endif
"SYSLOG_IDENTIFIER=%.*s", static_cast<int>(syslog_identifier.size()), syslog_identifier.data(), nullptr); "SYSLOG_IDENTIFIER=%.*s", static_cast<int>(syslog_identifier.size()), syslog_identifier.data(), nullptr);
} }
else else
{ {
err = (sd_journal_send)("MESSAGE=%.*s", static_cast<int>(length), payload.data(), "PRIORITY=%d", syslog_level(msg.level), err = (sd_journal_send)("MESSAGE=%.*s", static_cast<int>(length), payload.data(), "PRIORITY=%d", syslog_level(msg.level),
#ifndef SPDLOG_NO_THREAD_ID
"TID=%zu", details::os::thread_id(),
#endif
"SYSLOG_IDENTIFIER=%.*s", static_cast<int>(syslog_identifier.size()), syslog_identifier.data(), "CODE_FILE=%s", "SYSLOG_IDENTIFIER=%.*s", static_cast<int>(syslog_identifier.size()), syslog_identifier.data(), "CODE_FILE=%s",
msg.source.filename, "CODE_LINE=%d", msg.source.line, "CODE_FUNC=%s", msg.source.funcname, nullptr); msg.source.filename, "CODE_LINE=%d", msg.source.line, "CODE_FUNC=%s", msg.source.funcname, nullptr);
} }

View File

@ -117,4 +117,9 @@ SPDLOG_INLINE void set_default_logger(std::shared_ptr<spdlog::logger> default_lo
details::registry::instance().set_default_logger(std::move(default_logger)); details::registry::instance().set_default_logger(std::move(default_logger));
} }
SPDLOG_INLINE void apply_logger_env_levels(std::shared_ptr<logger> logger)
{
details::registry::instance().apply_logger_env_levels(std::move(logger));
}
} // namespace spdlog } // namespace spdlog

View File

@ -131,6 +131,15 @@ SPDLOG_API spdlog::logger *default_logger_raw();
SPDLOG_API void set_default_logger(std::shared_ptr<spdlog::logger> default_logger); SPDLOG_API void set_default_logger(std::shared_ptr<spdlog::logger> default_logger);
// Initialize logger level based on environment configs.
//
// Useful for applying SPDLOG_LEVEL to manually created loggers.
//
// Example:
// auto mylogger = std::make_shared<spdlog::logger>("mylogger", ...);
// spdlog::apply_logger_env_levels(mylogger);
SPDLOG_API void apply_logger_env_levels(std::shared_ptr<logger> logger);
template<typename... Args> template<typename... Args>
inline void log(source_loc source, level::level_enum lvl, format_string_t<Args...> fmt, Args &&... args) inline void log(source_loc source, level::level_enum lvl, format_string_t<Args...> fmt, Args &&... args)
{ {

View File

@ -13,6 +13,20 @@ if(PkgConfig_FOUND)
pkg_check_modules(systemd libsystemd) pkg_check_modules(systemd libsystemd)
endif() endif()
find_package(Catch2 3 QUIET)
if (Catch2_FOUND)
message(STATUS "Packaged version of Catch will be used.")
else()
message(STATUS "Bundled version of Catch will be downloaded and used.")
include(FetchContent)
FetchContent_Declare(
Catch2
GIT_REPOSITORY https://github.com/catchorg/Catch2.git
GIT_TAG v3.3.2
)
FetchContent_MakeAvailable(Catch2)
endif()
set(SPDLOG_UTESTS_SOURCES set(SPDLOG_UTESTS_SOURCES
test_file_helper.cpp test_file_helper.cpp
test_file_logging.cpp test_file_logging.cpp
@ -53,6 +67,7 @@ function(spdlog_prepare_test test_target spdlog_lib)
if(systemd_FOUND) if(systemd_FOUND)
target_link_libraries(${test_target} PRIVATE ${systemd_LIBRARIES}) target_link_libraries(${test_target} PRIVATE ${systemd_LIBRARIES})
endif() endif()
target_link_libraries(${test_target} PRIVATE Catch2::Catch2WithMain)
if(SPDLOG_SANITIZE_ADDRESS) if(SPDLOG_SANITIZE_ADDRESS)
spdlog_enable_sanitizer(${test_target}) spdlog_enable_sanitizer(${test_target})
endif() endif()

File diff suppressed because it is too large Load Diff

View File

@ -1,23 +0,0 @@
Boost Software License - Version 1.0 - August 17th, 2003
Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the
Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following:
The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer,
must be included in all copies of the Software, in whole or in part, and
all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by
a source language processor.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.

View File

@ -4,7 +4,7 @@
# pragma GCC diagnostic push # pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wmaybe-uninitialized" // Workaround for GCC 12 # pragma GCC diagnostic ignored "-Wmaybe-uninitialized" // Workaround for GCC 12
#endif #endif
#include "catch.hpp" #include <catch2/catch_all.hpp>
#if defined(__GNUC__) && __GNUC__ == 12 #if defined(__GNUC__) && __GNUC__ == 12
# pragma GCC diagnostic pop # pragma GCC diagnostic pop
#endif #endif

View File

@ -3,8 +3,7 @@
# pragma GCC diagnostic ignored "-Wmaybe-uninitialized" // Workaround for GCC 12 # pragma GCC diagnostic ignored "-Wmaybe-uninitialized" // Workaround for GCC 12
#endif #endif
#define CATCH_CONFIG_MAIN #include <catch2/catch_all.hpp>
#include "catch.hpp"
#if defined(__GNUC__) && __GNUC__ == 12 #if defined(__GNUC__) && __GNUC__ == 12
# pragma GCC diagnostic pop # pragma GCC diagnostic pop

View File

@ -7,7 +7,7 @@
#include "spdlog/async.h" #include "spdlog/async.h"
#include "spdlog/common.h" #include "spdlog/common.h"
TEST_CASE("custom_callback_logger", "[custom_callback_logger]]") TEST_CASE("custom_callback_logger", "[custom_callback_logger]")
{ {
std::vector<std::string> lines; std::vector<std::string> lines;
spdlog::pattern_formatter formatter; spdlog::pattern_formatter formatter;

View File

@ -87,19 +87,19 @@ TEST_CASE("daily_logger with custom calculator", "[daily_logger]")
* File name calculations * File name calculations
*/ */
TEST_CASE("rotating_file_sink::calc_filename1", "[rotating_file_sink]]") TEST_CASE("rotating_file_sink::calc_filename1", "[rotating_file_sink]")
{ {
auto filename = spdlog::sinks::rotating_file_sink_st::calc_filename(SPDLOG_FILENAME_T("rotated.txt"), 3); auto filename = spdlog::sinks::rotating_file_sink_st::calc_filename(SPDLOG_FILENAME_T("rotated.txt"), 3);
REQUIRE(filename == SPDLOG_FILENAME_T("rotated.3.txt")); REQUIRE(filename == SPDLOG_FILENAME_T("rotated.3.txt"));
} }
TEST_CASE("rotating_file_sink::calc_filename2", "[rotating_file_sink]]") TEST_CASE("rotating_file_sink::calc_filename2", "[rotating_file_sink]")
{ {
auto filename = spdlog::sinks::rotating_file_sink_st::calc_filename(SPDLOG_FILENAME_T("rotated"), 3); auto filename = spdlog::sinks::rotating_file_sink_st::calc_filename(SPDLOG_FILENAME_T("rotated"), 3);
REQUIRE(filename == SPDLOG_FILENAME_T("rotated.3")); REQUIRE(filename == SPDLOG_FILENAME_T("rotated.3"));
} }
TEST_CASE("rotating_file_sink::calc_filename3", "[rotating_file_sink]]") TEST_CASE("rotating_file_sink::calc_filename3", "[rotating_file_sink]")
{ {
auto filename = spdlog::sinks::rotating_file_sink_st::calc_filename(SPDLOG_FILENAME_T("rotated.txt"), 0); auto filename = spdlog::sinks::rotating_file_sink_st::calc_filename(SPDLOG_FILENAME_T("rotated.txt"), 0);
REQUIRE(filename == SPDLOG_FILENAME_T("rotated.txt")); REQUIRE(filename == SPDLOG_FILENAME_T("rotated.txt"));
@ -110,7 +110,7 @@ TEST_CASE("rotating_file_sink::calc_filename3", "[rotating_file_sink]]")
# include <regex> # include <regex>
TEST_CASE("daily_file_sink::daily_filename_calculator", "[daily_file_sink]]") TEST_CASE("daily_file_sink::daily_filename_calculator", "[daily_file_sink]")
{ {
// daily_YYYY-MM-DD_hh-mm.txt // daily_YYYY-MM-DD_hh-mm.txt
auto filename = auto filename =
@ -123,7 +123,7 @@ TEST_CASE("daily_file_sink::daily_filename_calculator", "[daily_file_sink]]")
} }
#endif #endif
TEST_CASE("daily_file_sink::daily_filename_format_calculator", "[daily_file_sink]]") TEST_CASE("daily_file_sink::daily_filename_format_calculator", "[daily_file_sink]")
{ {
std::tm tm = spdlog::details::os::localtime(); std::tm tm = spdlog::details::os::localtime();
// example-YYYY-MM-DD.log // example-YYYY-MM-DD.log

View File

@ -21,8 +21,10 @@ protected:
throw std::runtime_error("some error happened during flush"); throw std::runtime_error("some error happened during flush");
} }
}; };
struct custom_ex {};
TEST_CASE("default_error_handler", "[errors]]") #if !defined(SPDLOG_USE_STD_FORMAT) // std formt doesn't fully support tuntime strings
TEST_CASE("default_error_handler", "[errors]")
{ {
prepare_logdir(); prepare_logdir();
spdlog::filename_t filename = SPDLOG_FILENAME_T(SIMPLE_LOG); spdlog::filename_t filename = SPDLOG_FILENAME_T(SIMPLE_LOG);
@ -32,15 +34,13 @@ TEST_CASE("default_error_handler", "[errors]]")
logger->info(SPDLOG_FMT_RUNTIME("Test message {} {}"), 1); logger->info(SPDLOG_FMT_RUNTIME("Test message {} {}"), 1);
logger->info("Test message {}", 2); logger->info("Test message {}", 2);
logger->flush(); logger->flush();
using spdlog::details::os::default_eol; using spdlog::details::os::default_eol;
REQUIRE(file_contents(SIMPLE_LOG) == spdlog::fmt_lib::format("Test message 2{}", default_eol)); REQUIRE(file_contents(SIMPLE_LOG) == spdlog::fmt_lib::format("Test message 2{}", default_eol));
REQUIRE(count_lines(SIMPLE_LOG) == 1); REQUIRE(count_lines(SIMPLE_LOG) == 1);
} }
struct custom_ex
{}; TEST_CASE("custom_error_handler", "[errors]")
TEST_CASE("custom_error_handler", "[errors]]")
{ {
prepare_logdir(); prepare_logdir();
spdlog::filename_t filename = SPDLOG_FILENAME_T(SIMPLE_LOG); spdlog::filename_t filename = SPDLOG_FILENAME_T(SIMPLE_LOG);
@ -53,8 +53,9 @@ TEST_CASE("custom_error_handler", "[errors]]")
logger->info("Good message #2"); logger->info("Good message #2");
require_message_count(SIMPLE_LOG, 2); require_message_count(SIMPLE_LOG, 2);
} }
#endif
TEST_CASE("default_error_handler2", "[errors]]") TEST_CASE("default_error_handler2", "[errors]")
{ {
spdlog::drop_all(); spdlog::drop_all();
auto logger = spdlog::create<failing_sink>("failed_logger"); auto logger = spdlog::create<failing_sink>("failed_logger");
@ -62,7 +63,7 @@ TEST_CASE("default_error_handler2", "[errors]]")
REQUIRE_THROWS_AS(logger->info("Some message"), custom_ex); REQUIRE_THROWS_AS(logger->info("Some message"), custom_ex);
} }
TEST_CASE("flush_error_handler", "[errors]]") TEST_CASE("flush_error_handler", "[errors]")
{ {
spdlog::drop_all(); spdlog::drop_all();
auto logger = spdlog::create<failing_sink>("failed_logger"); auto logger = spdlog::create<failing_sink>("failed_logger");
@ -70,7 +71,8 @@ TEST_CASE("flush_error_handler", "[errors]]")
REQUIRE_THROWS_AS(logger->flush(), custom_ex); REQUIRE_THROWS_AS(logger->flush(), custom_ex);
} }
TEST_CASE("async_error_handler", "[errors]]") #if !defined(SPDLOG_USE_STD_FORMAT)
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");
@ -96,9 +98,10 @@ TEST_CASE("async_error_handler", "[errors]]")
require_message_count(SIMPLE_ASYNC_LOG, 2); require_message_count(SIMPLE_ASYNC_LOG, 2);
REQUIRE(file_contents("test_logs/custom_err.txt") == err_msg); REQUIRE(file_contents("test_logs/custom_err.txt") == err_msg);
} }
#endif
// Make sure async error handler is executed // Make sure async error handler is executed
TEST_CASE("async_error_handler2", "[errors]]") 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");

View File

@ -15,7 +15,7 @@ static void write_with_helper(file_helper &helper, size_t howmany)
helper.flush(); helper.flush();
} }
TEST_CASE("file_helper_filename", "[file_helper::filename()]]") TEST_CASE("file_helper_filename", "[file_helper::filename()]")
{ {
prepare_logdir(); prepare_logdir();
@ -25,7 +25,7 @@ TEST_CASE("file_helper_filename", "[file_helper::filename()]]")
REQUIRE(helper.filename() == target_filename); REQUIRE(helper.filename() == target_filename);
} }
TEST_CASE("file_helper_size", "[file_helper::size()]]") TEST_CASE("file_helper_size", "[file_helper::size()]")
{ {
prepare_logdir(); prepare_logdir();
spdlog::filename_t target_filename = SPDLOG_FILENAME_T(TEST_FILENAME); spdlog::filename_t target_filename = SPDLOG_FILENAME_T(TEST_FILENAME);
@ -39,7 +39,7 @@ TEST_CASE("file_helper_size", "[file_helper::size()]]")
REQUIRE(get_filesize(TEST_FILENAME) == expected_size); REQUIRE(get_filesize(TEST_FILENAME) == expected_size);
} }
TEST_CASE("file_helper_reopen", "[file_helper::reopen()]]") TEST_CASE("file_helper_reopen", "[file_helper::reopen()]")
{ {
prepare_logdir(); prepare_logdir();
spdlog::filename_t target_filename = SPDLOG_FILENAME_T(TEST_FILENAME); spdlog::filename_t target_filename = SPDLOG_FILENAME_T(TEST_FILENAME);
@ -51,7 +51,7 @@ TEST_CASE("file_helper_reopen", "[file_helper::reopen()]]")
REQUIRE(helper.size() == 0); REQUIRE(helper.size() == 0);
} }
TEST_CASE("file_helper_reopen2", "[file_helper::reopen(false)]]") TEST_CASE("file_helper_reopen2", "[file_helper::reopen(false)]")
{ {
prepare_logdir(); prepare_logdir();
spdlog::filename_t target_filename = SPDLOG_FILENAME_T(TEST_FILENAME); spdlog::filename_t target_filename = SPDLOG_FILENAME_T(TEST_FILENAME);
@ -78,7 +78,7 @@ static void test_split_ext(const spdlog::filename_t::value_type *fname, const sp
REQUIRE(ext == expected_ext); REQUIRE(ext == expected_ext);
} }
TEST_CASE("file_helper_split_by_extension", "[file_helper::split_by_extension()]]") TEST_CASE("file_helper_split_by_extension", "[file_helper::split_by_extension()]")
{ {
test_split_ext(SPDLOG_FILENAME_T("mylog.txt"), SPDLOG_FILENAME_T("mylog"), SPDLOG_FILENAME_T(".txt")); test_split_ext(SPDLOG_FILENAME_T("mylog.txt"), SPDLOG_FILENAME_T("mylog"), SPDLOG_FILENAME_T(".txt"));
test_split_ext(SPDLOG_FILENAME_T(".mylog.txt"), SPDLOG_FILENAME_T(".mylog"), SPDLOG_FILENAME_T(".txt")); test_split_ext(SPDLOG_FILENAME_T(".mylog.txt"), SPDLOG_FILENAME_T(".mylog"), SPDLOG_FILENAME_T(".txt"));

View File

@ -6,7 +6,7 @@
#define SIMPLE_LOG "test_logs/simple_log" #define SIMPLE_LOG "test_logs/simple_log"
#define ROTATING_LOG "test_logs/rotating_log" #define ROTATING_LOG "test_logs/rotating_log"
TEST_CASE("simple_file_logger", "[simple_logger]]") TEST_CASE("simple_file_logger", "[simple_logger]")
{ {
prepare_logdir(); prepare_logdir();
spdlog::filename_t filename = SPDLOG_FILENAME_T(SIMPLE_LOG); spdlog::filename_t filename = SPDLOG_FILENAME_T(SIMPLE_LOG);
@ -23,7 +23,7 @@ TEST_CASE("simple_file_logger", "[simple_logger]]")
REQUIRE(file_contents(SIMPLE_LOG) == spdlog::fmt_lib::format("Test message 1{}Test message 2{}", default_eol, default_eol)); REQUIRE(file_contents(SIMPLE_LOG) == spdlog::fmt_lib::format("Test message 1{}Test message 2{}", default_eol, default_eol));
} }
TEST_CASE("flush_on", "[flush_on]]") TEST_CASE("flush_on", "[flush_on]")
{ {
prepare_logdir(); prepare_logdir();
spdlog::filename_t filename = SPDLOG_FILENAME_T(SIMPLE_LOG); spdlog::filename_t filename = SPDLOG_FILENAME_T(SIMPLE_LOG);
@ -44,7 +44,7 @@ TEST_CASE("flush_on", "[flush_on]]")
spdlog::fmt_lib::format("Should not be flushed{}Test message 1{}Test message 2{}", default_eol, default_eol, default_eol)); spdlog::fmt_lib::format("Should not be flushed{}Test message 1{}Test message 2{}", default_eol, default_eol, default_eol));
} }
TEST_CASE("rotating_file_logger1", "[rotating_logger]]") TEST_CASE("rotating_file_logger1", "[rotating_logger]")
{ {
prepare_logdir(); prepare_logdir();
size_t max_size = 1024 * 10; size_t max_size = 1024 * 10;
@ -60,7 +60,7 @@ TEST_CASE("rotating_file_logger1", "[rotating_logger]]")
require_message_count(ROTATING_LOG, 10); require_message_count(ROTATING_LOG, 10);
} }
TEST_CASE("rotating_file_logger2", "[rotating_logger]]") TEST_CASE("rotating_file_logger2", "[rotating_logger]")
{ {
prepare_logdir(); prepare_logdir();
size_t max_size = 1024 * 10; size_t max_size = 1024 * 10;
@ -100,7 +100,7 @@ TEST_CASE("rotating_file_logger2", "[rotating_logger]]")
} }
// test that passing max_size=0 throws // test that passing max_size=0 throws
TEST_CASE("rotating_file_logger3", "[rotating_logger]]") TEST_CASE("rotating_file_logger3", "[rotating_logger]")
{ {
prepare_logdir(); prepare_logdir();
size_t max_size = 0; size_t max_size = 0;

View File

@ -10,7 +10,7 @@
#define TEST_FILENAME "test_logs/simple_log" #define TEST_FILENAME "test_logs/simple_log"
TEST_CASE("debug and trace w/o format string", "[macros]]") TEST_CASE("debug and trace w/o format string", "[macros]")
{ {
prepare_logdir(); prepare_logdir();

View File

@ -6,7 +6,7 @@ TEST_CASE("stopwatch1", "[stopwatch]")
{ {
using std::chrono::milliseconds; using std::chrono::milliseconds;
using clock = std::chrono::steady_clock; using clock = std::chrono::steady_clock;
milliseconds wait_ms(250); milliseconds wait_ms(200);
milliseconds tolerance_ms(250); milliseconds tolerance_ms(250);
auto start = clock::now(); auto start = clock::now();
spdlog::stopwatch sw; spdlog::stopwatch sw;
@ -24,7 +24,7 @@ TEST_CASE("stopwatch2", "[stopwatch]")
using std::chrono::milliseconds; using std::chrono::milliseconds;
using clock = std::chrono::steady_clock; using clock = std::chrono::steady_clock;
clock::duration wait_duration(milliseconds(250)); clock::duration wait_duration(milliseconds(200));
clock::duration tolerance_duration(milliseconds(250)); clock::duration tolerance_duration(milliseconds(250));
auto test_sink = std::make_shared<test_sink_st>(); auto test_sink = std::make_shared<test_sink_st>();