Merge branch 'seperate_std_string_view' into attributes

pull/2595/head
Bailey Chittle 2 years ago
commit fffa350db1

@ -9,14 +9,13 @@ jobs:
run:
shell: bash
strategy:
fail-fast: false
matrix:
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: 9, build_type: Release, cppstd: 17 }
- { compiler: gcc, version: 11, build_type: Debug, 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: 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
- name: Setup
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"
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

@ -25,7 +25,10 @@ endif()
# ---------------------------------------------------------------------------------------
# Compiler config
# ---------------------------------------------------------------------------------------
if(NOT CMAKE_CXX_STANDARD)
if(SPDLOG_USE_STD_FORMAT OR SPDLOG_USE_STD_STRING_VIEW)
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_REQUIRED ON)
endif()
@ -85,6 +88,7 @@ option(SPDLOG_BUILD_WARNINGS "Enable compiler warnings" OFF)
option(SPDLOG_SYSTEM_INCLUDES "Include as system headers (skip for clang-tidy)." OFF)
option(SPDLOG_INSTALL "Generate the install target" ${SPDLOG_MASTER_PROJECT})
option(SPDLOG_USE_STD_FORMAT "Use std::format instead of fmt library." OFF)
option(SPDLOG_USE_STD_STRING_VIEW "Use std::string_view instead of the fmt implementation of string_view." OFF)
option(SPDLOG_FMT_EXTERNAL "Use external fmt library instead of bundled" OFF)
option(SPDLOG_FMT_EXTERNAL_HO "Use external fmt header-only library instead of bundled" OFF)
option(SPDLOG_NO_EXCEPTIONS "Compile with -fno-exceptions. Call abort() on any spdlog exceptions" OFF)
@ -101,6 +105,11 @@ if(SPDLOG_USE_STD_FORMAT AND SPDLOG_FMT_EXTERNAL)
message(FATAL_ERROR "SPDLOG_USE_STD_FORMAT and SPDLOG_FMT_EXTERNAL are mutually exclusive")
endif()
if(SPDLOG_USE_STD_FORMAT AND NOT SPDLOG_USE_STD_STRING_VIEW)
# message(FATAL_ERROR "SPDLOG_USE_STD_FORMAT requires SPDLOG_USE_STD_STRING_VIEW")
set(SPDLOG_USE_STD_STRING_VIEW ON CACHE BOOL "" FORCE) # automatically set SPDLOG_USE_STD_STRING_VIEW instead of error
endif()
# misc tweakme options
if(WIN32)
option(SPDLOG_WCHAR_SUPPORT "Support wchar api" OFF)
@ -245,6 +254,7 @@ foreach(
SPDLOG_NO_TLS
SPDLOG_NO_ATOMIC_LEVELS
SPDLOG_DISABLE_DEFAULT_LOGGER
SPDLOG_USE_STD_STRING_VIEW
SPDLOG_USE_STD_FORMAT)
if(${SPDLOG_OPTION})
target_compile_definitions(spdlog PUBLIC ${SPDLOG_OPTION})
@ -256,11 +266,6 @@ if(SPDLOG_NO_EXCEPTIONS AND NOT MSVC)
target_compile_options(spdlog PRIVATE -fno-exceptions)
endif()
if(SPDLOG_USE_STD_FORMAT)
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
endif()
# ---------------------------------------------------------------------------------------
# Build binaries
# ---------------------------------------------------------------------------------------

@ -2,42 +2,6 @@ version: 1.0.{build}
image: Visual Studio 2017
environment:
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"'
BUILD_TYPE: Debug
BUILD_SHARED: 'OFF'
@ -119,7 +83,7 @@ build_script:
cmake --build . --config %BUILD_TYPE%
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:
- C:\projects\spdlog\build\tests\%BUILD_TYPE%\spdlog-utests.exe

@ -282,7 +282,7 @@ struct fmt::formatter<my_type> : fmt::formatter<std::string>
{
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);
}
};

