mirror of
https://github.com/gabime/spdlog.git
synced 2024-12-25 10:01:33 +08:00
Use std filesystem (#3284)
* Use std::filesystem for path names and impl
This commit is contained in:
parent
daf1b97b8f
commit
08c727e4f8
@ -86,6 +86,7 @@ endif()
|
||||
option(SPDLOG_PREVENT_CHILD_FD "Prevent from child processes to inherit log file descriptors" OFF)
|
||||
option(SPDLOG_NO_THREAD_ID "prevent spdlog from querying the thread id on each log call if thread id is not needed" OFF)
|
||||
option(SPDLOG_DISABLE_DEFAULT_LOGGER "Disable default logger creation" OFF)
|
||||
option(SPDLOG_NO_TLS "Disable thread local storage" OFF)
|
||||
|
||||
# clang-tidy
|
||||
option(SPDLOG_TIDY "run clang-tidy" OFF)
|
||||
@ -198,6 +199,7 @@ set(SPDLOG_SRCS
|
||||
"src/spdlog.cpp"
|
||||
"src/cfg/helpers.cpp"
|
||||
"src/details/file_helper.cpp"
|
||||
"src/details/os_filesystem.cpp"
|
||||
"src/details/log_msg.cpp"
|
||||
"src/details/log_msg_buffer.cpp"
|
||||
"src/details/periodic_worker.cpp"
|
||||
@ -307,8 +309,13 @@ endif()
|
||||
# ---------------------------------------------------------------------------------------
|
||||
# spdlog private defines according to the options
|
||||
# ---------------------------------------------------------------------------------------
|
||||
foreach(SPDLOG_OPTION SPDLOG_CLOCK_COARSE SPDLOG_PREVENT_CHILD_FD SPDLOG_NO_THREAD_ID SPDLOG_DISABLE_DEFAULT_LOGGER
|
||||
SPDLOG_FWRITE_UNLOCKED)
|
||||
foreach(SPDLOG_OPTION
|
||||
SPDLOG_CLOCK_COARSE
|
||||
SPDLOG_PREVENT_CHILD_FD
|
||||
SPDLOG_NO_THREAD_ID
|
||||
SPDLOG_DISABLE_DEFAULT_LOGGER
|
||||
SPDLOG_NO_TLS
|
||||
SPDLOG_FWRITE_UNLOCKED)
|
||||
if(${SPDLOG_OPTION})
|
||||
target_compile_definitions(spdlog PRIVATE ${SPDLOG_OPTION})
|
||||
endif()
|
||||
|
@ -1,4 +1,4 @@
|
||||
//
|
||||
//
|
||||
// Copyright(c) 2015 Gabi Melman.
|
||||
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||
|
||||
@ -299,16 +299,16 @@ void custom_flags_example() {
|
||||
void file_events_example() {
|
||||
// pass the spdlog::file_event_handlers to file sinks for open/close log file notifications
|
||||
spdlog::file_event_handlers handlers;
|
||||
handlers.before_open = [](spdlog::filename_t filename) { spdlog::info("Before opening {}", filename); };
|
||||
handlers.after_open = [](spdlog::filename_t filename, std::FILE *fstream) {
|
||||
spdlog::info("After opening {}", filename);
|
||||
handlers.before_open = [](spdlog::filename_t) { spdlog::info("Before opening logfile"); };
|
||||
handlers.after_open = [](spdlog::filename_t, std::FILE *fstream) {
|
||||
spdlog::info("After opening logfile");
|
||||
fputs("After opening\n", fstream);
|
||||
};
|
||||
handlers.before_close = [](spdlog::filename_t filename, std::FILE *fstream) {
|
||||
spdlog::info("Before closing {}", filename);
|
||||
handlers.before_close = [](spdlog::filename_t, std::FILE *fstream) {
|
||||
spdlog::info("Before closing logfile");
|
||||
fputs("Before closing\n", fstream);
|
||||
};
|
||||
handlers.after_close = [](spdlog::filename_t filename) { spdlog::info("After closing {}", filename); };
|
||||
handlers.after_close = [](spdlog::filename_t) { spdlog::info("After closing logfile"); };
|
||||
auto file_sink = std::make_shared<spdlog::sinks::basic_file_sink_mt>("logs/events-sample.txt", true, handlers);
|
||||
spdlog::logger my_logger("some_logger", file_sink);
|
||||
my_logger.info("Some log line");
|
||||
|
@ -5,14 +5,14 @@
|
||||
|
||||
#include <array>
|
||||
#include <atomic>
|
||||
#include <chrono>
|
||||
#include <cstdio>
|
||||
#include <exception>
|
||||
#include <functional>
|
||||
#include <initializer_list>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
#include <chrono>
|
||||
#include <string_view>
|
||||
|
||||
#include "./source_loc.h"
|
||||
|
||||
@ -47,9 +47,6 @@ namespace sinks {
|
||||
class sink;
|
||||
}
|
||||
|
||||
using filename_t = std::string;
|
||||
#define SPDLOG_FILENAME_T(s) s
|
||||
|
||||
using log_clock = std::chrono::system_clock;
|
||||
using sink_ptr = std::shared_ptr<sinks::sink>;
|
||||
using sinks_init_list = std::initializer_list<sink_ptr>;
|
||||
@ -64,7 +61,6 @@ using wmemory_buf_t = fmt::basic_memory_buffer<wchar_t, 250>;
|
||||
template <typename... Args>
|
||||
using format_string_t = fmt::format_string<Args...>;
|
||||
|
||||
#define SPDLOG_BUF_TO_STRING(x) fmt::to_string(x)
|
||||
#define SPDLOG_LEVEL_TRACE 0
|
||||
#define SPDLOG_LEVEL_DEBUG 1
|
||||
#define SPDLOG_LEVEL_INFO 2
|
||||
@ -102,7 +98,7 @@ constexpr std::array<std::string_view, levels_count> short_level_names{"T", "D",
|
||||
return level_string_views.at(level_to_number(lvl));
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr const std::string_view to_short_string_view(spdlog::level lvl) noexcept {
|
||||
[[nodiscard]] constexpr std::string_view to_short_string_view(spdlog::level lvl) noexcept {
|
||||
return short_level_names.at(level_to_number(lvl));
|
||||
}
|
||||
|
||||
@ -140,33 +136,4 @@ private:
|
||||
[[noreturn]] SPDLOG_API void throw_spdlog_ex(const std::string &msg, int last_errno);
|
||||
[[noreturn]] SPDLOG_API void throw_spdlog_ex(std::string msg);
|
||||
|
||||
struct file_event_handlers {
|
||||
file_event_handlers()
|
||||
: before_open(nullptr),
|
||||
after_open(nullptr),
|
||||
before_close(nullptr),
|
||||
after_close(nullptr) {}
|
||||
|
||||
std::function<void(const filename_t &filename)> before_open;
|
||||
std::function<void(const filename_t &filename, std::FILE *file_stream)> after_open;
|
||||
std::function<void(const filename_t &filename, std::FILE *file_stream)> before_close;
|
||||
std::function<void(const filename_t &filename)> after_close;
|
||||
};
|
||||
|
||||
namespace details {
|
||||
|
||||
// to_string_view
|
||||
|
||||
[[nodiscard]] constexpr spdlog::string_view_t to_string_view(const memory_buf_t &buf) noexcept {
|
||||
return spdlog::string_view_t{buf.data(), buf.size()};
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr spdlog::string_view_t to_string_view(spdlog::string_view_t str) noexcept { return str; }
|
||||
|
||||
template <typename T, typename... Args>
|
||||
[[nodiscard]] constexpr fmt::basic_string_view<T> to_string_view(fmt::basic_format_string<T, Args...> fmt) noexcept {
|
||||
return fmt;
|
||||
}
|
||||
|
||||
} // namespace details
|
||||
} // namespace spdlog
|
||||
|
@ -6,6 +6,7 @@
|
||||
#include <tuple>
|
||||
|
||||
#include "../common.h"
|
||||
#include "../file_event_handlers.h"
|
||||
|
||||
namespace spdlog {
|
||||
namespace details {
|
||||
@ -32,21 +33,6 @@ public:
|
||||
size_t size() const;
|
||||
const filename_t &filename() const;
|
||||
|
||||
//
|
||||
// return file path and its extension:
|
||||
//
|
||||
// "mylog.txt" => ("mylog", ".txt")
|
||||
// "mylog" => ("mylog", "")
|
||||
// "mylog." => ("mylog.", "")
|
||||
// "/dir1/dir2/mylog.txt" => ("/dir1/dir2/mylog", ".txt")
|
||||
//
|
||||
// the starting dot in filenames is ignored (hidden files):
|
||||
//
|
||||
// ".mylog" => (".mylog". "")
|
||||
// "my_folder/.mylog" => ("my_folder/.mylog", "")
|
||||
// "my_folder/.mylog.txt" => ("my_folder/.mylog", ".txt")
|
||||
static std::tuple<filename_t, filename_t> split_by_extension(const filename_t &fname);
|
||||
|
||||
private:
|
||||
const int open_tries_ = 5;
|
||||
const unsigned int open_interval_ = 10;
|
||||
|
@ -4,8 +4,9 @@
|
||||
#pragma once
|
||||
|
||||
#include <ctime> // std::time_t
|
||||
|
||||
#include <tuple>
|
||||
#include "../common.h"
|
||||
#include "../filename_t.h"
|
||||
|
||||
namespace spdlog {
|
||||
namespace details {
|
||||
@ -24,27 +25,13 @@ SPDLOG_API std::tm gmtime() noexcept;
|
||||
// eol definition and folder separator for the current os
|
||||
#ifdef _WIN32
|
||||
constexpr static const char *default_eol = "\r\n";
|
||||
constexpr static const filename_t::value_type folder_seps_filename[] = SPDLOG_FILENAME_T("\\/");
|
||||
#else
|
||||
constexpr static const char *default_eol = "\n";
|
||||
constexpr static const filename_t::value_type folder_seps_filename[] = SPDLOG_FILENAME_T("/");
|
||||
#endif
|
||||
|
||||
// fopen_s on non windows for writing
|
||||
SPDLOG_API bool fopen_s(FILE **fp, const filename_t &filename, const filename_t &mode);
|
||||
|
||||
// Remove filename. return 0 on success
|
||||
SPDLOG_API int remove(const filename_t &filename) noexcept;
|
||||
|
||||
// Remove file if exists. return 0 on success
|
||||
// Note: Non atomic (might return failure to delete if concurrently deleted by other process/thread)
|
||||
SPDLOG_API int remove_if_exists(const filename_t &filename) noexcept;
|
||||
|
||||
SPDLOG_API int rename(const filename_t &filename1, const filename_t &filename2) noexcept;
|
||||
|
||||
// Return if file exists.
|
||||
SPDLOG_API bool path_exists(const filename_t &filename) noexcept;
|
||||
|
||||
// Return file size according to open FILE* object
|
||||
SPDLOG_API size_t filesize(FILE *f);
|
||||
|
||||
@ -63,8 +50,7 @@ SPDLOG_API size_t thread_id() noexcept;
|
||||
// See https://github.com/gabime/spdlog/issues/609
|
||||
SPDLOG_API void sleep_for_millis(unsigned int milliseconds) noexcept;
|
||||
|
||||
SPDLOG_API std::string filename_to_str(const filename_t &filename);
|
||||
|
||||
// Return pid
|
||||
SPDLOG_API int pid() noexcept;
|
||||
|
||||
// Determine if the terminal supports colors
|
||||
@ -80,16 +66,6 @@ SPDLOG_API void wstr_to_utf8buf(wstring_view_t wstr, memory_buf_t &target);
|
||||
SPDLOG_API void utf8_to_wstrbuf(string_view_t str, wmemory_buf_t &target);
|
||||
#endif
|
||||
|
||||
// Return directory name from given path or empty string
|
||||
// "abc/file" => "abc"
|
||||
// "abc/" => "abc"
|
||||
// "abc" => ""
|
||||
// "abc///" => "abc//"
|
||||
SPDLOG_API filename_t dir_name(const filename_t &path);
|
||||
|
||||
// Create a dir from the given path.
|
||||
// Return true if succeeded or if this dir already exists.
|
||||
SPDLOG_API bool create_dir(const filename_t &path);
|
||||
|
||||
// non thread safe, cross platform getenv/getenv_s
|
||||
// return empty string if field not found
|
||||
@ -103,6 +79,52 @@ SPDLOG_API bool fsync(FILE *fp);
|
||||
// Return true on success.
|
||||
SPDLOG_API bool fwrite_bytes(const void *ptr, const size_t n_bytes, FILE *fp);
|
||||
|
||||
//
|
||||
// std::filesystem wrapper functions
|
||||
//
|
||||
|
||||
// Return directory name from given path or empty string
|
||||
// "abc/file" => "abc"
|
||||
// "abc/" => "abc"
|
||||
// "abc" => ""
|
||||
SPDLOG_API filename_t dir_name(const filename_t &path);
|
||||
|
||||
// Create a dir from the given path.
|
||||
// Return true if succeeded or if this dir already exists.
|
||||
SPDLOG_API bool create_dir(const filename_t &path);
|
||||
|
||||
// Remove filename. return true on success
|
||||
SPDLOG_API bool remove(const filename_t &filename);
|
||||
|
||||
// Remove file if exists. return 0 on success
|
||||
// Note: Non atomic (might return failure to delete if concurrently deleted by other process/thread)
|
||||
SPDLOG_API bool remove_if_exists(const filename_t &filename);
|
||||
|
||||
// Rename file. return true on success
|
||||
SPDLOG_API bool rename(const filename_t &filename1, const filename_t &filename2) noexcept;
|
||||
|
||||
// Return if file exists.
|
||||
SPDLOG_API bool path_exists(const filename_t &filename) noexcept;
|
||||
|
||||
|
||||
// Return file path and its extension:
|
||||
//
|
||||
// "mylog.txt" => ("mylog", ".txt")
|
||||
// "mylog" => ("mylog", "")
|
||||
// "mylog." => ("mylog.", "")
|
||||
// "/dir1/dir2/mylog.txt" => ("/dir1/dir2/mylog", ".txt")
|
||||
//
|
||||
// the starting dot in filenames is ignored (hidden files):
|
||||
//
|
||||
// ".mylog" => (".mylog". "")
|
||||
// "my_folder/.mylog" => ("my_folder/.mylog", "")
|
||||
// "my_folder/.mylog.txt" => ("my_folder/.mylog", ".txt")
|
||||
SPDLOG_API std::tuple<filename_t, filename_t> split_by_extension(const filename_t &fname);
|
||||
|
||||
// Try tp convert filename to string. Return "??" if failed
|
||||
SPDLOG_API std::string filename_to_str(const filename_t &filename);
|
||||
|
||||
|
||||
} // namespace os
|
||||
} // namespace details
|
||||
} // namespace spdlog
|
||||
|
19
include/spdlog/file_event_handlers.h
Normal file
19
include/spdlog/file_event_handlers.h
Normal file
@ -0,0 +1,19 @@
|
||||
#pragma once
|
||||
|
||||
#include <functional>
|
||||
#include "./filename_t.h"
|
||||
|
||||
namespace spdlog {
|
||||
struct file_event_handlers {
|
||||
file_event_handlers()
|
||||
: before_open(nullptr),
|
||||
after_open(nullptr),
|
||||
before_close(nullptr),
|
||||
after_close(nullptr) {}
|
||||
|
||||
std::function<void(const filename_t &filename)> before_open;
|
||||
std::function<void(const filename_t &filename, std::FILE *file_stream)> after_open;
|
||||
std::function<void(const filename_t &filename, std::FILE *file_stream)> before_close;
|
||||
std::function<void(const filename_t &filename)> after_close;
|
||||
};
|
||||
} // namespace spdlog
|
18
include/spdlog/filename_t.h
Normal file
18
include/spdlog/filename_t.h
Normal file
@ -0,0 +1,18 @@
|
||||
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
|
||||
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <filesystem>
|
||||
|
||||
#ifdef _WIN32
|
||||
// In windows, add L prefix for filename literals (e.g. L"filename.txt")
|
||||
#define SPDLOG_FILENAME_T_INNER(s) L##s
|
||||
#define SPDLOG_FILENAME_T(s) SPDLOG_FILENAME_T_INNER(s)
|
||||
#else
|
||||
#define SPDLOG_FILENAME_T(s) s
|
||||
#endif
|
||||
|
||||
namespace spdlog {
|
||||
using filename_t = std::filesystem::path;
|
||||
} // namespace spdlog
|
@ -6,3 +6,4 @@
|
||||
#pragma once
|
||||
|
||||
#include "fmt/format.h"
|
||||
#include "fmt/xchar.h"
|
||||
|
@ -11,41 +11,43 @@
|
||||
#include <string>
|
||||
|
||||
#include "../common.h"
|
||||
#include "./base_sink.h"
|
||||
#include "../details/circular_q.h"
|
||||
#include "../details/file_helper.h"
|
||||
#include "../details/null_mutex.h"
|
||||
#include "../details/os.h"
|
||||
#include "../details/synchronous_factory.h"
|
||||
#include "./base_sink.h"
|
||||
|
||||
|
||||
namespace spdlog {
|
||||
namespace sinks {
|
||||
|
||||
/*
|
||||
* Generator of daily log file names in format basename.YYYY-MM-DD.ext
|
||||
* Generator of daily log file names in format basename_YYYY-MM-DD.ext
|
||||
*/
|
||||
struct daily_filename_calculator {
|
||||
// Create filename for the form basename.YYYY-MM-DD
|
||||
struct daily_filename_calculator {
|
||||
static filename_t calc_filename(const filename_t &filename, const tm &now_tm) {
|
||||
filename_t basename, ext;
|
||||
std::tie(basename, ext) = details::file_helper::split_by_extension(filename);
|
||||
return fmt_lib::format(SPDLOG_FMT_STRING(SPDLOG_FILENAME_T("{}_{:04d}-{:02d}-{:02d}{}")), basename, now_tm.tm_year + 1900,
|
||||
now_tm.tm_mon + 1, now_tm.tm_mday, ext);
|
||||
std::tie(basename, ext) = details::os::split_by_extension(filename);
|
||||
std::basic_ostringstream<filename_t::value_type> oss;
|
||||
oss << basename.native() << '_' << std::setfill(SPDLOG_FILENAME_T('0')) << std::setw(4) << now_tm.tm_year + 1900 << '-'
|
||||
<< std::setw(2) << now_tm.tm_mon + 1 << '-' << std::setw(2) << now_tm.tm_mday << ext.native();
|
||||
return oss.str();
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* Generator of daily log file names with strftime format.
|
||||
* Usages:
|
||||
* auto sink =
|
||||
* std::make_shared<spdlog::sinks::daily_file_format_sink_mt>("myapp-%Y-%m-%d:%H:%M:%S.log", hour,
|
||||
* minute);" auto logger = spdlog::daily_logger_format_mt("loggername, "myapp-%Y-%m-%d:%X.log",
|
||||
* hour, minute)"
|
||||
*
|
||||
* std::make_shared<spdlog::sinks::daily_file_format_sink_mt>("myapp-%Y-%m-%d:%H:%M:%S.log", hour, minute);
|
||||
* or
|
||||
* spdlog::daily_logger_format_mt("loggername, "myapp-%Y-%m-%d:%X.log", hour, minute)"
|
||||
*
|
||||
*/
|
||||
struct daily_filename_format_calculator {
|
||||
static filename_t calc_filename(const filename_t &file_path, const tm &now_tm) {
|
||||
std::stringstream stream;
|
||||
std::basic_ostringstream<filename_t::value_type> stream;
|
||||
stream << std::put_time(&now_tm, file_path.c_str());
|
||||
return stream.str();
|
||||
}
|
||||
@ -164,7 +166,7 @@ private:
|
||||
if (filenames_q_.full()) {
|
||||
auto old_filename = std::move(filenames_q_.front());
|
||||
filenames_q_.pop_front();
|
||||
bool ok = remove_if_exists(old_filename) == 0;
|
||||
bool ok = remove_if_exists(old_filename);
|
||||
if (!ok) {
|
||||
filenames_q_.push_back(std::move(current_file));
|
||||
throw_spdlog_ex("Failed removing daily file " + filename_to_str(old_filename), errno);
|
||||
|
@ -22,15 +22,17 @@ namespace spdlog {
|
||||
namespace sinks {
|
||||
|
||||
/*
|
||||
* Generator of Hourly log file names in format basename.YYYY-MM-DD-HH.ext
|
||||
* Generator of Hourly log file names in format basename_YYYY-MM-DD_HH.ext
|
||||
*/
|
||||
struct hourly_filename_calculator {
|
||||
// Create filename for the form basename.YYYY-MM-DD-H
|
||||
static filename_t calc_filename(const filename_t &filename, const tm &now_tm) {
|
||||
filename_t basename, ext;
|
||||
std::tie(basename, ext) = details::file_helper::split_by_extension(filename);
|
||||
return fmt_lib::format(SPDLOG_FILENAME_T("{}_{:04d}-{:02d}-{:02d}_{:02d}{}"), basename, now_tm.tm_year + 1900,
|
||||
now_tm.tm_mon + 1, now_tm.tm_mday, now_tm.tm_hour, ext);
|
||||
std::tie(basename, ext) = details::os::split_by_extension(filename);
|
||||
std::basic_ostringstream<filename_t::value_type> oss;
|
||||
oss << basename.native() << '_' << std::setfill(SPDLOG_FILENAME_T('0')) << std::setw(4) << now_tm.tm_year + 1900 << '-'
|
||||
<< std::setw(2) << now_tm.tm_mon + 1 << '-' << std::setw(2) << now_tm.tm_mday << '_' << std::setw(2) << now_tm.tm_hour
|
||||
<< ext.native();
|
||||
return oss.str();
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -43,7 +43,7 @@ private:
|
||||
|
||||
// delete the target if exists, and rename the src file to target
|
||||
// return true on success, false otherwise.
|
||||
static bool rename_file_(const filename_t &src_filename, const filename_t &target_filename);
|
||||
static bool rename_file_(const filename_t &src_filename, const filename_t &target_filename) noexcept;
|
||||
|
||||
filename_t base_filename_;
|
||||
std::size_t max_size_;
|
||||
|
@ -1,12 +1,13 @@
|
||||
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
|
||||
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||
|
||||
#include "spdlog/details/file_helper.h"
|
||||
|
||||
#include <cerrno>
|
||||
#include <cstdio>
|
||||
#include <utility>
|
||||
#include <filesystem>
|
||||
|
||||
#include "spdlog/details/file_helper.h"
|
||||
#include "spdlog/common.h"
|
||||
#include "spdlog/details/os.h"
|
||||
|
||||
@ -107,37 +108,6 @@ size_t file_helper::size() const {
|
||||
|
||||
const filename_t &file_helper::filename() const { return filename_; }
|
||||
|
||||
//
|
||||
// return file path and its extension:
|
||||
//
|
||||
// "mylog.txt" => ("mylog", ".txt")
|
||||
// "mylog" => ("mylog", "")
|
||||
// "mylog." => ("mylog.", "")
|
||||
// "/dir1/dir2/mylog.txt" => ("/dir1/dir2/mylog", ".txt")
|
||||
//
|
||||
// the starting dot in filenames is ignored (hidden files):
|
||||
//
|
||||
// ".mylog" => (".mylog". "")
|
||||
// "my_folder/.mylog" => ("my_folder/.mylog", "")
|
||||
// "my_folder/.mylog.txt" => ("my_folder/.mylog", ".txt")
|
||||
std::tuple<filename_t, filename_t> file_helper::split_by_extension(const filename_t &fname) {
|
||||
auto ext_index = fname.rfind('.');
|
||||
|
||||
// no valid extension found - return whole path and empty string as
|
||||
// extension
|
||||
if (ext_index == filename_t::npos || ext_index == 0 || ext_index == fname.size() - 1) {
|
||||
return std::make_tuple(fname, filename_t());
|
||||
}
|
||||
|
||||
// treat cases like "/etc/rc.d/somelogfile or "/abc/.hiddenfile"
|
||||
auto folder_index = fname.find_last_of(details::os::folder_seps_filename);
|
||||
if (folder_index != filename_t::npos && folder_index >= ext_index - 1) {
|
||||
return std::make_tuple(fname, filename_t());
|
||||
}
|
||||
|
||||
// finally - return a valid base and extension tuple
|
||||
return std::make_tuple(fname.substr(0, ext_index), fname.substr(ext_index));
|
||||
}
|
||||
|
||||
} // namespace details
|
||||
} // namespace spdlog
|
||||
|
73
src/details/os_filesystem.cpp
Normal file
73
src/details/os_filesystem.cpp
Normal file
@ -0,0 +1,73 @@
|
||||
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
|
||||
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||
|
||||
#include <filesystem>
|
||||
#include <string>
|
||||
|
||||
#include "spdlog/common.h"
|
||||
#include "spdlog/details/os.h"
|
||||
|
||||
namespace spdlog {
|
||||
namespace details {
|
||||
namespace os {
|
||||
|
||||
bool remove(const filename_t &filename) {
|
||||
return std::filesystem::remove(filename);
|
||||
}
|
||||
|
||||
bool remove_if_exists(const filename_t &filename) {
|
||||
if (path_exists(filename)) {
|
||||
return os::remove(filename);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Rename if regular file
|
||||
bool rename(const filename_t &filename1, const filename_t &filename2) noexcept {
|
||||
if (!std::filesystem::is_regular_file(filename1)) {
|
||||
return false;
|
||||
}
|
||||
std::error_code ec;
|
||||
std::filesystem::rename(filename1, filename2, ec);
|
||||
return !ec;
|
||||
}
|
||||
|
||||
// Return true if path exists (file or directory)
|
||||
bool path_exists(const filename_t &filename) noexcept { return std::filesystem::exists(filename); }
|
||||
|
||||
// Return directory name from given path or empty string
|
||||
// "abc/file" => "abc"
|
||||
// "abc/" => "abc"
|
||||
// "abc" => ""
|
||||
// "abc///" => "abc//"
|
||||
filename_t dir_name(const filename_t &path) { return path.parent_path(); }
|
||||
|
||||
|
||||
// Create the given directory - and all directories leading to it
|
||||
// return true on success or if the directory already exists
|
||||
bool create_dir(const filename_t &path) {
|
||||
std::error_code ec;
|
||||
return std::filesystem::create_directories(path, ec) || !ec;
|
||||
}
|
||||
|
||||
|
||||
// Return file path and its extension:
|
||||
//
|
||||
// "mylog.txt" => ("mylog", ".txt")
|
||||
// "mylog" => ("mylog", "")
|
||||
// "mylog." => ("mylog", ".")
|
||||
// "/dir1/dir2/mylog.txt" => ("/dir1/dir2/mylog", ".txt")
|
||||
//
|
||||
// the starting dot in filenames is ignored (hidden files):
|
||||
//
|
||||
// ".mylog" => (".mylog". "")
|
||||
// "my_folder/.mylog" => ("my_folder/.mylog", "")
|
||||
// "my_folder/.mylog.txt" => ("my_folder/.mylog", ".txt")
|
||||
std::tuple<filename_t, filename_t> split_by_extension(const filename_t &fname) {
|
||||
const auto ext = fname.extension();
|
||||
auto without_ext = filename_t(fname).replace_extension();
|
||||
return std::make_tuple(without_ext, ext);
|
||||
}
|
||||
} // namespace os
|
||||
} // namespace details
|
||||
} // namespace spdlog
|
@ -99,19 +99,6 @@ bool fopen_s(FILE **fp, const filename_t &filename, const filename_t &mode) {
|
||||
return *fp == nullptr;
|
||||
}
|
||||
|
||||
int remove(const filename_t &filename) noexcept { return std::remove(filename.c_str()); }
|
||||
|
||||
int remove_if_exists(const filename_t &filename) noexcept { return path_exists(filename) ? remove(filename) : 0; }
|
||||
|
||||
int rename(const filename_t &filename1, const filename_t &filename2) noexcept {
|
||||
return std::rename(filename1.c_str(), filename2.c_str());
|
||||
}
|
||||
|
||||
// Return true if path exists (file or directory)
|
||||
bool path_exists(const filename_t &filename) noexcept {
|
||||
struct stat buffer {};
|
||||
return (::stat(filename.c_str(), &buffer) == 0);
|
||||
}
|
||||
|
||||
// Return file size according to open FILE* object
|
||||
size_t filesize(FILE *f) {
|
||||
@ -232,16 +219,22 @@ size_t _thread_id() noexcept {
|
||||
|
||||
// Return current thread id as size_t (from thread local storage)
|
||||
size_t thread_id() noexcept {
|
||||
// cache thread id in tls
|
||||
#if defined(SPDLOG_NO_TLS)
|
||||
return _thread_id();
|
||||
#else // cache thread id in tls
|
||||
static thread_local const size_t tid = _thread_id();
|
||||
return tid;
|
||||
#endif
|
||||
}
|
||||
|
||||
void sleep_for_millis(unsigned int milliseconds) noexcept {
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(milliseconds));
|
||||
}
|
||||
|
||||
std::string filename_to_str(const filename_t &filename) { return filename; }
|
||||
std::string filename_to_str(const filename_t &filename) {
|
||||
static_assert(std::is_same_v<filename_t::value_type, char>, "filename_t type must be char");
|
||||
return filename;
|
||||
}
|
||||
|
||||
int pid() noexcept { return static_cast<int>(::getpid()); }
|
||||
|
||||
@ -274,49 +267,6 @@ bool is_color_terminal() noexcept {
|
||||
// Source: https://github.com/agauniyal/rang/
|
||||
bool in_terminal(FILE *file) noexcept { return ::isatty(fileno(file)) != 0; }
|
||||
|
||||
// return true on success
|
||||
static bool mkdir_(const filename_t &path) { return ::mkdir(path.c_str(), static_cast<mode_t>(0755)) == 0; }
|
||||
|
||||
// create the given directory - and all directories leading to it
|
||||
// return true on success or if the directory already exists
|
||||
bool create_dir(const filename_t &path) {
|
||||
if (path_exists(path)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (path.empty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t search_offset = 0;
|
||||
do {
|
||||
auto token_pos = path.find_first_of(folder_seps_filename, search_offset);
|
||||
// treat the entire path as a folder if no folder separator not found
|
||||
if (token_pos == filename_t::npos) {
|
||||
token_pos = path.size();
|
||||
}
|
||||
|
||||
auto subdir = path.substr(0, token_pos);
|
||||
|
||||
if (!subdir.empty() && !path_exists(subdir) && !mkdir_(subdir)) {
|
||||
return false; // return error if failed creating dir
|
||||
}
|
||||
search_offset = token_pos + 1;
|
||||
} while (search_offset < path.size());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Return directory name from given path or empty string
|
||||
// "abc/file" => "abc"
|
||||
// "abc/" => "abc"
|
||||
// "abc" => ""
|
||||
// "abc///" => "abc//"
|
||||
filename_t dir_name(const filename_t &path) {
|
||||
auto pos = path.find_last_of(folder_seps_filename);
|
||||
return pos != filename_t::npos ? path.substr(0, pos) : filename_t{};
|
||||
}
|
||||
|
||||
std::string getenv(const char *field) {
|
||||
char *buf = ::getenv(field);
|
||||
return buf != nullptr ? buf : std::string{};
|
||||
|
@ -23,7 +23,6 @@
|
||||
#include <cstring>
|
||||
#include <ctime>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
|
||||
#include "spdlog/common.h"
|
||||
#include "spdlog/details/os.h"
|
||||
@ -63,7 +62,7 @@ std::tm gmtime() noexcept {
|
||||
}
|
||||
|
||||
bool fopen_s(FILE **fp, const filename_t &filename, const filename_t &mode) {
|
||||
*fp = ::_fsopen((filename.c_str()), mode.c_str(), _SH_DENYNO);
|
||||
*fp = ::_wfsopen((filename.c_str()), mode.c_str(), _SH_DENYNO);
|
||||
#if defined(SPDLOG_PREVENT_CHILD_FD)
|
||||
if (*fp != nullptr) {
|
||||
auto file_handle = reinterpret_cast<HANDLE>(_get_osfhandle(::_fileno(*fp)));
|
||||
@ -76,19 +75,7 @@ bool fopen_s(FILE **fp, const filename_t &filename, const filename_t &mode) {
|
||||
return *fp == nullptr;
|
||||
}
|
||||
|
||||
int remove(const filename_t &filename) noexcept { return std::remove(filename.c_str()); }
|
||||
|
||||
int remove_if_exists(const filename_t &filename) noexcept { return path_exists(filename) ? remove(filename) : 0; }
|
||||
|
||||
int rename(const filename_t &filename1, const filename_t &filename2) noexcept {
|
||||
return std::rename(filename1.c_str(), filename2.c_str());
|
||||
}
|
||||
|
||||
// Return true if path exists (file or directory)
|
||||
bool path_exists(const filename_t &filename) noexcept {
|
||||
struct _stat buffer;
|
||||
return (::_stat(filename.c_str(), &buffer) == 0);
|
||||
}
|
||||
|
||||
#ifdef _MSC_VER
|
||||
// avoid warning about unreachable statement at the end of filesize()
|
||||
@ -149,16 +136,31 @@ size_t _thread_id() noexcept { return static_cast<size_t>(::GetCurrentThreadId()
|
||||
|
||||
// Return current thread id as size_t (from thread local storage)
|
||||
size_t thread_id() noexcept {
|
||||
// cache thread id in tls
|
||||
#if defined(SPDLOG_NO_TLS)
|
||||
return _thread_id();
|
||||
#else // cache thread id in tls
|
||||
static thread_local const size_t tid = _thread_id();
|
||||
return tid;
|
||||
#endif
|
||||
}
|
||||
|
||||
// This is avoid msvc issue in sleep_for that happens if the clock changes.
|
||||
// See https://github.com/gabime/spdlog/issues/609
|
||||
void sleep_for_millis(unsigned int milliseconds) noexcept { ::Sleep(milliseconds); }
|
||||
|
||||
std::string filename_to_str(const filename_t &filename) { return filename; }
|
||||
// Try tp convert wstring filename to string. Return "???" if failed
|
||||
std::string filename_to_str(const filename_t &filename) {
|
||||
static_assert(std::is_same_v<filename_t::value_type, wchar_t>, "filename_t type must be wchar_t");
|
||||
try {
|
||||
memory_buf_t buf;
|
||||
wstr_to_utf8buf(filename.wstring(), buf);
|
||||
return std::string(buf.data(), buf.size());
|
||||
}
|
||||
catch (...) {
|
||||
return "???";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int pid() noexcept { return static_cast<int>(::GetCurrentProcessId()); }
|
||||
|
||||
@ -193,7 +195,7 @@ void wstr_to_utf8buf(wstring_view_t wstr, memory_buf_t &target) {
|
||||
}
|
||||
}
|
||||
|
||||
throw_spdlog_ex(fmt_lib::format("WideCharToMultiByte failed. Last error: {}", ::GetLastError()));
|
||||
throw spdlog_ex("WideCharToMultiByte failed");
|
||||
}
|
||||
|
||||
void utf8_to_wstrbuf(string_view_t str, wmemory_buf_t &target) {
|
||||
@ -222,56 +224,6 @@ void utf8_to_wstrbuf(string_view_t str, wmemory_buf_t &target) {
|
||||
throw_spdlog_ex(fmt_lib::format("MultiByteToWideChar failed. Last error: {}", ::GetLastError()));
|
||||
}
|
||||
|
||||
// return true on success
|
||||
static bool mkdir_(const filename_t &path) { return ::_mkdir(path.c_str()) == 0; }
|
||||
|
||||
// create the given directory - and all directories leading to it
|
||||
// return true on success or if the directory already exists
|
||||
bool create_dir(const filename_t &path) {
|
||||
if (path_exists(path)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (path.empty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t search_offset = 0;
|
||||
do {
|
||||
auto token_pos = path.find_first_of(folder_seps_filename, search_offset);
|
||||
// treat the entire path as a folder if no folder separator not found
|
||||
if (token_pos == filename_t::npos) {
|
||||
token_pos = path.size();
|
||||
}
|
||||
|
||||
auto subdir = path.substr(0, token_pos);
|
||||
|
||||
// if subdir is just a drive letter, add a slash e.g. "c:"=>"c:\",
|
||||
// otherwise path_exists(subdir) returns false (issue #3079)
|
||||
const bool is_drive = subdir.length() == 2 && subdir[1] == ':';
|
||||
if (is_drive) {
|
||||
subdir += '\\';
|
||||
token_pos++;
|
||||
}
|
||||
|
||||
if (!subdir.empty() && !path_exists(subdir) && !mkdir_(subdir)) {
|
||||
return false; // return error if failed creating dir
|
||||
}
|
||||
search_offset = token_pos + 1;
|
||||
} while (search_offset < path.size());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Return directory name from given path or empty string
|
||||
// "abc/file" => "abc"
|
||||
// "abc/" => "abc"
|
||||
// "abc" => ""
|
||||
// "abc///" => "abc//"
|
||||
filename_t dir_name(const filename_t &path) {
|
||||
auto pos = path.find_last_of(folder_seps_filename);
|
||||
return pos != filename_t::npos ? path.substr(0, pos) : filename_t{};
|
||||
}
|
||||
|
||||
std::string getenv(const char *field) {
|
||||
#if defined(_MSC_VER)
|
||||
|
@ -7,11 +7,11 @@
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
#include <sstream>
|
||||
|
||||
#include "spdlog/common.h"
|
||||
#include "spdlog/details/file_helper.h"
|
||||
#include "spdlog/details/os.h"
|
||||
// #include "spdlog/fmt/fmt.h"
|
||||
|
||||
namespace spdlog {
|
||||
namespace sinks {
|
||||
@ -51,8 +51,10 @@ filename_t rotating_file_sink<Mutex>::calc_filename(const filename_t &filename,
|
||||
|
||||
filename_t basename;
|
||||
filename_t ext;
|
||||
std::tie(basename, ext) = details::file_helper::split_by_extension(filename);
|
||||
return fmt_lib::format(SPDLOG_FMT_STRING(SPDLOG_FILENAME_T("{}.{}{}")), basename, index, ext);
|
||||
std::tie(basename, ext) = details::os::split_by_extension(filename);
|
||||
std::basic_ostringstream<filename_t::value_type> oss;
|
||||
oss << basename.native() << '.' << index << ext.native();
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
template <typename Mutex>
|
||||
@ -130,10 +132,8 @@ void rotating_file_sink<Mutex>::rotate_() {
|
||||
// delete the target if exists, and rename the src file to target
|
||||
// return true on success, false otherwise.
|
||||
template <typename Mutex>
|
||||
bool rotating_file_sink<Mutex>::rename_file_(const filename_t &src_filename, const filename_t &target_filename) {
|
||||
// try to delete the target file in case it already exists.
|
||||
(void)details::os::remove(target_filename);
|
||||
return details::os::rename(src_filename, target_filename) == 0;
|
||||
bool rotating_file_sink<Mutex>::rename_file_(const filename_t &src_filename, const filename_t &target_filename) noexcept{
|
||||
return details::os::rename(src_filename, target_filename);
|
||||
}
|
||||
|
||||
} // namespace sinks
|
||||
|
@ -31,3 +31,8 @@
|
||||
#include "spdlog/sinks/null_sink.h"
|
||||
#include "spdlog/sinks/stdout_color_sinks.h"
|
||||
#include "spdlog/spdlog.h"
|
||||
|
||||
// to_string_view
|
||||
[[nodiscard]] constexpr spdlog::string_view_t to_string_view(const spdlog::memory_buf_t &buf) noexcept {
|
||||
return spdlog::string_view_t{buf.data(), buf.size()};
|
||||
}
|
||||
|
@ -43,34 +43,38 @@ TEST_CASE("create_invalid_dir", "[create_dir]") {
|
||||
}
|
||||
|
||||
TEST_CASE("dir_name", "[create_dir]") {
|
||||
using spdlog::details::os::dir_name;
|
||||
REQUIRE(dir_name(SPDLOG_FILENAME_T("")).empty());
|
||||
REQUIRE(dir_name(SPDLOG_FILENAME_T("dir")).empty());
|
||||
|
||||
#ifdef WIN32
|
||||
using spdlog::details::os::dir_name;
|
||||
#ifdef WIN32
|
||||
REQUIRE(dir_name(SPDLOG_FILENAME_T(R"(dir\)")) == SPDLOG_FILENAME_T("dir"));
|
||||
REQUIRE(dir_name(SPDLOG_FILENAME_T(R"(dir\\\)")) == SPDLOG_FILENAME_T(R"(dir\\)"));
|
||||
REQUIRE(dir_name(SPDLOG_FILENAME_T(R"(dir\\\)")) == SPDLOG_FILENAME_T(R"(dir)"));
|
||||
REQUIRE(dir_name(SPDLOG_FILENAME_T(R"(dir\file)")) == SPDLOG_FILENAME_T("dir"));
|
||||
REQUIRE(dir_name(SPDLOG_FILENAME_T(R"(dir/file)")) == SPDLOG_FILENAME_T("dir"));
|
||||
REQUIRE(dir_name(SPDLOG_FILENAME_T(R"(dir\file.txt)")) == SPDLOG_FILENAME_T("dir"));
|
||||
REQUIRE(dir_name(SPDLOG_FILENAME_T(R"(dir/file)")) == SPDLOG_FILENAME_T("dir"));
|
||||
REQUIRE(dir_name(SPDLOG_FILENAME_T(R"(dir\file.txt\)")) == SPDLOG_FILENAME_T(R"(dir\file.txt)"));
|
||||
REQUIRE(dir_name(SPDLOG_FILENAME_T(R"(\dir\file.txt)")) == SPDLOG_FILENAME_T(R"(\dir)"));
|
||||
REQUIRE(dir_name(SPDLOG_FILENAME_T(R"(\\dir\file.txt)")) == SPDLOG_FILENAME_T(R"(\\dir)"));
|
||||
REQUIRE(dir_name(SPDLOG_FILENAME_T(R"(\\dir\file.txt)")) == SPDLOG_FILENAME_T(R"(\\dir\)"));
|
||||
REQUIRE(dir_name(SPDLOG_FILENAME_T(R"(..\file.txt)")) == SPDLOG_FILENAME_T(".."));
|
||||
REQUIRE(dir_name(SPDLOG_FILENAME_T(R"(.\file.txt)")) == SPDLOG_FILENAME_T("."));
|
||||
REQUIRE(dir_name(SPDLOG_FILENAME_T(R"(c:\\a\b\c\d\file.txt)")) == SPDLOG_FILENAME_T(R"(c:\\a\b\c\d)"));
|
||||
REQUIRE(dir_name(SPDLOG_FILENAME_T(R"(c://a/b/c/d/file.txt)")) == SPDLOG_FILENAME_T(R"(c://a/b/c/d)"));
|
||||
#endif
|
||||
REQUIRE(dir_name(SPDLOG_FILENAME_T("")).empty());
|
||||
REQUIRE(dir_name(SPDLOG_FILENAME_T("dir")).empty());
|
||||
REQUIRE(dir_name(SPDLOG_FILENAME_T("dir/")) == SPDLOG_FILENAME_T("dir"));
|
||||
REQUIRE(dir_name(SPDLOG_FILENAME_T("dir///")) == SPDLOG_FILENAME_T("dir//"));
|
||||
REQUIRE(dir_name(SPDLOG_FILENAME_T("dir///")) == SPDLOG_FILENAME_T("dir"));
|
||||
REQUIRE(dir_name(SPDLOG_FILENAME_T("dir/file")) == SPDLOG_FILENAME_T("dir"));
|
||||
REQUIRE(dir_name(SPDLOG_FILENAME_T("dir/file.txt")) == SPDLOG_FILENAME_T("dir"));
|
||||
REQUIRE(dir_name(SPDLOG_FILENAME_T("dir/file.txt/")) == SPDLOG_FILENAME_T("dir/file.txt"));
|
||||
REQUIRE(dir_name(SPDLOG_FILENAME_T("/dir/file.txt")) == SPDLOG_FILENAME_T("/dir"));
|
||||
REQUIRE(dir_name(SPDLOG_FILENAME_T("//dir/file.txt")) == SPDLOG_FILENAME_T("//dir"));
|
||||
REQUIRE(dir_name(SPDLOG_FILENAME_T("/dir/file.txt")) == SPDLOG_FILENAME_T("/dir"));
|
||||
REQUIRE(dir_name(SPDLOG_FILENAME_T("../file.txt")) == SPDLOG_FILENAME_T(".."));
|
||||
REQUIRE(dir_name(SPDLOG_FILENAME_T("./file.txt")) == SPDLOG_FILENAME_T("."));
|
||||
|
||||
#ifdef _WIN32
|
||||
REQUIRE(dir_name(SPDLOG_FILENAME_T("//dir/file.txt")) == SPDLOG_FILENAME_T("//dir/"));
|
||||
#else
|
||||
REQUIRE(dir_name(SPDLOG_FILENAME_T("//dir/file.txt")) == SPDLOG_FILENAME_T("//dir"));
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
@ -122,15 +126,4 @@ TEST_CASE("create_abs_path2", "[create_dir]") {
|
||||
REQUIRE(create_dir(abs_path) == true);
|
||||
}
|
||||
|
||||
TEST_CASE("non_existing_drive", "[create_dir]") {
|
||||
prepare_logdir();
|
||||
spdlog::filename_t path;
|
||||
|
||||
auto non_existing_drive = find_non_existing_drive();
|
||||
path += non_existing_drive;
|
||||
path += SPDLOG_FILENAME_T(":\\");
|
||||
REQUIRE(create_dir(path) == false);
|
||||
path += SPDLOG_FILENAME_T("subdir");
|
||||
REQUIRE(create_dir(path) == false);
|
||||
}
|
||||
#endif // _WIN32
|
||||
|
@ -5,6 +5,7 @@
|
||||
#include "includes.h"
|
||||
#include "spdlog/sinks/daily_file_sink.h"
|
||||
#include "spdlog/sinks/rotating_file_sink.h"
|
||||
#include "spdlog/sinks/hourly_file_sink.h"
|
||||
|
||||
using filename_memory_buf_t = spdlog::memory_buf_t;
|
||||
|
||||
@ -16,9 +17,8 @@ TEST_CASE("daily_logger with dateonly calculator", "[daily_logger]") {
|
||||
// calculate filename (time based)
|
||||
spdlog::filename_t basename = SPDLOG_FILENAME_T("test_logs/daily_dateonly");
|
||||
std::tm tm = spdlog::details::os::localtime();
|
||||
filename_memory_buf_t w;
|
||||
spdlog::fmt_lib::format_to(std::back_inserter(w), SPDLOG_FILENAME_T("{}_{:04d}-{:02d}-{:02d}"), basename, tm.tm_year + 1900,
|
||||
tm.tm_mon + 1, tm.tm_mday);
|
||||
auto w = spdlog::fmt_lib::format(SPDLOG_FILENAME_T("{}_{:04d}-{:02d}-{:02d}"), basename.native(), tm.tm_year + 1900,
|
||||
tm.tm_mon + 1, tm.tm_mday);
|
||||
|
||||
auto logger = spdlog::create<sink_type>("logger", basename, 0, 0);
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
@ -26,16 +26,15 @@ TEST_CASE("daily_logger with dateonly calculator", "[daily_logger]") {
|
||||
}
|
||||
logger->flush();
|
||||
|
||||
require_message_count(SPDLOG_BUF_TO_STRING(w), 10);
|
||||
require_message_count(w, 10);
|
||||
}
|
||||
|
||||
struct custom_daily_file_name_calculator {
|
||||
static spdlog::filename_t calc_filename(const spdlog::filename_t &basename, const tm &now_tm) {
|
||||
filename_memory_buf_t w;
|
||||
spdlog::fmt_lib::format_to(std::back_inserter(w), SPDLOG_FILENAME_T("{}{:04d}{:02d}{:02d}"), basename,
|
||||
now_tm.tm_year + 1900, now_tm.tm_mon + 1, now_tm.tm_mday);
|
||||
auto w = spdlog::fmt_lib::format(SPDLOG_FILENAME_T("{}{:04d}{:02d}{:02d}"), basename.native(), now_tm.tm_year + 1900,
|
||||
now_tm.tm_mon + 1, now_tm.tm_mday);
|
||||
|
||||
return SPDLOG_BUF_TO_STRING(w);
|
||||
return w;
|
||||
}
|
||||
};
|
||||
|
||||
@ -47,9 +46,10 @@ TEST_CASE("daily_logger with custom calculator", "[daily_logger]") {
|
||||
// calculate filename (time based)
|
||||
spdlog::filename_t basename = SPDLOG_FILENAME_T("test_logs/daily_dateonly");
|
||||
std::tm tm = spdlog::details::os::localtime();
|
||||
filename_memory_buf_t w;
|
||||
spdlog::fmt_lib::format_to(std::back_inserter(w), SPDLOG_FILENAME_T("{}{:04d}{:02d}{:02d}"), basename, tm.tm_year + 1900,
|
||||
tm.tm_mon + 1, tm.tm_mday);
|
||||
|
||||
auto w = spdlog::fmt_lib::format(SPDLOG_FILENAME_T("{}{:04d}{:02d}{:02d}"), basename.native(), tm.tm_year + 1900,
|
||||
tm.tm_mon + 1,
|
||||
tm.tm_mday);
|
||||
|
||||
auto logger = spdlog::create<sink_type>("logger", basename, 0, 0);
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
@ -57,7 +57,7 @@ TEST_CASE("daily_logger with custom calculator", "[daily_logger]") {
|
||||
}
|
||||
|
||||
logger->flush();
|
||||
require_message_count(SPDLOG_BUF_TO_STRING(w), 10);
|
||||
require_message_count(w, 10);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -82,17 +82,32 @@ TEST_CASE("rotating_file_sink::calc_filename3", "[rotating_file_sink]") {
|
||||
// regex supported only from gcc 4.9 and above
|
||||
#if defined(_MSC_VER) || !(__GNUC__ <= 4 && __GNUC_MINOR__ < 9)
|
||||
|
||||
#include <regex>
|
||||
#include <regex>
|
||||
|
||||
TEST_CASE("daily_file_sink::daily_filename_calculator", "[daily_file_sink]") {
|
||||
// daily_YYYY-MM-DD_hh-mm.txt
|
||||
auto filename =
|
||||
spdlog::sinks::daily_filename_calculator::calc_filename(SPDLOG_FILENAME_T("daily.txt"),
|
||||
spdlog::details::os::localtime());
|
||||
// date regex based on https://www.regular-expressions.info/dates.html
|
||||
std::basic_regex<spdlog::filename_t::value_type> re(
|
||||
SPDLOG_FILENAME_T(R"(^daily_(19|20)\d\d-(0[1-9]|1[012])-(0[1-9]|[12][0-9]|3[01])\.txt$)"));
|
||||
|
||||
std::match_results<spdlog::filename_t::string_type::const_iterator> match;
|
||||
REQUIRE(std::regex_match(filename.native(), match, re));
|
||||
}
|
||||
|
||||
|
||||
TEST_CASE("hourly_file_sink::hourly_filename_calculator", "[hrouly_file_sink]") {
|
||||
// daily_YYYY-MM-DD_hh-mm.txt
|
||||
auto filename =
|
||||
spdlog::sinks::daily_filename_calculator::calc_filename(SPDLOG_FILENAME_T("daily.txt"), spdlog::details::os::localtime());
|
||||
spdlog::sinks::hourly_filename_calculator::calc_filename(SPDLOG_FILENAME_T("hourly.txt"), spdlog::details::os::localtime());
|
||||
// date regex based on https://www.regular-expressions.info/dates.html
|
||||
std::basic_regex<spdlog::filename_t::value_type> re(
|
||||
SPDLOG_FILENAME_T(R"(^daily_(19|20)\d\d-(0[1-9]|1[012])-(0[1-9]|[12][0-9]|3[01])\.txt$)"));
|
||||
std::match_results<spdlog::filename_t::const_iterator> match;
|
||||
REQUIRE(std::regex_match(filename, match, re));
|
||||
SPDLOG_FILENAME_T(R"(^hourly_(19|20)\d\d-(0[1-9]|1[012])-(0[1-9]|[12][0-9]|3[01])_\d\d\.txt$)"));
|
||||
|
||||
std::match_results<spdlog::filename_t::string_type::const_iterator> match;
|
||||
REQUIRE(std::regex_match(filename.native(), match, re));
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -148,4 +163,4 @@ TEST_CASE("daily_logger rotate", "[daily_file_sink]") {
|
||||
test_rotate(days_to_run, 10, 10);
|
||||
test_rotate(days_to_run, 11, 10);
|
||||
test_rotate(days_to_run, 20, 10);
|
||||
}
|
||||
}
|
@ -70,7 +70,7 @@ static void test_split_ext(const spdlog::filename_t::value_type *fname,
|
||||
|
||||
spdlog::filename_t basename;
|
||||
spdlog::filename_t ext;
|
||||
std::tie(basename, ext) = file_helper::split_by_extension(filename);
|
||||
std::tie(basename, ext) = spdlog::details::os::split_by_extension(filename);
|
||||
REQUIRE(basename == expected_base);
|
||||
REQUIRE(ext == expected_ext);
|
||||
}
|
||||
@ -82,7 +82,7 @@ TEST_CASE("file_helper_split_by_extension", "[file_helper::split_by_extension()]
|
||||
test_split_ext(SPDLOG_FILENAME_T("/aaa/bb.d/mylog"), SPDLOG_FILENAME_T("/aaa/bb.d/mylog"), SPDLOG_FILENAME_T(""));
|
||||
test_split_ext(SPDLOG_FILENAME_T("/aaa/bb.d/mylog.txt"), SPDLOG_FILENAME_T("/aaa/bb.d/mylog"), SPDLOG_FILENAME_T(".txt"));
|
||||
test_split_ext(SPDLOG_FILENAME_T("aaa/bbb/ccc/mylog.txt"), SPDLOG_FILENAME_T("aaa/bbb/ccc/mylog"), SPDLOG_FILENAME_T(".txt"));
|
||||
test_split_ext(SPDLOG_FILENAME_T("aaa/bbb/ccc/mylog."), SPDLOG_FILENAME_T("aaa/bbb/ccc/mylog."), SPDLOG_FILENAME_T(""));
|
||||
test_split_ext(SPDLOG_FILENAME_T("aaa/bbb/ccc/mylog."), SPDLOG_FILENAME_T("aaa/bbb/ccc/mylog"), SPDLOG_FILENAME_T("."));
|
||||
test_split_ext(SPDLOG_FILENAME_T("aaa/bbb/ccc/.mylog.txt"), SPDLOG_FILENAME_T("aaa/bbb/ccc/.mylog"),
|
||||
SPDLOG_FILENAME_T(".txt"));
|
||||
test_split_ext(SPDLOG_FILENAME_T("/aaa/bbb/ccc/mylog.txt"), SPDLOG_FILENAME_T("/aaa/bbb/ccc/mylog"),
|
||||
@ -92,7 +92,7 @@ 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/xxx"), SPDLOG_FILENAME_T(".././mylog.txt/xxx"), SPDLOG_FILENAME_T(""));
|
||||
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(""), SPDLOG_FILENAME_T(""), SPDLOG_FILENAME_T(""));
|
||||
test_split_ext(SPDLOG_FILENAME_T("."), SPDLOG_FILENAME_T("."), SPDLOG_FILENAME_T(""));
|
||||
test_split_ext(SPDLOG_FILENAME_T("..txt"), SPDLOG_FILENAME_T("."), SPDLOG_FILENAME_T(".txt"));
|
||||
|
@ -2,7 +2,6 @@
|
||||
#include "includes.h"
|
||||
|
||||
using spdlog::memory_buf_t;
|
||||
using spdlog::details::to_string_view;
|
||||
|
||||
void test_pad2(int n, const char *expected) {
|
||||
memory_buf_t buf;
|
||||
|
@ -3,7 +3,6 @@
|
||||
#include "test_sink.h"
|
||||
|
||||
using spdlog::memory_buf_t;
|
||||
using spdlog::details::to_string_view;
|
||||
|
||||
// log to str and return it
|
||||
template <typename... Args>
|
||||
|
@ -27,7 +27,7 @@ std::string file_contents(const std::string &filename) {
|
||||
return std::string((std::istreambuf_iterator<char>(ifs)), (std::istreambuf_iterator<char>()));
|
||||
}
|
||||
|
||||
std::size_t count_lines(const std::string &filename) {
|
||||
std::size_t count_lines(const spdlog::filename_t &filename) {
|
||||
std::ifstream ifs(filename);
|
||||
if (!ifs) {
|
||||
throw std::runtime_error("Failed open file ");
|
||||
@ -39,7 +39,7 @@ std::size_t count_lines(const std::string &filename) {
|
||||
return counter;
|
||||
}
|
||||
|
||||
void require_message_count(const std::string &filename, const std::size_t messages) {
|
||||
void require_message_count(const std::filesystem::path &filename, const std::size_t messages) {
|
||||
if (strlen(spdlog::details::os::default_eol) == 0) {
|
||||
REQUIRE(count_lines(filename) == 1);
|
||||
} else {
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
#include <cstddef>
|
||||
#include <string>
|
||||
#include <filesystem>
|
||||
|
||||
std::size_t count_files(const std::string &folder);
|
||||
|
||||
@ -9,9 +10,10 @@ void prepare_logdir();
|
||||
|
||||
std::string file_contents(const std::string &filename);
|
||||
|
||||
std::size_t count_lines(const std::string &filename);
|
||||
//std::size_t count_lines(const std::string &filename);
|
||||
std::size_t count_lines(const std::filesystem::path &filename);
|
||||
|
||||
void require_message_count(const std::string &filename, const std::size_t messages);
|
||||
void require_message_count(const std::filesystem::path &filename, const std::size_t messages);
|
||||
|
||||
std::size_t get_filesize(const std::string &filename);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user