111 lines
2.6 KiB
C++
111 lines
2.6 KiB
C++
#include "matador/logger/rotating_file_sink.hpp"
|
|
|
|
#include "matador/utils/string.hpp"
|
|
#include "matador/utils/os.hpp"
|
|
|
|
#include <iostream>
|
|
#include <cstring>
|
|
|
|
namespace matador::logger {
|
|
|
|
rotating_file_sink::rotating_file_sink(const std::string& path, size_t max_size, size_t file_count)
|
|
: max_size_(max_size)
|
|
, file_count_(file_count)
|
|
{
|
|
// split path and file
|
|
prepare(path);
|
|
|
|
current_size_ = logfile_.size();
|
|
}
|
|
|
|
void rotating_file_sink::write(const char *message, size_t size)
|
|
{
|
|
current_size_ += size;
|
|
if (current_size_ > max_size_) {
|
|
current_size_ = size;
|
|
rotate();
|
|
}
|
|
fwrite(message, sizeof(char), size, logfile_.stream());
|
|
fflush(logfile_.stream());
|
|
}
|
|
|
|
void rotating_file_sink::close()
|
|
{
|
|
logfile_.close();
|
|
}
|
|
|
|
std::string rotating_file_sink::calculate_filename(size_t fileno)
|
|
{
|
|
char buffer[1024];
|
|
#ifdef _WIN32
|
|
sprintf_s(buffer, 1024, "%s.%zu.%s", base_path_.c_str(), fileno, extension_.c_str());
|
|
#else
|
|
sprintf(buffer, "%s.%zu.%s", base_path_.c_str(), fileno, extension_.c_str());
|
|
#endif
|
|
return buffer;
|
|
}
|
|
|
|
/*
|
|
* Rotate log files:
|
|
* log_path.log -> log_path.01.log
|
|
* log_path.01.log -> log_path.02.log
|
|
* log_path.02.log -> log_path.03.log
|
|
* ...
|
|
* log_path.[n-1].log -> log_path.[n].log
|
|
* delete log_path.[n].log
|
|
* create new log_path.log
|
|
*/
|
|
void rotating_file_sink::rotate()
|
|
{
|
|
std::string filename;
|
|
for (size_t i = file_count_; i != 0; --i) {
|
|
filename = calculate_filename(i);
|
|
if (!matador::os::exists(filename.c_str())) {
|
|
continue;
|
|
}
|
|
if (i == file_count_) {
|
|
matador::os::remove(filename.c_str());
|
|
} else {
|
|
matador::os::rename(filename.c_str(), calculate_filename(i+1).c_str());
|
|
}
|
|
}
|
|
std::string path = logfile_.path();
|
|
logfile_.close();
|
|
matador::os::rename(path.c_str(), filename.c_str());
|
|
logfile_.open(path, "a");
|
|
}
|
|
|
|
void rotating_file_sink::prepare(const std::string &path)
|
|
{
|
|
std::string filename(path);
|
|
// find last dir delimiter
|
|
const char *last = strrchr(path.c_str(), os::DIR_SEPARATOR);
|
|
if (last != nullptr) {
|
|
path_.assign(path.data(), last-path.data());
|
|
} else {
|
|
path_.clear();
|
|
}
|
|
|
|
if (last != nullptr) {
|
|
filename = (last + 1);
|
|
}
|
|
// extract base path and extension
|
|
std::vector<std::string> result;
|
|
if (utils::split(filename, '.', result) != 2) {
|
|
throw std::logic_error("split path must consists of two elements");
|
|
}
|
|
base_path_.assign(result[0]);
|
|
extension_.assign(result[1]);
|
|
// get the current path
|
|
const auto pwd = os::get_current_dir();
|
|
// make the path
|
|
os::mkpath(path_);
|
|
// change into the path
|
|
os::chdir(path_);
|
|
// create the file
|
|
logfile_.open(filename, "a");
|
|
// change back to the origin path
|
|
os::chdir(pwd);
|
|
}
|
|
}
|