@ -132,10 +132,15 @@ using log_clock = std::chrono::system_clock;
using sink_ptr = std::shared_ptr<sinks::sink>;
using sinks_init_list = std::initializer_list<sink_ptr>;
using err_handler = std::function<void(const std::string &err_msg)>;
#ifdef SPDLOG_USE_STD_STRING_VIEW
using string_view_t = std::string_view;
#else
using string_view_t = fmt::basic_string_view<char>;
#endif
#ifdef SPDLOG_USE_STD_FORMAT
namespace fmt_lib = std;
using string_view_t = std::string_view;
using memory_buf_t = std::string;
template<typename... Args>
@ -164,7 +169,6 @@ using wformat_string_t = std::wstring_view;
#else // use fmt lib instead of std::format
namespace fmt_lib = fmt;
using string_view_t = fmt::basic_string_view<char>;
using memory_buf_t = fmt::basic_memory_buffer<char, 250>;
template<typename... Args>
@ -360,7 +364,7 @@ SPDLOG_CONSTEXPR_FUNC spdlog::wstring_view_t to_string_view(spdlog::wstring_view
}
#endif
#ifndef SPDLOG_USE_STD_FORMAT
#if !defined(SPDLOG_USE_STD_STRING_VIEW) && !defined(SPDLOG_USE_STD_FORMAT)
template<typename T, typename... Args>
inline fmt::basic_string_view<T> to_string_view(fmt::basic_format_string<T, Args...> fmt)
{
@ -372,6 +376,13 @@ SPDLOG_CONSTEXPR_FUNC std::basic_string_view<T> to_string_view(std::basic_format
{
return fmt.get();
}
#elif defined(SPDLOG_USE_STD_STRING_VIEW) && !defined(SPDLOG_USE_STD_FORMAT)
template<typename T, typename... Args>
SPDLOG_CONSTEXPR_FUNC std::basic_string_view<T> to_string_view(fmt::basic_format_string<T, Args...> fmt) SPDLOG_NOEXCEPT
{
auto tmp = fmt::basic_string_view<T>{fmt};
return std::string_view{tmp.data(), tmp.size()};
}
#endif
// make_unique support for pre c++14

@ -13,16 +13,16 @@ namespace details {
SPDLOG_INLINE log_msg_buffer::log_msg_buffer(const log_msg &orig_msg)
: log_msg{orig_msg}
{
buffer.append(logger_name.begin(), logger_name.end());
buffer.append(payload.begin(), payload.end());
buffer.append(logger_name.data(), logger_name.data() + logger_name.size());
buffer.append(payload.data(), payload.data() + payload.size());
update_string_views();
}
SPDLOG_INLINE log_msg_buffer::log_msg_buffer(const log_msg_buffer &other)
: log_msg{other}
{
buffer.append(logger_name.begin(), logger_name.end());
buffer.append(payload.begin(), payload.end());
buffer.append(logger_name.data(), logger_name.data() + logger_name.size());
buffer.append(payload.data(), payload.data() + payload.size());
update_string_views();
}

@ -34,6 +34,7 @@
# if defined(SPDLOG_WCHAR_TO_UTF8_SUPPORT) || defined(SPDLOG_WCHAR_FILENAMES)
# include <limits>
# include <cassert>
# endif
# include <direct.h> // for _mkdir/_wmkdir
@ -501,20 +502,16 @@ SPDLOG_INLINE void utf8_to_wstrbuf(string_view_t str, wmemory_buf_t &target)
return;
}
int result_size = static_cast<int>(target.capacity());
if (str_size + 1 > result_size)
{
result_size = ::MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, str.data(), str_size, NULL, 0);
}
// find the size to allocate for the result buffer
int result_size = ::MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, str.data(), str_size, NULL, 0);
if (result_size > 0)
{
target.resize(result_size);
result_size = ::MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, str.data(), str_size, target.data(), result_size);
if (result_size > 0)
if (result_size > 0)
{
target.resize(result_size);
assert(result_size == target.size());
return;
}
}

@ -287,6 +287,14 @@ SPDLOG_INLINE registry &registry::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)
{
if (loggers_.find(logger_name) != loggers_.end())

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

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

@ -7,13 +7,20 @@
#if defined(_WIN32)
# 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 <mutex>
# include <string>
// Avoid including windows.h (https://stackoverflow.com/a/30741042)
#if defined(SPDLOG_WCHAR_TO_UTF8_SUPPORT)
extern "C" __declspec(dllimport) void __stdcall OutputDebugStringW(const wchar_t *lpOutputString);
#else
extern "C" __declspec(dllimport) void __stdcall OutputDebugStringA(const char *lpOutputString);
#endif
extern "C" __declspec(dllimport) int __stdcall IsDebuggerPresent();
namespace spdlog {
@ -38,8 +45,14 @@ protected:
}
memory_buf_t 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());
#endif
}
void flush_() override {}

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

