This commit is contained in:
Gabi Melman 2024-12-04 00:33:42 +02:00
parent daf1b97b8f
commit 1c58ca4b5e
12 changed files with 168 additions and 175 deletions

View File

@ -1,4 +1,4 @@
//
//
// Copyright(c) 2015 Gabi Melman.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
@ -7,6 +7,8 @@
#include <chrono>
#include <cstdio>
#include "spdlog/details/windows_include.h"
void load_levels_example();
void stdout_logger_example();
void basic_example();
@ -32,9 +34,26 @@ void replace_default_logger_example();
#include "spdlog/version.h"
int main(int, char *[]) {
SetConsoleOutputCP(CP_UTF8);
// Log levels can be loaded from argv/env using "SPDLOG_LEVEL"
load_levels_example();
SPDLOG_INFO("This message should be displayed..");
//spdlog::filename_t x = L"logs/hourlyעכעכ.txt";
std::filesystem::path const x{L"\xd83d\x4000"};
try {
auto my_s = spdlog::details::os::filename_to_str(x);
spdlog::info("mystring: {}", my_s);
auto s = x.u8string();
spdlog::info("u8string: {}", s);
} catch (const std::exception &e) {
SPDLOG_INFO("EXCEPTION {}", e.what());
}
return 0;
spdlog::info("Welcome to spdlog version {}.{}.{} !", SPDLOG_VER_MAJOR, SPDLOG_VER_MINOR, SPDLOG_VER_PATCH);
spdlog::warn("Easy padding in numbers like {:08d}", 12);
spdlog::critical("Support for int: {0:d}; hex: {0:x}; oct: {0:o}; bin: {0:b}", 42);
@ -114,9 +133,12 @@ void rotating_example() {
}
#include "spdlog/sinks/daily_file_sink.h"
#include "spdlog/sinks/hourly_file_sink.h"
void daily_example() {
using namespace spdlog::sinks;
// Create a daily logger - a new file is created every day on 2:30am.
auto daily_logger = spdlog::daily_logger_mt("daily_logger", "logs/daily.txt", 2, 30);
auto hourly_logger = spdlog::hourly_logger_mt("hourly_logger", L"logs/hourlyגבי.txt", 0);
}
#include "spdlog/sinks/callback_sink.h"
@ -283,10 +305,7 @@ public:
dest.append(some_txt.data(), some_txt.data() + some_txt.size());
}
[[nodiscard]]
std::unique_ptr<custom_flag_formatter> clone() const override {
return std::make_unique<my_formatter_flag>();
}
[[nodiscard]] std::unique_ptr<custom_flag_formatter> clone() const override { return std::make_unique<my_formatter_flag>(); }
};
void custom_flags_example() {
@ -299,16 +318,20 @@ 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.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);
// spdlog::info("After opening {}", filename);
fputs("After opening\n", fstream);
};
handlers.before_close = [](spdlog::filename_t filename, std::FILE *fstream) {
spdlog::info("Before closing {}", filename);
// spdlog::info("Before closing {}", filename);
fputs("Before closing\n", fstream);
};
handlers.after_close = [](spdlog::filename_t filename) { spdlog::info("After closing {}", filename); };
handlers.after_close = [](spdlog::filename_t filename) {
// spdlog::info("After closing {}", filename);
};
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");

View File

@ -13,6 +13,7 @@
#include <memory>
#include <string>
#include <type_traits>
#include <filesystem>
#include "./source_loc.h"
@ -47,8 +48,13 @@ namespace sinks {
class sink;
}
using filename_t = std::string;
#define SPDLOG_FILENAME_T(s) s
using filename_t = std::filesystem::path;
#ifdef _WIN32 // Add L prefix to string literals on Windows when dealing with filenames
#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
using log_clock = std::chrono::system_clock;
using sink_ptr = std::shared_ptr<sinks::sink>;
@ -64,7 +70,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

View File

