Skip to content

Commit

Permalink
Merge branch 'gabime:v1.x' into v1.x
Browse files Browse the repository at this point in the history
  • Loading branch information
MaxwellGengYF authored Dec 30, 2024
2 parents 7d58582 + 276ee5f commit 26f680c
Show file tree
Hide file tree
Showing 18 changed files with 148 additions and 18 deletions.
27 changes: 22 additions & 5 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -108,15 +108,15 @@ endif()
if(WIN32)
option(SPDLOG_WCHAR_SUPPORT "Support wchar api" OFF)
option(SPDLOG_WCHAR_FILENAMES "Support wchar filenames" OFF)
option(SPDLOG_WCHAR_CONSOLE "Support wchar output to console" OFF)
option(SPDLOG_WCHAR_CONSOLE "Support wchar output to console" OFF)
else()
set(SPDLOG_WCHAR_SUPPORT OFF CACHE BOOL "non supported option" FORCE)
set(SPDLOG_WCHAR_FILENAMES OFF CACHE BOOL "non supported option" FORCE)
set(SPDLOG_WCHAR_CONSOLE OFF CACHE BOOL "non supported option" FORCE)
endif()

if(MSVC)
option(SPDLOG_MSVC_UTF8 "Enable/disable msvc /utf-8 flag required by fmt lib" ON)
if(MSVC)
option(SPDLOG_MSVC_UTF8 "Enable/disable msvc /utf-8 flag required by fmt lib" ON)
endif()

if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
Expand Down Expand Up @@ -238,6 +238,20 @@ if(SPDLOG_FMT_EXTERNAL OR SPDLOG_FMT_EXTERNAL_HO)
set(PKG_CONFIG_REQUIRES fmt) # add dependency to pkg-config
endif()

# ---------------------------------------------------------------------------------------
# Check if fwrite_unlocked/_fwrite_nolock is available
# ---------------------------------------------------------------------------------------
include(CheckSymbolExists)
if(WIN32)
check_symbol_exists(_fwrite_nolock "stdio.h" HAVE_FWRITE_UNLOCKED)
else ()
check_symbol_exists(fwrite_unlocked "stdio.h" HAVE_FWRITE_UNLOCKED)
endif()
if(HAVE_FWRITE_UNLOCKED)
target_compile_definitions(spdlog PRIVATE SPDLOG_FWRITE_UNLOCKED)
target_compile_definitions(spdlog_header_only INTERFACE SPDLOG_FWRITE_UNLOCKED)
endif()

# ---------------------------------------------------------------------------------------
# Add required libraries for Android CMake build
# ---------------------------------------------------------------------------------------
Expand Down Expand Up @@ -274,8 +288,11 @@ if(MSVC)
target_compile_options(spdlog PRIVATE "/Zc:__cplusplus")
target_compile_options(spdlog_header_only INTERFACE "/Zc:__cplusplus")
if(SPDLOG_MSVC_UTF8)
target_compile_options(spdlog PUBLIC "/utf-8")
target_compile_options(spdlog_header_only INTERFACE "/utf-8")
# fmtlib requires the /utf-8 flag when building with msvc.
# see https://github.com/fmtlib/fmt/pull/4159 on the purpose of the additional
# "$<$<AND:$<COMPILE_LANGUAGE:CXX>,$<CXX_COMPILER_ID:MSVC>>"
target_compile_options(spdlog PUBLIC $<$<AND:$<COMPILE_LANGUAGE:CXX>,$<CXX_COMPILER_ID:MSVC>>:/utf-8>)
target_compile_options(spdlog_header_only INTERFACE $<$<AND:$<COMPILE_LANGUAGE:CXX>,$<CXX_COMPILER_ID:MSVC>>:/utf-8>)
endif()
endif()

Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -303,7 +303,7 @@ struct fmt::formatter<my_type> : fmt::formatter<std::string>
{
auto format(my_type my, format_context &ctx) const -> decltype(ctx.out())
{
return format_to(ctx.out(), "[my_type i={}]", my.i);
return fmt::format_to(ctx.out(), "[my_type i={}]", my.i);
}
};