@ -4,6 +4,7 @@
#pragma once
#include <spdlog/sinks/base_sink.h>
#include <spdlog/details/os.h>
#include <spdlog/details/null_mutex.h>
#include <spdlog/details/synchronous_factory.h>
@ -75,11 +76,17 @@ protected:
{
// 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),
#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);
}
else
{
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",
msg.source.filename, "CODE_LINE=%d", msg.source.line, "CODE_FUNC=%s", msg.source.funcname, nullptr);
}

@ -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));
}
SPDLOG_INLINE void apply_logger_env_levels(std::shared_ptr<logger> logger)
{
details::registry::instance().apply_logger_env_levels(std::move(logger));
}
} // namespace spdlog

@ -142,6 +142,14 @@ inline void pop_context() {
inline void clear_context() {
default_logger_raw()->clear_context();
}
// 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>
inline void log(source_loc source, level::level_enum lvl, format_string_t<Args...> fmt, Args &&... args)

@ -13,6 +13,20 @@ if(PkgConfig_FOUND)
pkg_check_modules(systemd libsystemd)
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
test_file_helper.cpp
test_file_logging.cpp
@ -54,6 +68,7 @@ function(spdlog_prepare_test test_target spdlog_lib)
if(systemd_FOUND)
target_link_libraries(${test_target} PRIVATE ${systemd_LIBRARIES})
endif()
target_link_libraries(${test_target} PRIVATE Catch2::Catch2WithMain)
if(SPDLOG_SANITIZE_ADDRESS)
spdlog_enable_sanitizer(${test_target})
endif()

File diff suppressed because it is too large Load Diff

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

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

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

@ -7,7 +7,7 @@
#include "spdlog/async.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;
spdlog::pattern_formatter formatter;

@ -87,19 +87,19 @@ TEST_CASE("daily_logger with custom calculator", "[daily_logger]")
* 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);
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);
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);
REQUIRE(filename == SPDLOG_FILENAME_T("rotated.txt"));
@ -110,7 +110,7 @@ TEST_CASE("rotating_file_sink::calc_filename3", "[rotating_file_sink]]")
# 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
auto filename =
@ -123,7 +123,7 @@ TEST_CASE("daily_file_sink::daily_filename_calculator", "[daily_file_sink]]")
}
#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();
// example-YYYY-MM-DD.log