@ -4,7 +4,6 @@
#pragma once
#include <ctime> // std::time_t
#include "../common.h"
namespace spdlog {
@ -24,7 +23,7 @@ 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("\\/");
constexpr static const filename_t::value_type folder_seps_filename[] = L"\\/";
#else
constexpr static const char *default_eol = "\n";
constexpr static const filename_t::value_type folder_seps_filename[] = SPDLOG_FILENAME_T("/");
@ -33,14 +32,15 @@ constexpr static const filename_t::value_type folder_seps_filename[] = SPDLOG_FI
// 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 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 int remove_if_exists(const filename_t &filename) noexcept;
SPDLOG_API bool remove_if_exists(const filename_t &filename) ;
SPDLOG_API int rename(const filename_t &filename1, const filename_t &filename2) noexcept;
// 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;
@ -63,6 +63,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;
// Try tp convert wstring filename to string. Return "??" if failed
SPDLOG_API std::string filename_to_str(const filename_t &filename);
SPDLOG_API int pid() noexcept;

View File

@ -11,41 +11,45 @@
#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::basic_ostringstream<filename_t::value_type> oss;
auto sep = SPDLOG_FILENAME_T('-');
oss << basename.native() << SPDLOG_FILENAME_T('_') << std::setfill(SPDLOG_FILENAME_T('0')) << std::setw(4)
<< now_tm.tm_year + 1900 << sep
<< std::setw(2) << now_tm.tm_mon + 1 << sep << 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 +168,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

@ -29,8 +29,12 @@ struct hourly_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_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::basic_ostringstream<filename_t::value_type> oss;
auto sep = SPDLOG_FILENAME_T('-');
oss << basename.native() << sep << std::setfill(SPDLOG_FILENAME_T('0')) << std::setw(4) << now_tm.tm_year + 1900 << sep
<< std::setw(2) << now_tm.tm_mon + 1 << sep << std::setw(2) << now_tm.tm_mday << sep << 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_;

View File

@ -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"
@ -112,7 +113,7 @@ const filename_t &file_helper::filename() const { return filename_; }
//
// "mylog.txt" => ("mylog", ".txt")
// "mylog" => ("mylog", "")
// "mylog." => ("mylog.", "")
// "mylog." => ("mylog", ".")
// "/dir1/dir2/mylog.txt" => ("/dir1/dir2/mylog", ".txt")
//
// the starting dot in filenames is ignored (hidden files):
@ -120,23 +121,10 @@ const filename_t &file_helper::filename() const { return filename_; }
// ".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));
std::tuple<filename_t, filename_t> file_helper::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 details

View File

@ -22,8 +22,8 @@
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <filesystem>
#include <string>
#include <thread>
#include "spdlog/common.h"
#include "spdlog/details/os.h"
@ -63,7 +63,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 +76,27 @@ 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()); }
bool remove(const filename_t &filename) { return std::filesystem::remove(filename); }
int remove_if_exists(const filename_t &filename) noexcept { return path_exists(filename) ? remove(filename) : 0; }
bool remove_if_exists(const filename_t &filename) {
if (path_exists(filename)) {
return os::remove(filename);
}
return false;
}
int rename(const filename_t &filename1, const filename_t &filename2) noexcept {
return std::rename(filename1.c_str(), filename2.c_str());
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 {
struct _stat buffer;
return (::_stat(filename.c_str(), &buffer) == 0);
}
bool path_exists(const filename_t &filename) noexcept { return std::filesystem::exists(filename); }
#ifdef _MSC_VER
// avoid warning about unreachable statement at the end of filesize()
@ -158,7 +166,19 @@ size_t thread_id() noexcept {
// 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 +213,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) {
@ -223,44 +243,13 @@ void utf8_to_wstrbuf(string_view_t str, wmemory_buf_t &target) {
}
// return true on success
static bool mkdir_(const filename_t &path) { return ::_mkdir(path.c_str()) == 0; }
// 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;
bool create_dir(const filename_t &path) {
std::error_code ec;
return std::filesystem::create_directories(path, ec) || !ec;
}
// Return directory name from given path or empty string
@ -268,10 +257,7 @@ bool create_dir(const filename_t &path) {
// "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{};
}
filename_t dir_name(const filename_t &path) { return path.parent_path(); }
std::string getenv(const char *field) {
#if defined(_MSC_VER)

View File

@ -7,6 +7,7 @@
#include <mutex>
#include <string>
#include <tuple>
#include <sstream>
#include "spdlog/common.h"
#include "spdlog/details/file_helper.h"
@ -51,8 +52,11 @@ 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::file_helper::split_by_extension(filename);
std::basic_ostringstream<filename_t::value_type> oss;
oss << basename.native() << "." << index << ext.native();
return oss.str();
//return fmt_lib::format(SPDLOG_FMT_STRING(SPDLOG_FILENAME_T("{}.{}{}")), basename, index, ext);
}
template <typename Mutex>
@ -130,10 +134,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

View File

@ -43,32 +43,31 @@ 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("."));
}
@ -122,15 +121,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