Expand Down
2 changes: 1 addition & 1 deletion example/example.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -281,7 +281,7 @@ struct fmt::formatter<my_type> : fmt::formatter<std::string> {
template <>
struct std::formatter<my_type> : std::formatter<std::string> {
auto format(my_type my, format_context &ctx) const -> decltype(ctx.out()) {
return format_to(ctx.out(), "[my_type i={}]", my.i);
return std::format_to(ctx.out(), "[my_type i={}]", my.i);
}
};
#endif
Expand Down
7 changes: 7 additions & 0 deletions include/spdlog/common.h
Original file line number Diff line number Diff line change
Expand Up @@ -365,10 +365,17 @@ SPDLOG_CONSTEXPR_FUNC spdlog::wstring_view_t to_string_view(spdlog::wstring_view
#endif

#ifndef SPDLOG_USE_STD_FORMAT
#if FMT_VERSION >= 110100
template <typename T, typename... Args>
inline fmt::basic_string_view<T> to_string_view(fmt::basic_format_arg<T> fmt) {
return fmt;
}
#else
template <typename T, typename... Args>
inline fmt::basic_string_view<T> to_string_view(fmt::basic_format_string<T, Args...> fmt) {
return fmt;
}
#endif
#elif __cpp_lib_format >= 202207L
template <typename T, typename... Args>
SPDLOG_CONSTEXPR_FUNC std::basic_string_view<T> to_string_view(
Expand Down
3 changes: 2 additions & 1 deletion include/spdlog/details/file_helper-inl.h
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,8 @@ SPDLOG_INLINE void file_helper::write(const memory_buf_t &buf) {
if (fd_ == nullptr) return;
size_t msg_size = buf.size();
auto data = buf.data();
if (std::fwrite(data, 1, msg_size, fd_) != msg_size) {

if (!details::os::fwrite_bytes(data, msg_size, fd_)) {
throw_spdlog_ex("Failed writing to file " + os::filename_to_str(filename_), errno);
}
}
Expand Down
12 changes: 12 additions & 0 deletions include/spdlog/details/os-inl.h
Original file line number Diff line number Diff line change
Expand Up @@ -589,6 +589,18 @@ SPDLOG_INLINE bool fsync(FILE *fp) {
#endif
}

// Do non-locking fwrite if possible by the os or use the regular locking fwrite
// Return true on success.
SPDLOG_INLINE bool fwrite_bytes(const void *ptr, const size_t n_bytes, FILE *fp) {
#if defined(_WIN32) && defined(SPDLOG_FWRITE_UNLOCKED)
return _fwrite_nolock(ptr, 1, n_bytes, fp) == n_bytes;
#elif defined(SPDLOG_FWRITE_UNLOCKED)
return ::fwrite_unlocked(ptr, 1, n_bytes, fp) == n_bytes;
#else
return std::fwrite(ptr, 1, n_bytes, fp) == n_bytes;
#endif
}

} // namespace os
} // namespace details
} // namespace spdlog
4 changes: 4 additions & 0 deletions include/spdlog/details/os.h
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,10 @@ SPDLOG_API std::string getenv(const char *field);
// Return true on success.
SPDLOG_API bool fsync(FILE *fp);

// Do non-locking fwrite if possible by the os or use the regular locking fwrite
// Return true on success.
SPDLOG_API bool fwrite_bytes(const void *ptr, const size_t n_bytes, FILE *fp);

} // namespace os
} // namespace details
} // namespace spdlog
Expand Down
4 changes: 2 additions & 2 deletions include/spdlog/sinks/ansicolor_sink-inl.h
Original file line number Diff line number Diff line change
Expand Up @@ -106,14 +106,14 @@ SPDLOG_INLINE void ansicolor_sink<ConsoleMutex>::set_color_mode(color_mode mode)

template <typename ConsoleMutex>
SPDLOG_INLINE void ansicolor_sink<ConsoleMutex>::print_ccode_(const string_view_t &color_code) {
fwrite(color_code.data(), sizeof(char), color_code.size(), target_file_);
details::os::fwrite_bytes(color_code.data(), color_code.size(), target_file_);
}

template <typename ConsoleMutex>
SPDLOG_INLINE void ansicolor_sink<ConsoleMutex>::print_range_(const memory_buf_t &formatted,
size_t start,
size_t end) {
fwrite(formatted.data() + start, sizeof(char), end - start, target_file_);
details::os::fwrite_bytes(formatted.data() + start, end - start, target_file_);
}

template <typename ConsoleMutex>
Expand Down
6 changes: 6 additions & 0 deletions include/spdlog/sinks/basic_file_sink-inl.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,12 @@ SPDLOG_INLINE const filename_t &basic_file_sink<Mutex>::filename() const {
return file_helper_.filename();
}

