Use std filesystem (#3284)

* Use std::filesystem for path names and impl
This commit is contained in:
Gabi Melman
2024-12-05 19:14:25 +02:00
committed by GitHub
parent daf1b97b8f
commit 08c727e4f8
24 changed files with 300 additions and 318 deletions

View File

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

View File

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

View File

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

View 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

View 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

View File

@@ -6,3 +6,4 @@
#pragma once
#include "fmt/format.h"
#include "fmt/xchar.h"

View File

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

View File

@@ -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();
}
};

View File

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