Compare commits

..

10 Commits

Author SHA1 Message Date
zjyhjqs
5ebfc92730
fix: set /Zc:__cplusplus and /MP to MSVC only (#3139)
Some checks failed
ci / ${{ matrix.config.compiler}} ${{ matrix.config.version }} (C++${{ matrix.config.cppstd }}, ${{ matrix.config.build_type }}) (map[asan:OFF build_type:Debug compiler:clang cppstd:17 version:12]) (push) Has been cancelled
ci / ${{ matrix.config.compiler}} ${{ matrix.config.version }} (C++${{ matrix.config.cppstd }}, ${{ matrix.config.build_type }}) (map[asan:OFF build_type:Release compiler:clang cppstd:20 version:15]) (push) Has been cancelled
ci / ${{ matrix.config.compiler}} ${{ matrix.config.version }} (C++${{ matrix.config.cppstd }}, ${{ matrix.config.build_type }}) (map[build_type:Debug compiler:gcc cppstd:20 version:11]) (push) Has been cancelled
ci / ${{ matrix.config.compiler}} ${{ matrix.config.version }} (C++${{ matrix.config.cppstd }}, ${{ matrix.config.build_type }}) (map[build_type:Release compiler:gcc cppstd:11 version:7]) (push) Has been cancelled
ci / ${{ matrix.config.compiler}} ${{ matrix.config.version }} (C++${{ matrix.config.cppstd }}, ${{ matrix.config.build_type }}) (map[build_type:Release compiler:gcc cppstd:17 version:9]) (push) Has been cancelled
ci / ${{ matrix.config.compiler}} ${{ matrix.config.version }} (C++${{ matrix.config.cppstd }}, ${{ matrix.config.build_type }}) (map[build_type:Release compiler:gcc cppstd:20 version:12]) (push) Has been cancelled
ci / OS X Clang (C++11, Release) (push) Has been cancelled
1. macro `__cplusplus` is enabled by clang-cl
2. `/MP` is not supported by clang-cl (warning `-Wunused-command-line-argument` will be generated)
2024-07-22 13:37:28 +03:00
Alex Overchenko
885b5473e2
Fix building with FMT_ENFORCE_COMPILE_STRING (#3137) 2024-07-16 20:41:21 +03:00
Ziyao
d276069a6e
make example compatible with fmt 11 (#3130)
Since fmt 11.0.0, formatter::format() is required to be const. Mark
format() method in example as const to stay compatible with fmt 11.
2024-07-08 23:14:30 +03:00
Philippe Vaucher
eeb22c13bb
Allow customization of syslog_sink (#3124)
Thanks @Silex
2024-07-03 22:51:11 +03:00
Dominik Grabiec
c3aed4b683
Add wide character formatting and output support to wincolor_sink. (#3092)
Fixes printing of unicode characters to the windows console such as microsecond suffix for std::chrono types.
2024-05-22 00:20:17 +03:00
gabime
27cb4c7670 Added mdc example to readme 2024-04-30 13:14:29 +03:00
gabime
2d4acf8cc3 Added mdc example 2024-04-30 13:11:01 +03:00
gabime
3b4fd93bd0 Updated comment about mdc 2024-04-30 12:56:35 +03:00
gabime
2122eb2194 Update spdlog version to 1.14.1 2024-04-30 12:50:45 +03:00
gabime
22b0f4fc06 Clang format 2024-04-30 12:28:13 +03:00
19 changed files with 114 additions and 68 deletions

View File

@ -34,7 +34,7 @@ elseif(NOT CMAKE_CXX_STANDARD)
endif() endif()
# make sure __cplusplus is defined when using msvc and enable parallel build # make sure __cplusplus is defined when using msvc and enable parallel build
if(MSVC) if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
string(APPEND CMAKE_CXX_FLAGS " /Zc:__cplusplus /MP") string(APPEND CMAKE_CXX_FLAGS " /Zc:__cplusplus /MP")
endif() endif()
@ -108,9 +108,11 @@ endif()
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)
option(SPDLOG_WCHAR_CONSOLE "Support wchar output to console" OFF)
else() else()
set(SPDLOG_WCHAR_SUPPORT OFF CACHE BOOL "non supported option" FORCE) 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_FILENAMES OFF CACHE BOOL "non supported option" FORCE)
set(SPDLOG_WCHAR_CONSOLE OFF CACHE BOOL "non supported option" FORCE)
endif() endif()
if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux") if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
@ -159,7 +161,7 @@ if(SPDLOG_BUILD_SHARED OR BUILD_SHARED_LIBS)
endif() endif()
add_library(spdlog SHARED ${SPDLOG_SRCS} ${SPDLOG_ALL_HEADERS}) add_library(spdlog SHARED ${SPDLOG_SRCS} ${SPDLOG_ALL_HEADERS})
target_compile_definitions(spdlog PUBLIC SPDLOG_SHARED_LIB) target_compile_definitions(spdlog PUBLIC SPDLOG_SHARED_LIB)
if(MSVC) if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
target_compile_options(spdlog PUBLIC $<$<AND:$<CXX_COMPILER_ID:MSVC>,$<NOT:$<COMPILE_LANGUAGE:CUDA>>>:/wd4251 target_compile_options(spdlog PUBLIC $<$<AND:$<CXX_COMPILER_ID:MSVC>,$<NOT:$<COMPILE_LANGUAGE:CUDA>>>:/wd4251
/wd4275>) /wd4275>)
endif() endif()
@ -237,9 +239,11 @@ endif()
# Misc definitions according to tweak options # Misc definitions according to tweak options
# --------------------------------------------------------------------------------------- # ---------------------------------------------------------------------------------------
set(SPDLOG_WCHAR_TO_UTF8_SUPPORT ${SPDLOG_WCHAR_SUPPORT}) set(SPDLOG_WCHAR_TO_UTF8_SUPPORT ${SPDLOG_WCHAR_SUPPORT})
set(SPDLOG_UTF8_TO_WCHAR_CONSOLE ${SPDLOG_WCHAR_CONSOLE})
foreach( foreach(
SPDLOG_OPTION SPDLOG_OPTION
SPDLOG_WCHAR_TO_UTF8_SUPPORT SPDLOG_WCHAR_TO_UTF8_SUPPORT
SPDLOG_UTF8_TO_WCHAR_CONSOLE
SPDLOG_WCHAR_FILENAMES SPDLOG_WCHAR_FILENAMES
SPDLOG_NO_EXCEPTIONS SPDLOG_NO_EXCEPTIONS
SPDLOG_CLOCK_COARSE SPDLOG_CLOCK_COARSE

View File

@ -437,7 +437,22 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent)
logger->info("Some info message"); logger->info("Some info message");
} }
``` ```
---
#### Mapped Diagnostic Context
```c++
// Mapped Diagnostic Context (MDC) is a map that stores key-value pairs (string values) in thread local storage.
// Each thread maintains its own MDC, which loggers use to append diagnostic information to log outputs.
// Note: it is not supported in asynchronous mode due to its reliance on thread-local storage.
#include "spdlog/mdc.h"
void mdc_example()
{
spdlog::mdc::put("key1", "value1");
spdlog::mdc::put("key2", "value2");
// if not using the default format, use the %& formatter to print mdc data
// spdlog::set_pattern("[%H:%M:%S %z] [%^%L%$] [%&] %v");
}
```
--- ---
## Benchmarks ## Benchmarks

View File

@ -26,6 +26,7 @@ void udp_example();
void custom_flags_example(); void custom_flags_example();
void file_events_example(); void file_events_example();
void replace_default_logger_example(); void replace_default_logger_example();
void mdc_example();
#include "spdlog/spdlog.h" #include "spdlog/spdlog.h"
#include "spdlog/cfg/env.h" // support for loading levels from the environment variable #include "spdlog/cfg/env.h" // support for loading levels from the environment variable
@ -84,6 +85,7 @@ int main(int, char *[]) {
custom_flags_example(); custom_flags_example();
file_events_example(); file_events_example();
replace_default_logger_example(); replace_default_logger_example();
mdc_example();
// Flush all *registered* loggers using a worker thread every 3 seconds. // Flush all *registered* loggers using a worker thread every 3 seconds.
// note: registered loggers *must* be thread safe for this to work correctly! // note: registered loggers *must* be thread safe for this to work correctly!
@ -270,7 +272,7 @@ struct my_type {
#ifndef SPDLOG_USE_STD_FORMAT // when using fmtlib #ifndef SPDLOG_USE_STD_FORMAT // when using fmtlib
template <> template <>
struct fmt::formatter<my_type> : fmt::formatter<std::string> { 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) const -> decltype(ctx.out()) {
return fmt::format_to(ctx.out(), "[my_type i={}]", my.i); return fmt::format_to(ctx.out(), "[my_type i={}]", my.i);
} }
}; };
@ -376,3 +378,16 @@ void replace_default_logger_example() {
spdlog::set_default_logger(old_logger); spdlog::set_default_logger(old_logger);
} }
// Mapped Diagnostic Context (MDC) is a map that stores key-value pairs (string values) in thread local storage.
// Each thread maintains its own MDC, which loggers use to append diagnostic information to log outputs.
// Note: it is not supported in asynchronous mode due to its reliance on thread-local storage.
#include "spdlog/mdc.h"
void mdc_example()
{
spdlog::mdc::put("key1", "value1");
spdlog::mdc::put("key2", "value2");
// if not using the default format, you can use the %& formatter to print mdc data as well
spdlog::set_pattern("[%H:%M:%S %z] [%^%L%$] [%&] %v");
spdlog::info("Some log message with context");
}