template <typename Mutex>
SPDLOG_INLINE void basic_file_sink<Mutex>::truncate() {
std::lock_guard<Mutex> lock(base_sink<Mutex>::mutex_);
file_helper_.reopen(true);
}

template <typename Mutex>
SPDLOG_INLINE void basic_file_sink<Mutex>::sink_it_(const details::log_msg &msg) {
memory_buf_t formatted;
Expand Down
1 change: 1 addition & 0 deletions include/spdlog/sinks/basic_file_sink.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ class basic_file_sink final : public base_sink<Mutex> {
bool truncate = false,
const file_event_handlers &event_handlers = {});
const filename_t &filename() const;
void truncate();

protected:
void sink_it_(const details::log_msg &msg) override;
Expand Down
1 change: 0 additions & 1 deletion include/spdlog/sinks/daily_file_sink.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,6 @@ struct daily_filename_format_calculator {
* Rotating file sink based on date.
* If truncate != false , the created file will be truncated.
* If max_files > 0, retain only the last max_files and delete previous.
* If max_files > 0, retain only the last max_files and delete previous.
* Note that old log files from previous executions will not be deleted by this class,
* rotation and deletion is only applied while the program is running.
*/
Expand Down
2 changes: 1 addition & 1 deletion include/spdlog/sinks/null_sink.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ namespace spdlog {
namespace sinks {

template <typename Mutex>
class null_sink : public base_sink<Mutex> {
class null_sink final : public base_sink<Mutex> {
protected:
void sink_it_(const details::log_msg &) override {}
void flush_() override {}
Expand Down
6 changes: 6 additions & 0 deletions include/spdlog/sinks/rotating_file_sink-inl.h
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,12 @@ SPDLOG_INLINE filename_t rotating_file_sink<Mutex>::filename() {
return file_helper_.filename();
}

template <typename Mutex>
SPDLOG_INLINE void rotating_file_sink<Mutex>::rotate_now() {
std::lock_guard<Mutex> lock(base_sink<Mutex>::mutex_);
rotate_();
}

template <typename Mutex>
SPDLOG_INLINE void rotating_file_sink<Mutex>::sink_it_(const details::log_msg &msg) {
memory_buf_t formatted;
Expand Down
1 change: 1 addition & 0 deletions include/spdlog/sinks/rotating_file_sink.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ class rotating_file_sink final : public base_sink<Mutex> {
const file_event_handlers &event_handlers = {});
static filename_t calc_filename(const filename_t &filename, std::size_t index);
filename_t filename();
void rotate_now();

protected:
void sink_it_(const details::log_msg &msg) override;
Expand Down
9 changes: 5 additions & 4 deletions include/spdlog/sinks/stdout_sinks-inl.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include <memory>
#include <spdlog/details/console_globals.h>
#include <spdlog/pattern_formatter.h>
#include <spdlog/details/os.h>

#ifdef _WIN32
// under windows using fwrite to non-binary stream results in \r\r\n (see issue #1675)
Expand All @@ -22,7 +23,7 @@

#include <io.h> // _get_osfhandle(..)
#include <stdio.h> // _fileno(..)
#endif // WIN32
#endif // _WIN32

namespace spdlog {

Expand All @@ -44,7 +45,7 @@ SPDLOG_INLINE stdout_sink_base<ConsoleMutex>::stdout_sink_base(FILE *file)
if (handle_ == INVALID_HANDLE_VALUE && file != stdout && file != stderr) {
throw_spdlog_ex("spdlog::stdout_sink_base: _get_osfhandle() failed", errno);
}
#endif // WIN32
#endif // _WIN32
}

template <typename ConsoleMutex>
Expand All @@ -67,8 +68,8 @@ 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);
::fwrite(formatted.data(), sizeof(char), formatted.size(), file_);
#endif // WIN32
details::os::fwrite_bytes(formatted.data(), formatted.size(), file_);
#endif // _WIN32
::fflush(file_); // flush every line to terminal
}

Expand Down
4 changes: 2 additions & 2 deletions include/spdlog/version.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
#pragma once

#define SPDLOG_VER_MAJOR 1
#define SPDLOG_VER_MINOR 14
#define SPDLOG_VER_PATCH 1
#define SPDLOG_VER_MINOR 15
#define SPDLOG_VER_PATCH 0

#define SPDLOG_TO_VERSION(major, minor, patch) (major * 10000 + minor * 100 + patch)
#define SPDLOG_VERSION SPDLOG_TO_VERSION(SPDLOG_VER_MAJOR, SPDLOG_VER_MINOR, SPDLOG_VER_PATCH)
40 changes: 40 additions & 0 deletions tests/test_file_logging.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,26 @@ TEST_CASE("flush_on", "[flush_on]") {
default_eol, default_eol, default_eol));
}

TEST_CASE("simple_file_logger", "[truncate]") {
prepare_logdir();
const spdlog::filename_t filename = SPDLOG_FILENAME_T(SIMPLE_LOG);
const bool truncate = true;
const auto sink = std::make_shared<spdlog::sinks::basic_file_sink_mt>(filename, truncate);
const auto logger = std::make_shared<spdlog::logger>("simple_file_logger", sink);

logger->info("Test message {}", 3.14);
logger->info("Test message {}", 2.71);
logger->flush();
REQUIRE(count_lines(SIMPLE_LOG) == 2);

sink->truncate();
REQUIRE(count_lines(SIMPLE_LOG) == 0);

logger->info("Test message {}", 6.28);
logger->flush();
REQUIRE(count_lines(SIMPLE_LOG) == 1);
}

TEST_CASE("rotating_file_logger1", "[rotating_logger]") {
prepare_logdir();
size_t max_size = 1024 * 10;
Expand Down Expand Up @@ -101,3 +121,23 @@ TEST_CASE("rotating_file_logger3", "[rotating_logger]") {
REQUIRE_THROWS_AS(spdlog::rotating_logger_mt("logger", basename, max_size, 0),
spdlog::spdlog_ex);
}

// test on-demand rotation of logs
TEST_CASE("rotating_file_logger4", "[rotating_logger]") {
prepare_logdir();
size_t max_size = 1024 * 10;
spdlog::filename_t basename = SPDLOG_FILENAME_T(ROTATING_LOG);
auto sink = std::make_shared<spdlog::sinks::rotating_file_sink_st>(basename, max_size, 2);
auto logger = std::make_shared<spdlog::logger>("rotating_sink_logger", sink);

logger->info("Test message - pre-rotation");
logger->flush();

sink->rotate_now();

logger->info("Test message - post-rotation");
logger->flush();

REQUIRE(get_filesize(ROTATING_LOG) > 0);
REQUIRE(get_filesize(ROTATING_LOG ".1") > 0);
}
35 changes: 35 additions & 0 deletions tests/test_misc.cpp
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
#ifdef _WIN32 // to prevent fopen warning on windows
#define _CRT_SECURE_NO_WARNINGS
#endif

#include "includes.h"
#include "test_sink.h"

Expand Down Expand Up @@ -185,3 +189,34 @@ TEST_CASE("utf8 to utf16 conversion using windows api", "[windows utf]") {
REQUIRE(std::wstring(buffer.data(), buffer.size()) == std::wstring(L"\x306d\x3053"));
}
#endif

struct auto_closer {
FILE* fp = nullptr;
explicit auto_closer(FILE* f) : fp(f) {}
auto_closer(const auto_closer&) = delete;
auto_closer& operator=(const auto_closer&) = delete;
~auto_closer() {
if (fp != nullptr) (void)std::fclose(fp);
}
};

TEST_CASE("os::fwrite_bytes", "[os]") {
using spdlog::details::os::fwrite_bytes;
using spdlog::details::os::create_dir;
const char* filename = "log_tests/test_fwrite_bytes.txt";
const char *msg = "hello";
prepare_logdir();
REQUIRE(create_dir(SPDLOG_FILENAME_T("log_tests")) == true);
{
auto_closer closer(std::fopen(filename, "wb"));
REQUIRE(closer.fp != nullptr);
REQUIRE(fwrite_bytes(msg, std::strlen(msg), closer.fp) == true);
REQUIRE(fwrite_bytes(msg, 0, closer.fp) == true);
std::fflush(closer.fp);
REQUIRE(spdlog::details::os::filesize(closer.fp) == 5);
}
// fwrite_bytes should return false on write failure
auto_closer closer(std::fopen(filename, "r"));
REQUIRE(closer.fp != nullptr);
REQUIRE_FALSE(fwrite_bytes("Hello", 5, closer.fp));
}

0 comments on commit 26f680c

Please sign in to comment.