@ -1,6 +1,6 @@
/*
* This content is released under the MIT License as specified in https://raw.githubusercontent.com/gabime/spdlog/master/LICENSE
*/
* This content is released under the MIT License as specified in https://raw.githubusercontent.com/gabime/spdlog/master/LICENSE
*/
#include "includes.h"
#include <iostream>
@ -11,111 +11,114 @@
class failing_sink : public spdlog::sinks::base_sink<std::mutex>
{
protected:
void sink_it_(const spdlog::details::log_msg &) final
{
throw std::runtime_error("some error happened during log");
}
void sink_it_(const spdlog::details::log_msg &) final
{
throw std::runtime_error("some error happened during log");
}
void flush_() final
{
throw std::runtime_error("some error happened during flush");
}
void flush_() final
{
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();
spdlog::filename_t filename = SPDLOG_FILENAME_T(SIMPLE_LOG);
prepare_logdir();
spdlog::filename_t filename = SPDLOG_FILENAME_T(SIMPLE_LOG);
auto logger = spdlog::create<spdlog::sinks::basic_file_sink_mt>("test-error", filename, true);
logger->set_pattern("%v");
logger->info(SPDLOG_FMT_RUNTIME("Test message {} {}"), 1);
logger->info("Test message {}", 2);
logger->flush();
using spdlog::details::os::default_eol;
REQUIRE(file_contents(SIMPLE_LOG) == spdlog::fmt_lib::format("Test message 2{}", default_eol));
REQUIRE(count_lines(SIMPLE_LOG) == 1);
auto logger = spdlog::create<spdlog::sinks::basic_file_sink_mt>("test-error", filename, true);
logger->set_pattern("%v");
logger->info(SPDLOG_FMT_RUNTIME("Test message {} {}"), 1);
logger->info("Test message {}", 2);
logger->flush();
using spdlog::details::os::default_eol;
REQUIRE(file_contents(SIMPLE_LOG) == spdlog::fmt_lib::format("Test message 2{}", default_eol));
REQUIRE(count_lines(SIMPLE_LOG) == 1);
}
struct custom_ex
{};
TEST_CASE("custom_error_handler", "[errors]]")
TEST_CASE("custom_error_handler", "[errors]")
{
prepare_logdir();
spdlog::filename_t filename = SPDLOG_FILENAME_T(SIMPLE_LOG);
auto logger = spdlog::create<spdlog::sinks::basic_file_sink_mt>("logger", filename, true);
logger->flush_on(spdlog::level::info);
logger->set_error_handler([=](const std::string &) { throw custom_ex(); });
logger->info("Good message #1");
prepare_logdir();
spdlog::filename_t filename = SPDLOG_FILENAME_T(SIMPLE_LOG);
auto logger = spdlog::create<spdlog::sinks::basic_file_sink_mt>("logger", filename, true);
logger->flush_on(spdlog::level::info);
logger->set_error_handler([=](const std::string &) { throw custom_ex(); });
logger->info("Good message #1");
REQUIRE_THROWS_AS(logger->info(SPDLOG_FMT_RUNTIME("Bad format msg {} {}"), "xxx"), custom_ex);
logger->info("Good message #2");
require_message_count(SIMPLE_LOG, 2);
REQUIRE_THROWS_AS(logger->info(SPDLOG_FMT_RUNTIME("Bad format msg {} {}"), "xxx"), custom_ex);
logger->info("Good message #2");
require_message_count(SIMPLE_LOG, 2);
}
#endif
TEST_CASE("default_error_handler2", "[errors]]")
TEST_CASE("default_error_handler2", "[errors]")
{
spdlog::drop_all();
auto logger = spdlog::create<failing_sink>("failed_logger");
logger->set_error_handler([=](const std::string &) { throw custom_ex(); });
REQUIRE_THROWS_AS(logger->info("Some message"), custom_ex);
spdlog::drop_all();
auto logger = spdlog::create<failing_sink>("failed_logger");
logger->set_error_handler([=](const std::string &) { throw 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();
auto logger = spdlog::create<failing_sink>("failed_logger");
logger->set_error_handler([=](const std::string &) { throw custom_ex(); });
REQUIRE_THROWS_AS(logger->flush(), custom_ex);
spdlog::drop_all();
auto logger = spdlog::create<failing_sink>("failed_logger");
logger->set_error_handler([=](const std::string &) { throw 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();
std::string err_msg("log failed with some msg");
prepare_logdir();
std::string err_msg("log failed with some msg");
spdlog::filename_t filename = SPDLOG_FILENAME_T(SIMPLE_ASYNC_LOG);
{
spdlog::init_thread_pool(128, 1);
auto logger = spdlog::create_async<spdlog::sinks::basic_file_sink_mt>("logger", filename, true);
logger->set_error_handler([=](const std::string &) {
std::ofstream ofs("test_logs/custom_err.txt");
if (!ofs)
{
throw std::runtime_error("Failed open test_logs/custom_err.txt");
}
ofs << err_msg;
});
logger->info("Good message #1");
logger->info(SPDLOG_FMT_RUNTIME("Bad format msg {} {}"), "xxx");
logger->info("Good message #2");
spdlog::drop("logger"); // force logger to drain the queue and shutdown
}
spdlog::init_thread_pool(128, 1);
require_message_count(SIMPLE_ASYNC_LOG, 2);
REQUIRE(file_contents("test_logs/custom_err.txt") == err_msg);
spdlog::filename_t filename = SPDLOG_FILENAME_T(SIMPLE_ASYNC_LOG);
{
spdlog::init_thread_pool(128, 1);
auto logger = spdlog::create_async<spdlog::sinks::basic_file_sink_mt>("logger", filename, true);
logger->set_error_handler([=](const std::string &) {
std::ofstream ofs("test_logs/custom_err.txt");
if (!ofs)
{
throw std::runtime_error("Failed open test_logs/custom_err.txt");
}
ofs << err_msg;
});
logger->info("Good message #1");
logger->info(SPDLOG_FMT_RUNTIME("Bad format msg {} {}"), "xxx");
logger->info("Good message #2");
spdlog::drop("logger"); // force logger to drain the queue and shutdown
}
spdlog::init_thread_pool(128, 1);
require_message_count(SIMPLE_ASYNC_LOG, 2);
REQUIRE(file_contents("test_logs/custom_err.txt") == err_msg);
}
#endif
// Make sure async error handler is executed
TEST_CASE("async_error_handler2", "[errors]]")
TEST_CASE("async_error_handler2", "[errors]")
{
prepare_logdir();
std::string err_msg("This is async handler error message");
{
spdlog::details::os::create_dir(SPDLOG_FILENAME_T("test_logs"));
spdlog::init_thread_pool(128, 1);
auto logger = spdlog::create_async<failing_sink>("failed_logger");
logger->set_error_handler([=](const std::string &) {
std::ofstream ofs("test_logs/custom_err2.txt");
if (!ofs)
throw std::runtime_error("Failed open test_logs/custom_err2.txt");
ofs << err_msg;
});
logger->info("Hello failure");
spdlog::drop("failed_logger"); // force logger to drain the queue and shutdown
}
prepare_logdir();
std::string err_msg("This is async handler error message");
{
spdlog::details::os::create_dir(SPDLOG_FILENAME_T("test_logs"));
spdlog::init_thread_pool(128, 1);
auto logger = spdlog::create_async<failing_sink>("failed_logger");
logger->set_error_handler([=](const std::string &) {
std::ofstream ofs("test_logs/custom_err2.txt");
if (!ofs)
throw std::runtime_error("Failed open test_logs/custom_err2.txt");
ofs << err_msg;
});
logger->info("Hello failure");
spdlog::drop("failed_logger"); // force logger to drain the queue and shutdown
}
spdlog::init_thread_pool(128, 1);
REQUIRE(file_contents("test_logs/custom_err2.txt") == err_msg);
spdlog::init_thread_pool(128, 1);
REQUIRE(file_contents("test_logs/custom_err2.txt") == err_msg);
}

@ -15,7 +15,7 @@ static void write_with_helper(file_helper &helper, size_t howmany)
helper.flush();
}
TEST_CASE("file_helper_filename", "[file_helper::filename()]]")
TEST_CASE("file_helper_filename", "[file_helper::filename()]")
{
prepare_logdir();
@ -25,7 +25,7 @@ TEST_CASE("file_helper_filename", "[file_helper::filename()]]")
REQUIRE(helper.filename() == target_filename);
}
TEST_CASE("file_helper_size", "[file_helper::size()]]")
TEST_CASE("file_helper_size", "[file_helper::size()]")
{
prepare_logdir();
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);
}
TEST_CASE("file_helper_reopen", "[file_helper::reopen()]]")
TEST_CASE("file_helper_reopen", "[file_helper::reopen()]")
{
prepare_logdir();
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);
}
TEST_CASE("file_helper_reopen2", "[file_helper::reopen(false)]]")
TEST_CASE("file_helper_reopen2", "[file_helper::reopen(false)]")
{
prepare_logdir();
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);
}
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"));

@ -6,7 +6,7 @@
#define SIMPLE_LOG "test_logs/simple_log"
#define ROTATING_LOG "test_logs/rotating_log"
TEST_CASE("simple_file_logger", "[simple_logger]]")
TEST_CASE("simple_file_logger", "[simple_logger]")
{
prepare_logdir();
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));
}
TEST_CASE("flush_on", "[flush_on]]")
TEST_CASE("flush_on", "[flush_on]")
{
prepare_logdir();
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));
}
TEST_CASE("rotating_file_logger1", "[rotating_logger]]")
TEST_CASE("rotating_file_logger1", "[rotating_logger]")
{
prepare_logdir();
size_t max_size = 1024 * 10;
@ -60,7 +60,7 @@ TEST_CASE("rotating_file_logger1", "[rotating_logger]]")
require_message_count(ROTATING_LOG, 10);
}
TEST_CASE("rotating_file_logger2", "[rotating_logger]]")
TEST_CASE("rotating_file_logger2", "[rotating_logger]")
{
prepare_logdir();
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_CASE("rotating_file_logger3", "[rotating_logger]]")
TEST_CASE("rotating_file_logger3", "[rotating_logger]")
{
prepare_logdir();
size_t max_size = 0;

@ -10,7 +10,7 @@
#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();

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

Loading…
Cancel
Save