pull/509/merge
Antony Cherepanov 8 years ago committed by GitHub
commit 42fbbb1518

@ -55,6 +55,7 @@ int main(int argc, char* argv[])
auto rotating_st = spdlog::rotating_logger_st("rotating_st", "logs/rotating_st", file_size, rotating_files);
bench(howmany, rotating_st);
bench(howmany, spdlog::create<spdlog::sinks::rotating_file_sink_mp_st>("rotating_mp_st", "logs/rotating_mp_st", file_size, rotating_files));
auto daily_st = spdlog::daily_logger_st("daily_st", "logs/daily_st");
bench(howmany, daily_st);
bench(howmany, spdlog::create<null_sink_st>("null_st"));
@ -65,7 +66,7 @@ int main(int argc, char* argv[])
auto rotating_mt = spdlog::rotating_logger_mt("rotating_mt", "logs/rotating_mt", file_size, rotating_files);
bench_mt(howmany, rotating_mt, threads);
bench_mt(howmany, spdlog::create<spdlog::sinks::rotating_file_sink_mp_mt>("rotating_mp_mt", "logs/rotating_mp_mt", file_size, rotating_files), threads);
auto daily_mt = spdlog::daily_logger_mt("daily_mt", "logs/daily_mt");
bench_mt(howmany, daily_mt, threads);

@ -23,13 +23,42 @@ namespace spdlog
namespace details
{
class file_helper
class base_file_helper
{
public:
const int open_tries = 5;
const int open_interval = 10;
explicit base_file_helper() {}
virtual ~base_file_helper() {}
base_file_helper(const base_file_helper&) = delete;
base_file_helper& operator=(const base_file_helper&) = delete;
virtual void open(const filename_t& fname, bool truncate) = 0;
virtual void reopen(bool truncate) = 0;
virtual void write(const log_msg& msg) = 0;
virtual void flush() = 0;
virtual void close() = 0;
virtual size_t size() = 0;
const filename_t& filename() const
{
return _filename;
}
static bool file_exists(const filename_t& name)
{
return os::file_exists(name);
}
protected:
filename_t _filename;
};
class file_helper : public base_file_helper
{
public:
explicit file_helper() :
_fd(nullptr)
{}
@ -37,15 +66,13 @@ public:
file_helper(const file_helper&) = delete;
file_helper& operator=(const file_helper&) = delete;
~file_helper()
virtual ~file_helper() override
{
close();
}
void open(const filename_t& fname, bool truncate = false)
virtual void open(const filename_t& fname, bool truncate = false) override
{
close();
auto *mode = truncate ? SPDLOG_FILENAME_T("wb") : SPDLOG_FILENAME_T("ab");
_filename = fname;
@ -60,20 +87,28 @@ public:
throw spdlog_ex("Failed opening file " + os::filename_to_str(_filename) + " for writing", errno);
}
void reopen(bool truncate)
virtual void reopen(bool truncate) override
{
if (_filename.empty())
throw spdlog_ex("Failed re opening file - was not opened before");
open(_filename, truncate);
}
virtual void write(const log_msg& msg) override
{
size_t msg_size = msg.formatted.size();
auto data = msg.formatted.data();
if (std::fwrite(data, 1, msg_size, _fd) != msg_size)
throw spdlog_ex("Failed writing to file " + os::filename_to_str(_filename), errno);
}
void flush()
virtual void flush() override
{
std::fflush(_fd);
}
void close()
virtual void close() override
{
if (_fd)
{
@ -82,36 +117,94 @@ public:
}
}
void write(const log_msg& msg)
virtual size_t size() override
{
if (!_fd)
throw spdlog_ex("Cannot use size() on closed file " + os::filename_to_str(_filename));
size_t msg_size = msg.formatted.size();
auto data = msg.formatted.data();
if (std::fwrite(data, 1, msg_size, _fd) != msg_size)
throw spdlog_ex("Failed writing to file " + os::filename_to_str(_filename), errno);
return os::filesize(_fd);
}
size_t size()
private:
FILE* _fd;
};
// file_helper_mp - helper class for multi-process version of file sinks
class file_helper_mp : public base_file_helper
{
public:
explicit file_helper_mp() :
_fd(-1)
{}
file_helper_mp(const file_helper_mp&) = delete;
file_helper_mp& operator=(const file_helper_mp&) = delete;
virtual ~file_helper_mp() override
{
if (!_fd)
throw spdlog_ex("Cannot use size() on closed file " + os::filename_to_str(_filename));
return os::filesize(_fd);
close();
}
const filename_t& filename() const
virtual void open(const spdlog::filename_t& fname, bool truncate = false) override
{
return _filename;
close();
_filename = fname;
int mode = SPDLOG_O_RDWR | SPDLOG_O_APPEND | SPDLOG_O_CREATE | SPDLOG_O_BINARY;
if (truncate)
mode |= SPDLOG_O_TRUNCATE;
for (int tries = 0; tries < open_tries; ++tries)
{
if (!os::fopen_s(&_fd, fname, mode))
return;
std::this_thread::sleep_for(std::chrono::milliseconds(open_interval));
}
throw spdlog_ex("Failed opening file " + os::filename_to_str(_filename) + " for writing", errno);
}
static bool file_exists(const filename_t& name)
virtual void reopen(bool truncate) override
{
if (_filename.empty())
{
throw spdlog_ex("Failed re opening file - was not opened before");
}
open(_filename, truncate);
}
virtual void write(const spdlog::details::log_msg& msg) override
{
os::write_s(_fd, msg.formatted.data(), msg.formatted.size());
}
return os::file_exists(name);
virtual void flush() override
{
// We do not flush because writes supposed to be atomic - all
// data is already in file on disk
}
virtual void close() override
{
if (_fd >= 0)
{
os::close_s(_fd);
_fd = -1;
}
}
virtual size_t size() override
{
if (_fd < 0)
throw spdlog_ex("Cannot use size() on closed file " + os::filename_to_str(_filename));
return os::filesize(_fd);
}
private:
FILE* _fd;
filename_t _filename;
int _fd;
};
}
}