View File

@ -6,7 +6,8 @@
#include "spdlog/sinks/daily_file_sink.h"
#include "spdlog/sinks/rotating_file_sink.h"
using filename_memory_buf_t = spdlog::memory_buf_t;
using file_t_sstream = std::basic_stringstream<spdlog::filename_t::value_type>;
using spdlog::details::os::filename_to_str;
TEST_CASE("daily_logger with dateonly calculator", "[daily_logger]") {
using sink_type = spdlog::sinks::daily_file_sink<std::mutex, spdlog::sinks::daily_filename_calculator>;
@ -15,10 +16,12 @@ 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);
std::tm now_tm = spdlog::details::os::localtime();
//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 logger = spdlog::create<sink_type>("logger", basename, 0, 0);
for (int i = 0; i < 10; ++i) {
@ -26,39 +29,17 @@ TEST_CASE("daily_logger with dateonly calculator", "[daily_logger]") {
}
logger->flush();
require_message_count(SPDLOG_BUF_TO_STRING(w), 10);
// calcluate expected filename and check if it exists with the expected message count
file_t_sstream stream;
auto sep = SPDLOG_FILENAME_T('-');
stream << basename.native() << SPDLOG_FILENAME_T('_') << std::setfill(SPDLOG_FILENAME_T('0')) << std::setw(4)
<< now_tm.tm_year + 1900 << sep << std::setw(2) << now_tm.tm_mon + 1 << sep << std::setw(2) << now_tm.tm_mday;
require_message_count(filename_to_str(stream.str()), 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);
return SPDLOG_BUF_TO_STRING(w);
}
};
TEST_CASE("daily_logger with custom calculator", "[daily_logger]") {
using sink_type = spdlog::sinks::daily_file_sink<std::mutex, custom_daily_file_name_calculator>;
prepare_logdir();
// 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 logger = spdlog::create<sink_type>("logger", basename, 0, 0);
for (int i = 0; i < 10; ++i) {
logger->info("Test message {}", i);
}
logger->flush();
require_message_count(SPDLOG_BUF_TO_STRING(w), 10);
}
/*
* File name calculations
@ -86,13 +67,19 @@ TEST_CASE("rotating_file_sink::calc_filename3", "[rotating_file_sink]") {
TEST_CASE("daily_file_sink::daily_filename_calculator", "[daily_file_sink]") {
// daily_YYYY-MM-DD_hh-mm.txt
auto now = spdlog::details::os::localtime();
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::const_iterator> match;
REQUIRE(std::regex_match(filename, match, re));
spdlog::sinks::daily_filename_calculator::calc_filename(SPDLOG_FILENAME_T("daily.txt"), now);
file_t_sstream stream;
stream << "daily_" << now.tm_year + 1900 << "-" << std::setw(2) << std::setfill(SPDLOG_FILENAME_T('0')) << now.tm_mon + 1 << "-"
<< std::setw(2) << std::setfill(SPDLOG_FILENAME_T('0')) << now.tm_mday << ".txt";
REQUIRE(filename == std::filesystem::path(stream.str()));
//// 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));
}
#endif
@ -101,8 +88,13 @@ TEST_CASE("daily_file_sink::daily_filename_format_calculator", "[daily_file_sink
// example-YYYY-MM-DD.log
auto filename = spdlog::sinks::daily_filename_format_calculator::calc_filename(SPDLOG_FILENAME_T("example-%Y-%m-%d.log"), tm);
REQUIRE(filename == spdlog::fmt_lib::format(SPDLOG_FILENAME_T("example-{:04d}-{:02d}-{:02d}.log"), tm.tm_year + 1900,
tm.tm_mon + 1, tm.tm_mday));
// calc excpected filename
file_t_sstream stream;
stream << "example-" << tm.tm_year + 1900 << "-" << std::setw(2) << std::setfill(SPDLOG_FILENAME_T('0')) << tm.tm_mon + 1
<< "-" << std::setw(2) << std::setfill(SPDLOG_FILENAME_T('0')) << tm.tm_mday << ".log";
REQUIRE(filename == std::filesystem::path(stream.str()));
}
/* Test removal of old files */

View File

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