View File

@ -81,7 +81,7 @@
#if FMT_USE_CONSTEXPR #if FMT_USE_CONSTEXPR
#define SPDLOG_CONSTEXPR_FUNC FMT_CONSTEXPR #define SPDLOG_CONSTEXPR_FUNC FMT_CONSTEXPR
#else #else
#define SPDLOG_CONSTEXPR_FUNC inline #define SPDLOG_CONSTEXPR_FUNC inline
#endif #endif
#endif #endif

View File

@ -98,7 +98,7 @@ SPDLOG_INLINE void file_helper::close() {
} }
SPDLOG_INLINE void file_helper::write(const memory_buf_t &buf) { SPDLOG_INLINE void file_helper::write(const memory_buf_t &buf) {
if(fd_ == nullptr) return; if (fd_ == nullptr) return;
size_t msg_size = buf.size(); size_t msg_size = buf.size();
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) {

View File

@ -535,7 +535,7 @@ SPDLOG_INLINE bool create_dir(const filename_t &path) {
auto subdir = path.substr(0, token_pos); auto subdir = path.substr(0, token_pos);
#ifdef _WIN32 #ifdef _WIN32
// if subdir is just a drive letter, add a slash e.g. "c:"=>"c:\", // if subdir is just a drive letter, add a slash e.g. "c:"=>"c:\",
// otherwise path_exists(subdir) returns false (issue #3079) // otherwise path_exists(subdir) returns false (issue #3079)
const bool is_drive = subdir.length() == 2 && subdir[1] == ':'; const bool is_drive = subdir.length() == 2 && subdir[1] == ':';
if (is_drive) { if (is_drive) {

View File

@ -84,7 +84,6 @@ SPDLOG_INLINE std::shared_ptr<logger> registry::get(const std::string &logger_na
return found == loggers_.end() ? nullptr : found->second; return found == loggers_.end() ? nullptr : found->second;
} }
SPDLOG_INLINE std::shared_ptr<logger> registry::default_logger() { SPDLOG_INLINE std::shared_ptr<logger> registry::default_logger() {
std::lock_guard<std::mutex> lock(logger_map_mutex_); std::lock_guard<std::mutex> lock(logger_map_mutex_);
return default_logger_; return default_logger_;
@ -99,7 +98,7 @@ SPDLOG_INLINE logger *registry::get_default_raw() { return default_logger_.get()
// set default logger. // set default logger.
// default logger is stored in default_logger_ (for faster retrieval) and in the loggers_ map. // default logger is stored in default_logger_ (for faster retrieval) and in the loggers_ map.
SPDLOG_INLINE void registry::set_default_logger(std::shared_ptr<logger> new_default_logger) { SPDLOG_INLINE void registry::set_default_logger(std::shared_ptr<logger> new_default_logger) {
std::lock_guard<std::mutex> lock(logger_map_mutex_); std::lock_guard<std::mutex> lock(logger_map_mutex_);
if (new_default_logger != nullptr) { if (new_default_logger != nullptr) {
loggers_[new_default_logger->name()] = new_default_logger; loggers_[new_default_logger->name()] = new_default_logger;
} }

View File

@ -44,7 +44,8 @@ public:
// set default logger and add it to the registry if not registered already. // set default logger and add it to the registry if not registered already.
// default logger is stored in default_logger_ (for faster retrieval) and in the loggers_ map. // default logger is stored in default_logger_ (for faster retrieval) and in the loggers_ map.
// Note: Make sure to unregister it when no longer needed or before calling again with a new logger. // Note: Make sure to unregister it when no longer needed or before calling again with a new
// logger.
void set_default_logger(std::shared_ptr<logger> new_default_logger); void set_default_logger(std::shared_ptr<logger> new_default_logger);
void set_tp(std::shared_ptr<thread_pool> tp); void set_tp(std::shared_ptr<thread_pool> tp);
@ -70,8 +71,8 @@ public:
} }
std::unique_ptr<periodic_worker> &get_flusher() { std::unique_ptr<periodic_worker> &get_flusher() {
std::lock_guard<std::mutex> lock(flusher_mutex_); std::lock_guard<std::mutex> lock(flusher_mutex_);
return periodic_flusher_; return periodic_flusher_;
} }
void set_error_handler(err_handler handler); void set_error_handler(err_handler handler);

View File

@ -67,9 +67,7 @@ struct async_msg : log_msg_buffer {
worker_ptr{std::move(worker)}, worker_ptr{std::move(worker)},
flush_promise{} {} flush_promise{} {}
async_msg(async_logger_ptr &&worker, async_msg(async_logger_ptr &&worker, async_msg_type the_type, std::promise<void> &&promise)
async_msg_type the_type,
std::promise<void> &&promise)
: log_msg_buffer{}, : log_msg_buffer{},
msg_type{the_type}, msg_type{the_type},
worker_ptr{std::move(worker)}, worker_ptr{std::move(worker)},

View File

@ -20,7 +20,7 @@
#ifndef FMT_USE_WINDOWS_H #ifndef FMT_USE_WINDOWS_H
#define FMT_USE_WINDOWS_H 0 #define FMT_USE_WINDOWS_H 0
#endif #endif
#include <spdlog/fmt/bundled/core.h> #include <spdlog/fmt/bundled/core.h>
#include <spdlog/fmt/bundled/format.h> #include <spdlog/fmt/bundled/format.h>

View File

@ -1,3 +1,6 @@
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
#pragma once #pragma once
#include <map> #include <map>
@ -5,32 +8,39 @@
#include <spdlog/common.h> #include <spdlog/common.h>
// MDC is a simple map of key->string values stored in thread local storage whose content will be printed by the loggers.
// Note: Not supported in async mode (thread local storage - so the async thread pool have different copy).
//
// Usage example:
// spdlog::mdc::put("mdc_key_1", "mdc_value_1");
// spdlog::info("Hello, {}", "World!"); // => [2024-04-26 02:08:05.040] [info] [mdc_key_1:mdc_value_1] Hello, World!
namespace spdlog { namespace spdlog {
class SPDLOG_API mdc { class SPDLOG_API mdc {
public: public:
using mdc_map_t = std::map<std::string, std::string>; using mdc_map_t = std::map<std::string, std::string>;
static void put(const std::string &key, const std::string &value) { static void put(const std::string &key, const std::string &value) {
get_context()[key] = value; get_context()[key] = value;
}
static std::string get(const std::string &key) {
auto &context = get_context();
auto it = context.find(key);
if (it != context.end()) {
return it->second;
} }
return "";
}
static std::string get(const std::string &key) { static void remove(const std::string &key) { get_context().erase(key); }
auto &context = get_context();
auto it = context.find(key);
if (it != context.end()) {
return it->second;
}
return "";
}
static void remove(const std::string &key) { get_context().erase(key); } static void clear() { get_context().clear(); }
static void clear() { get_context().clear(); } static mdc_map_t &get_context() {
static thread_local mdc_map_t context;
static mdc_map_t &get_context() { return context;
static thread_local mdc_map_t context; }
return context; };
}
};
} // namespace spdlog } // namespace spdlog

View File

@ -790,7 +790,7 @@ template <typename ScopedPadder>
class mdc_formatter : public flag_formatter { class mdc_formatter : public flag_formatter {
public: public:
explicit mdc_formatter(padding_info padinfo) explicit mdc_formatter(padding_info padinfo)
: flag_formatter(padinfo) {} : flag_formatter(padinfo) {}
void format(const details::log_msg &, const std::tm &, memory_buf_t &dest) override { void format(const details::log_msg &, const std::tm &, memory_buf_t &dest) override {
auto &mdc_map = mdc::get_context(); auto &mdc_map = mdc::get_context();
@ -802,7 +802,7 @@ public:
} }
} }
void format_mdc(const mdc::mdc_map_t &mdc_map, memory_buf_t &dest){ void format_mdc(const mdc::mdc_map_t &mdc_map, memory_buf_t &dest) {
auto last_element = --mdc_map.end(); auto last_element = --mdc_map.end();
for (auto it = mdc_map.begin(); it != mdc_map.end(); ++it) { for (auto it = mdc_map.begin(); it != mdc_map.end(); ++it) {
auto &pair = *it; auto &pair = *it;
@ -825,8 +825,6 @@ public:
} }
}; };
// Full info formatter // Full info formatter
// pattern: [%Y-%m-%d %H:%M:%S.%e] [%n] [%l] [%s:%#] %v // pattern: [%Y-%m-%d %H:%M:%S.%e] [%n] [%l] [%s:%#] %v
class full_formatter final : public flag_formatter { class full_formatter final : public flag_formatter {
@ -921,8 +919,6 @@ private:
mdc_formatter<null_scoped_padder> mdc_formatter_{padding_info{}}; mdc_formatter<null_scoped_padder> mdc_formatter_{padding_info{}};
}; };
} // namespace details } // namespace details
SPDLOG_INLINE pattern_formatter::pattern_formatter(std::string pattern, SPDLOG_INLINE pattern_formatter::pattern_formatter(std::string pattern,

View File

@ -60,7 +60,7 @@ SPDLOG_INLINE filename_t rotating_file_sink<Mutex>::calc_filename(const filename
filename_t basename, ext; filename_t basename, ext;
std::tie(basename, ext) = details::file_helper::split_by_extension(filename); std::tie(basename, ext) = details::file_helper::split_by_extension(filename);
return fmt_lib::format(SPDLOG_FILENAME_T("{}.{}{}"), basename, index, ext); return fmt_lib::format(SPDLOG_FMT_STRING(SPDLOG_FILENAME_T("{}.{}{}")), basename, index, ext);
} }
template <typename Mutex> template <typename Mutex>

View File

@ -64,13 +64,14 @@ protected:
// //
// Simply maps spdlog's log level to syslog priority level. // Simply maps spdlog's log level to syslog priority level.
// //
int syslog_prio_from_level(const details::log_msg &msg) const { virtual int syslog_prio_from_level(const details::log_msg &msg) const {
return syslog_levels_.at(static_cast<levels_array::size_type>(msg.level)); return syslog_levels_.at(static_cast<levels_array::size_type>(msg.level));
} }
private:
using levels_array = std::array<int, 7>; using levels_array = std::array<int, 7>;
levels_array syslog_levels_; levels_array syslog_levels_;
private:
// must store the ident because the man says openlog might use the pointer as // must store the ident because the man says openlog might use the pointer as
// is and not a string copy // is and not a string copy
const std::string ident_; const std::string ident_;

View File

@ -134,9 +134,18 @@ void SPDLOG_INLINE wincolor_sink<ConsoleMutex>::print_range_(const memory_buf_t
size_t start, size_t start,
size_t end) { size_t end) {
if (end > start) { if (end > start) {
#if defined(SPDLOG_UTF8_TO_WCHAR_CONSOLE)
wmemory_buf_t wformatted;
details::os::utf8_to_wstrbuf(string_view_t(formatted.data() + start, end - start),
wformatted);
auto size = static_cast<DWORD>(wformatted.size());
auto ignored = ::WriteConsoleW(static_cast<HANDLE>(out_handle_), wformatted.data(), size,
nullptr, nullptr);
#else
auto size = static_cast<DWORD>(end - start); auto size = static_cast<DWORD>(end - start);
auto ignored = ::WriteConsoleA(static_cast<HANDLE>(out_handle_), formatted.data() + start, auto ignored = ::WriteConsoleA(static_cast<HANDLE>(out_handle_), formatted.data() + start,
size, nullptr, nullptr); size, nullptr, nullptr);
#endif
(void)(ignored); (void)(ignored);
} }
} }

View File

@ -20,7 +20,6 @@ SPDLOG_INLINE std::shared_ptr<logger> get(const std::string &name) {
return details::registry::instance().get(name); return details::registry::instance().get(name);
} }
SPDLOG_INLINE void set_formatter(std::unique_ptr<spdlog::formatter> formatter) { SPDLOG_INLINE void set_formatter(std::unique_ptr<spdlog::formatter> formatter) {
details::registry::instance().set_formatter(std::move(formatter)); details::registry::instance().set_formatter(std::move(formatter));
} }

View File

@ -5,7 +5,7 @@
#define SPDLOG_VER_MAJOR 1 #define SPDLOG_VER_MAJOR 1
#define SPDLOG_VER_MINOR 14 #define SPDLOG_VER_MINOR 14
#define SPDLOG_VER_PATCH 0 #define SPDLOG_VER_PATCH 1
#define SPDLOG_TO_VERSION(major, minor, patch) (major * 10000 + minor * 100 + patch) #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) #define SPDLOG_VERSION SPDLOG_TO_VERSION(SPDLOG_VER_MAJOR, SPDLOG_VER_MINOR, SPDLOG_VER_PATCH)

View File

@ -132,8 +132,8 @@ TEST_CASE("multithread flush", "[async]") {
} }
REQUIRE(test_sink->flush_counter() >= 1); REQUIRE(test_sink->flush_counter() >= 1);
REQUIRE(test_sink->flush_counter() + errmsgs.size() == n_threads * flush_count); REQUIRE(test_sink->flush_counter() + errmsgs.size() == n_threads * flush_count);
if (errmsgs.size() > 0) { if (errmsgs.size() > 0) {
REQUIRE(errmsgs[0] == "Broken promise"); REQUIRE(errmsgs[0] == "Broken promise");
} }
} }

View File

@ -84,23 +84,23 @@ TEST_CASE("dir_name", "[create_dir]") {
#ifdef _WIN32 #ifdef _WIN32
// //
// test windows cases when drive letter is given e.g. C:\\some-folder // test windows cases when drive letter is given e.g. C:\\some-folder
// //
#include <windows.h> #include <windows.h>
#include <fileapi.h> #include <fileapi.h>
std::string get_full_path(const std::string &relative_folder_path) { std::string get_full_path(const std::string &relative_folder_path) {
char full_path[MAX_PATH]; char full_path[MAX_PATH];
DWORD result = ::GetFullPathNameA(relative_folder_path.c_str(), MAX_PATH, full_path, nullptr); DWORD result = ::GetFullPathNameA(relative_folder_path.c_str(), MAX_PATH, full_path, nullptr);
// Return an empty string if failed to get full path // Return an empty string if failed to get full path
return result > 0 && result < MAX_PATH ? std::string(full_path) : std::string(); return result > 0 && result < MAX_PATH ? std::string(full_path) : std::string();
} }
std::wstring get_full_path(const std::wstring &relative_folder_path) { std::wstring get_full_path(const std::wstring &relative_folder_path) {
wchar_t full_path[MAX_PATH]; wchar_t full_path[MAX_PATH];
DWORD result = ::GetFullPathNameW(relative_folder_path.c_str(), MAX_PATH, full_path, nullptr); DWORD result = ::GetFullPathNameW(relative_folder_path.c_str(), MAX_PATH, full_path, nullptr);
return result > 0 && result < MAX_PATH ? std::wstring(full_path) : std::wstring(); return result > 0 && result < MAX_PATH ? std::wstring(full_path) : std::wstring();
} }
@ -109,16 +109,16 @@ spdlog::filename_t::value_type find_non_existing_drive() {
std::string root_path = std::string(1, drive) + ":\\"; std::string root_path = std::string(1, drive) + ":\\";
UINT drive_type = GetDriveTypeA(root_path.c_str()); UINT drive_type = GetDriveTypeA(root_path.c_str());
if (drive_type == DRIVE_NO_ROOT_DIR) { if (drive_type == DRIVE_NO_ROOT_DIR) {
return static_cast <spdlog::filename_t::value_type>(drive); return static_cast<spdlog::filename_t::value_type>(drive);
} }
} }
return '\0'; // No available drive found return '\0'; // No available drive found
} }
TEST_CASE("create_abs_path1", "[create_dir]") { TEST_CASE("create_abs_path1", "[create_dir]") {
prepare_logdir(); prepare_logdir();
auto abs_path = get_full_path(SPDLOG_FILENAME_T("test_logs\\logdir1")); auto abs_path = get_full_path(SPDLOG_FILENAME_T("test_logs\\logdir1"));
REQUIRE(!abs_path.empty()); REQUIRE(!abs_path.empty());
REQUIRE(create_dir(abs_path) == true); REQUIRE(create_dir(abs_path) == true);
} }
@ -126,20 +126,19 @@ TEST_CASE("create_abs_path2", "[create_dir]") {
prepare_logdir(); prepare_logdir();
auto abs_path = get_full_path(SPDLOG_FILENAME_T("test_logs/logdir2")); auto abs_path = get_full_path(SPDLOG_FILENAME_T("test_logs/logdir2"));
REQUIRE(!abs_path.empty()); REQUIRE(!abs_path.empty());
REQUIRE(create_dir(abs_path) == true); REQUIRE(create_dir(abs_path) == true);
} }
TEST_CASE("non_existing_drive", "[create_dir]") { TEST_CASE("non_existing_drive", "[create_dir]") {
prepare_logdir(); prepare_logdir();
spdlog::filename_t path; spdlog::filename_t path;
auto non_existing_drive = find_non_existing_drive(); auto non_existing_drive = find_non_existing_drive();
path += non_existing_drive ; path += non_existing_drive;
path += SPDLOG_FILENAME_T(":\\"); path += SPDLOG_FILENAME_T(":\\");
REQUIRE(create_dir(path) == false); REQUIRE(create_dir(path) == false);
path += SPDLOG_FILENAME_T("subdir"); path += SPDLOG_FILENAME_T("subdir");
REQUIRE(create_dir(path) == false); REQUIRE(create_dir(path) == false);
} }
//#endif // SPDLOG_WCHAR_FILENAMES // #endif // SPDLOG_WCHAR_FILENAMES
#endif // _WIN32 #endif // _WIN32