@ -17,6 +17,7 @@
#include <cstdlib>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#ifdef _WIN32
@ -38,17 +39,53 @@
#else // unix
#include <unistd.h>
#include <fcntl.h>
#include <sys/uio.h>
#ifdef __linux__
#include <sys/syscall.h> //Use gettid() syscall under linux to get thread id
#include <linux/limits.h> // for PIPE_BUF
#elif __FreeBSD__
#include <sys/thr.h> //Use thr_self() syscall under FreeBSD to get thread id
#include <limits.h>
#endif
// Max number of iovec structures
#ifndef IOV_MAX
#define IOV_MAX UIO_MAXIOV
#endif
#endif //unix
// File open modes
#if defined(_WIN32) && !defined(__MINGW32__)
#define SPDLOG_O_APPEND _O_APPEND
#define SPDLOG_O_CREATE _O_CREAT
#define SPDLOG_O_BINARY _O_BINARY
#define SPDLOG_O_WRONLY _O_WRONLY
#define SPDLOG_O_RDONLY _O_RDONLY
#define SPDLOG_O_RDWR _O_RDWR
#define SPDLOG_O_TRUNCATE _O_TRUNC
#else // unix and MinGW
#define SPDLOG_O_APPEND O_APPEND
#define SPDLOG_O_CREATE O_CREAT
#ifdef O_BINARY
#define SPDLOG_O_BINARY O_BINARY
#else
#define SPDLOG_O_BINARY 0
#endif
#define SPDLOG_O_WRONLY O_WRONLY
#define SPDLOG_O_RDONLY O_RDONLY
#define SPDLOG_O_RDWR O_RDWR
#define SPDLOG_O_TRUNCATE O_TRUNC
#endif
#ifndef __has_feature // Clang - feature checking macros.
#define __has_feature(x) 0 // Compatibility with non-clang compilers.
#endif
@ -77,6 +114,7 @@ inline spdlog::log_clock::time_point now()
#endif
}
inline std::tm localtime(const std::time_t &time_tt)
{
@ -96,7 +134,6 @@ inline std::tm localtime()
return localtime(now_t);
}
inline std::tm gmtime(const std::time_t &time_tt)
{
@ -115,6 +152,7 @@ inline std::tm gmtime()
std::time_t now_t = time(nullptr);
return gmtime(now_t);
}
inline bool operator==(const std::tm& tm1, const std::tm& tm2)
{
return (tm1.tm_sec == tm2.tm_sec &&
@ -143,31 +181,43 @@ inline bool operator!=(const std::tm& tm1, const std::tm& tm2)
SPDLOG_CONSTEXPR static const char* eol = SPDLOG_EOL;
SPDLOG_CONSTEXPR static int eol_size = sizeof(SPDLOG_EOL) - 1;
inline void prevent_child_fd(FILE *f)
inline int fileno_s(FILE* file)
{
#ifdef _WIN32
return _fileno(file);
#else
return fileno(file);
#endif
}
inline void prevent_child_fd(int fd)
{
#ifdef _WIN32
auto file_handle = (HANDLE)_get_osfhandle(_fileno(f));
auto file_handle = (HANDLE)_get_osfhandle(fd);
if (!::SetHandleInformation(file_handle, HANDLE_FLAG_INHERIT, 0))
throw spdlog_ex("SetHandleInformation failed", errno);
#else
auto fd = fileno(f);
if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1)
throw spdlog_ex("fcntl with FD_CLOEXEC failed", errno);
#endif
}
inline void prevent_child_fd(FILE *f)
{
prevent_child_fd(fileno_s(f));
}
//fopen_s on non windows for writing
inline int fopen_s(FILE** fp, const filename_t& filename, const filename_t& mode)
{
#ifdef _WIN32
#ifdef SPDLOG_WCHAR_FILENAMES
*fp = _wfsopen((filename.c_str()), mode.c_str(), _SH_DENYWR);
*fp = _wfsopen((filename.c_str()), (mode.c_str()), _SH_DENYWR);
#else
*fp = _fsopen((filename.c_str()), mode.c_str(), _SH_DENYWR);
*fp = _fsopen((filename.c_str()), (mode.c_str()), _SH_DENYWR);
#endif
#else //unix
*fp = fopen((filename.c_str()), mode.c_str());
*fp = fopen((filename.c_str()), (mode.c_str()));
#endif
#ifdef SPDLOG_PREVENT_CHILD_FD
@ -177,6 +227,97 @@ inline int fopen_s(FILE** fp, const filename_t& filename, const filename_t& mode
return *fp == nullptr;
}
inline int fopen_s(int* fp, const filename_t& filename, const int& mode)
{
#ifdef _WIN32
#ifdef SPDLOG_WCHAR_FILENAMES
_wsopen_s(fp, (filename.c_str()), mode, _SH_DENYNO, (_S_IREAD | _S_IWRITE));
#else
_sopen_s(fp, (filename.c_str()), mode, _SH_DENYNO, (_S_IREAD | _S_IWRITE));
#endif
#else //unix
*fp = open((filename.c_str()), mode, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH);
#endif
#ifdef SPDLOG_PREVENT_CHILD_FD
if (*fp != nullptr)
prevent_child_fd(*fp);
#endif
// Return true if something went wrong; false - if there was no errors and
// we get new file descriptor
return (fp != nullptr) && (*fp < 0) ? true : false;
}
inline void write_s(int fd, const char* msg, std::size_t size)
{
#ifdef _WIN32
// TODO: what is max size of data for atomic write on Windows?
int result = _write(fd, msg, size);
if ( (result < 0) || (static_cast<std::size_t>(result) != size) )
{
throw spdlog_ex("Write to file failed", errno);
}
// Immediately flush data to file
_commit(fd);
#else // unix
// PIPE_BUF - max message length for atomic write
if (size <= static_cast<std::size_t>(PIPE_BUF))
{
if (write(fd, msg, size) != static_cast<ssize_t>(size))
{
throw spdlog_ex("Write to file failed", errno);
}
}
else
{
// Max message length should be less than SSIZE_MAX (see writev() docs)
std::size_t msg_size = std::min(size, static_cast<std::size_t>(SSIZE_MAX));
// Calculate how many iovec structures we need
const std::size_t iovec_num = std::min((size / PIPE_BUF) + 1, static_cast<std::size_t>(IOV_MAX));
std::vector<iovec> iovectors(iovec_num);
// Warning: using const_cast so we could move along the message buffer
char* msg_ptr = const_cast<char*>(msg);
for (std::size_t i = 0; i < iovectors.size(); ++i)
{
iovectors[i].iov_base = static_cast<void*>(msg_ptr);
std::size_t msg_part_length = 0;
if (i < iovectors.size() - 1)
{
msg_part_length = PIPE_BUF;
}
else
{
// Calc length of the last iovec
std::size_t previos_parts_length = PIPE_BUF * i;
msg_part_length = std::min(msg_size - previos_parts_length, static_cast<std::size_t>(PIPE_BUF));
}
iovectors[i].iov_len = msg_part_length;
msg_ptr += msg_part_length;
}
if (writev(fd, &iovectors[0], iovec_num) != static_cast<ssize_t>(msg_size))
{
throw spdlog::spdlog_ex("Failed writing to file", errno);
}
}
#endif
}
inline void close_s(int fd)
{
#ifdef _WIN32
_close(fd);
#else // unix
close(fd);
#endif
}
inline int remove(const filename_t &filename)
{
@ -196,7 +337,6 @@ inline int rename(const filename_t& filename1, const filename_t& filename2)
#endif
}
//Return if file exists
inline bool file_exists(const filename_t& filename)
{
@ -213,29 +353,22 @@ inline bool file_exists(const filename_t& filename)
#endif
}
//Return file size according to open FILE* object
inline size_t filesize(FILE *f)
//Return file size according to open file descriptor
inline size_t filesize(int fd)
{
if (f == nullptr)
throw spdlog_ex("Failed getting file size. fd is null");
#ifdef _WIN32
int fd = _fileno(f);
#if _WIN64 //64 bits
struct _stat64 st;
if (_fstat64(fd, &st) == 0)
return st.st_size;
#else //windows 32 bits
#else // windows 32 bits
long ret = _filelength(fd);
if (ret >= 0)
return static_cast<size_t>(ret);
#endif
#else // unix
int fd = fileno(f);
//64 bits(but not in osx, where fstat64 is deprecated)
#if !defined(__FreeBSD__) && !defined(__APPLE__) && (defined(__x86_64__) || defined(__ppc64__))
struct stat64 st;
@ -247,11 +380,39 @@ inline size_t filesize(FILE *f)
return static_cast<size_t>(st.st_size);
#endif
#endif
throw spdlog_ex("Failed getting file size from fd", errno);
}
//Return file size according to open FILE* object
inline size_t filesize(FILE *f)
{
if (f == nullptr)
throw spdlog_ex("Failed getting file size. fd is null");
return filesize(fileno_s(f));
}
inline size_t filesize(const filename_t& filename)
{
int fd = -1;
const int open_tries = 5;
const int open_interval = 10;
for (int tries = 0; tries < open_tries; ++tries)
{
if (!fopen_s(&fd, filename, SPDLOG_O_RDONLY))
{
size_t file_size = filesize(fd);
close_s(fd);
return file_size;
}
std::this_thread::sleep_for(std::chrono::milliseconds(open_interval));
}
throw spdlog_ex("Failed opening file for filesize command", errno);
}
//Return utc offset in minutes or throw spdlog_ex on failure
inline int utc_minutes_offset(const std::tm& tm = details::os::localtime())
@ -414,13 +575,11 @@ inline std::string errno_str(int err_num)
inline int pid()
{
#ifdef _WIN32
return ::_getpid();
#else
return static_cast<int>(::getpid());
#endif
}
@ -457,11 +616,10 @@ inline bool is_color_terminal()
// Source: https://github.com/agauniyal/rang/
inline bool in_terminal(FILE* file)
{
#ifdef _WIN32
return _isatty(_fileno(file)) ? true : false;
return _isatty(fileno_s(file)) ? true : false;
#else
return isatty(fileno(file)) ? true : false;
return isatty(fileno_s(file)) ? true : false;
#endif
}
} //os

@ -145,6 +145,165 @@ private:
typedef rotating_file_sink<std::mutex> rotating_file_sink_mt;
typedef rotating_file_sink<details::null_mutex>rotating_file_sink_st;
// Rotating file sink for multi-process environment
template<class Mutex>
class rotating_file_sink_mp SPDLOG_FINAL : public spdlog::sinks::base_sink < Mutex >
{
public:
rotating_file_sink_mp(const spdlog::filename_t & base_filename,
const std::size_t& max_size,
const std::size_t& max_files) :
_base_filename(base_filename),
_max_size(max_size),
_max_files(max_files),
_file_helper()
{
_rotating_file = get_folder_path(_base_filename) + "rotating";
_file_helper.open(calc_filename(_base_filename, 0));
}
protected:
void _sink_it(const details::log_msg& msg) override
{
if (details::os::file_exists(_rotating_file))
{
wait_till_rotation_completed();
}
else
{
size_t file_size = _file_helper.size();
if ( (file_size + msg.formatted.size()) > _max_size )
{
// Check that _file_helper give us real size of a log file and not a size of already rotated (old) log file
if (file_size <= details::os::filesize(_file_helper.filename()))
{
// Because previous operation was long, check that other processes did not started rotation
if (details::os::file_exists(_rotating_file))
{
wait_till_rotation_completed();
}
else
{
safe_rotation();
}
}
else
{
// File helper have file descriptor to rotated log file. We need to close it and open current log file
_file_helper.reopen(false);
}
}
}
_file_helper.write(msg);
}
void _flush() override
{
_file_helper.flush();
}
private:
static filename_t get_folder_path(const filename_t& filename)
{
size_t pos = filename.find_last_of('/');
if (pos == std::string::npos)
{
return filename_t("/");
}
filename_t path;
path.assign(filename, 0, pos + 1);
return path;
}
static filename_t calc_filename(const filename_t& filename, std::size_t index)
{
std::conditional<std::is_same<filename_t::value_type, char>::value, fmt::MemoryWriter, fmt::WMemoryWriter>::type w;
if (index)
w.write(SPDLOG_FILENAME_T("{}.{}"), filename, index);
else
w.write(SPDLOG_FILENAME_T("{}"), filename);
return w.str();
}
void wait_till_rotation_completed()
{
_file_helper.close();
const int max_tries = 100;
const int sleep_time = 10;
for (int i = 0; i < max_tries; ++i)
{
if (!details::os::file_exists(_rotating_file))
{
break;
}
std::this_thread::sleep_for(std::chrono::milliseconds(sleep_time));
}
_file_helper.reopen(false);
}
void safe_rotation()
{
// create rotating file
details::file_helper_mp rotating_file;
rotating_file.open(_rotating_file);
rotating_file.close();
// close log file
_file_helper.close();
// perform rotation
_rotate();
// open log file and truncate it
_file_helper.reopen(true);
// delete rotating file
details::os::remove(_rotating_file);
}
// Rotate files:
// log.txt -> log.txt.1
// log.txt.1 -> log.txt.2
// log.txt.2 -> log.txt.3
// lo3.txt.3 -> delete
void _rotate()
{
for (auto i = _max_files; i > 0; --i)
{
filename_t src = calc_filename(_base_filename, i - 1);
filename_t target = calc_filename(_base_filename, i);
if (details::os::file_exists(target))
{
if (details::os::remove(target) != 0)
{
throw spdlog_ex("rotating_file_sink: failed removing " + details::os::filename_to_str(target), errno);
}
}
if (details::os::file_exists(src) && details::os::rename(src, target))
{
throw spdlog_ex("rotating_file_sink: failed renaming " + details::os::filename_to_str(src) + " to " + details::os::filename_to_str(target), errno);
}
}
}
private:
filename_t _base_filename;
filename_t _rotating_file;
std::size_t _max_size;
std::size_t _max_files;
details::file_helper_mp _file_helper;
};
typedef rotating_file_sink_mp<std::mutex> rotating_file_sink_mp_mt;
typedef rotating_file_sink_mp<spdlog::details::null_mutex> rotating_file_sink_mp_st;
/*
* Default generator of daily log file names.
*/

@ -7,15 +7,14 @@ using namespace spdlog::details;
static const std::string target_filename = "logs/file_helper_test.txt";
static void write_with_helper(file_helper &helper, size_t howmany)
static void write_with_helper(base_file_helper* helper, size_t howmany)
{
log_msg msg;
msg.formatted << std::string(howmany, '1');
helper.write(msg);
helper.flush();
helper->write(msg);
helper->flush();
}
TEST_CASE("file_helper_filename", "[file_helper::filename()]]")
{
prepare_logdir();
@ -25,8 +24,6 @@ TEST_CASE("file_helper_filename", "[file_helper::filename()]]")
REQUIRE(helper.filename() == target_filename);
}
TEST_CASE("file_helper_size", "[file_helper::size()]]")
{
prepare_logdir();
@ -34,13 +31,12 @@ TEST_CASE("file_helper_size", "[file_helper::size()]]")
{
file_helper helper;
helper.open(target_filename);
write_with_helper(helper, expected_size);
write_with_helper(&helper, expected_size);
REQUIRE(static_cast<size_t>(helper.size()) == expected_size);
}
REQUIRE(get_filesize(target_filename) == expected_size);
}
TEST_CASE("file_helper_exists", "[file_helper::file_exists()]]")
{
prepare_logdir();
@ -55,7 +51,7 @@ TEST_CASE("file_helper_reopen", "[file_helper::reopen()]]")
prepare_logdir();
file_helper helper;
helper.open(target_filename);
write_with_helper(helper, 12);
write_with_helper(&helper, 12);
REQUIRE(helper.size() == 12);
helper.reopen(true);
REQUIRE(helper.size() == 0);
@ -67,12 +63,62 @@ TEST_CASE("file_helper_reopen2", "[file_helper::reopen(false)]]")
size_t expected_size = 14;
file_helper helper;
helper.open(target_filename);
write_with_helper(helper, expected_size);
write_with_helper(&helper, expected_size);
REQUIRE(helper.size() == expected_size);
helper.reopen(false);
REQUIRE(helper.size() == expected_size);
}
TEST_CASE("file_helper_mp_filename", "[file_helper_mp::filename()]]")
{
prepare_logdir();
file_helper_mp helper;
helper.open(target_filename);
REQUIRE(helper.filename() == target_filename);
}
TEST_CASE("file_helper_mp_size", "[file_helper_mp::size()]]")
{
prepare_logdir();
size_t expected_size = 123;
{
file_helper_mp helper;
helper.open(target_filename);
write_with_helper(&helper, expected_size);
REQUIRE(static_cast<size_t>(helper.size()) == expected_size);
}
REQUIRE(get_filesize(target_filename) == expected_size);
}
TEST_CASE("file_helper_mp_exists", "[file_helper_mp::file_exists()]]")
{
prepare_logdir();
REQUIRE(!file_helper_mp::file_exists(target_filename));
file_helper_mp helper;
helper.open(target_filename);
REQUIRE(file_helper_mp::file_exists(target_filename));
}
TEST_CASE("file_helper_mp_reopen", "[file_helper_mp::reopen()]]")
{
prepare_logdir();
file_helper_mp helper;
helper.open(target_filename);
write_with_helper(&helper, 12);
REQUIRE(helper.size() == 12);
helper.reopen(true);
REQUIRE(helper.size() == 0);
}
TEST_CASE("file_helper_mp_reopen2", "[file_helper_mp::reopen(false)]]")
{
prepare_logdir();
size_t expected_size = 14;
file_helper_mp helper;
helper.open(target_filename);
write_with_helper(&helper, expected_size);
REQUIRE(helper.size() == expected_size);
helper.reopen(false);
REQUIRE(helper.size() == expected_size);
}

@ -24,7 +24,6 @@ TEST_CASE("simple_file_logger", "[simple_logger]]")
REQUIRE(count_lines(filename) == 2);
}
TEST_CASE("flush_on", "[flush_on]]")
{
prepare_logdir();
@ -69,7 +68,6 @@ TEST_CASE("rotating_file_logger1", "[rotating_logger]]")
REQUIRE(count_lines(filename) == 10);
}
TEST_CASE("rotating_file_logger2", "[rotating_logger]]")
{
prepare_logdir();
@ -97,6 +95,40 @@ TEST_CASE("rotating_file_logger2", "[rotating_logger]]")
}
TEST_CASE("rotating_file_logger_mp1", "[rotating_logger]]")
{
prepare_logdir();
std::string basename = "logs/rotating_log";
auto logger = spdlog::create<spdlog::sinks::rotating_file_sink_mp_mt>("logger", basename, 1024, 0);
for (int i = 0; i < 10; ++i)
logger->info("Test message {}", i);
logger->flush();
auto filename = basename;
REQUIRE(count_lines(filename) == 10);
}
TEST_CASE("rotating_file_logger_mp2", "[rotating_logger]]")
{
prepare_logdir();
std::string basename = "logs/rotating_log";
auto logger = spdlog::create<spdlog::sinks::rotating_file_sink_mp_mt>("logger", basename, 1024, 1);
for (int i = 0; i < 10; ++i)
logger->info("Test message {}", i);
logger->flush();
auto filename = basename;
REQUIRE(count_lines(filename) == 10);
for (int i = 0; i < 1000; i++)
logger->info("Test message {}", i);
logger->flush();
REQUIRE(get_filesize(filename) <= 1024);
auto filename1 = basename + ".1";
REQUIRE(get_filesize(filename1) <= 1024);
}
TEST_CASE("daily_logger", "[daily_logger]]")
{
prepare_logdir();
@ -121,7 +153,6 @@ TEST_CASE("daily_logger", "[daily_logger]]")
REQUIRE(count_lines(filename) == 10);
}
TEST_CASE("daily_logger with dateonly calculator", "[daily_logger_dateonly]]")
{
using sink_type = spdlog::sinks::daily_file_sink<
@ -187,4 +218,3 @@ TEST_CASE("daily_logger with custom calculator", "[daily_logger_custom]]")
auto filename = w.str();
REQUIRE(count_lines(filename) == 10);
}

@ -14,6 +14,7 @@
#define SPDLOG_DEBUG_ON
#include "../include/spdlog/spdlog.h"
#include "../include/spdlog/sinks/file_sinks.h"
#include "../include/spdlog/sinks/null_sink.h"
#include "../include/spdlog/sinks/ostream_sink.h"

Loading…
Cancel
Save