#include "daily_and_size_sink.h" #include #include #include "date_util.h" namespace zsy { DailyAndSizeSink::DailyAndSizeSink(const std::string &filename, uintmax_t maxSize, int32_t maxDays) : maxSize(maxSize) , maxDays(maxDays) { std::filesystem::path base_path(filename); auto paths = base_path.parent_path(); basePath = paths.string(); baseFilename = base_path.stem().string(); baseExt = base_path.extension().string(); std::filesystem::create_directories(paths); currentDate = DateUtil::format(Ymd_); currentIndex = lastIndex(); currentSize = lastSize(); fileHelper.open(basePath + "\\" + baseFilename + baseExt, false); } void DailyAndSizeSink::rotateFile() { auto current_date = DateUtil::format(Ymd_); if (current_date != currentDate) { fileHelper.flush(); fileHelper.close(); std::filesystem::rename(basePath + "\\" + baseFilename + baseExt, basePath + "\\" + baseFilename + "." + currentDate + "." + std::to_string(currentIndex) + baseExt); fileHelper.open(basePath + "\\" + baseFilename + baseExt, false); currentDate = current_date; currentIndex = 1; } else { if (currentSize >= maxSize) { fileHelper.flush(); fileHelper.close(); std::filesystem::rename(basePath + "\\" + baseFilename + baseExt, basePath + "\\" + baseFilename + "." + currentDate + "." + std::to_string(currentIndex) + baseExt); fileHelper.open(basePath + "\\" + baseFilename + baseExt, false); currentIndex++; } } } void DailyAndSizeSink::cleanOldFiles() { try { if (maxDays <= 0) return; auto now = std::chrono::floor(std::chrono::system_clock::now()); auto cutoff_time = now - std::chrono::days(maxDays); // 正则表达式模式:baseName.YYYY-MM-DD(.index)?.ext std::regex file_pattern(baseFilename + R"(\.(\d{4}-\d{2}-\d{2})(\.\d+)?)" + baseExt); std::filesystem::path paths(basePath); for (const auto &entry: std::filesystem::directory_iterator(paths)) { if (entry.is_regular_file()) { std::string filename = entry.path().filename().string(); std::smatch match; if (std::regex_match(filename, match, file_pattern)) { std::string date_str = match[1].str(); std::chrono::sys_days date; std::istringstream tstr(date_str); tstr >> std::chrono::parse("%F", date); if (date < cutoff_time) { std::filesystem::remove(entry.path()); } } } } } catch (const std::exception &e) { // 清理失败 } } void DailyAndSizeSink::sink_it_(const spdlog::details::log_msg &msg) { spdlog::memory_buf_t formatted; formatter_->format(msg, formatted); std::string formatted_str(formatted.data(), formatted.size()); rotateFile(); fileHelper.write(formatted); currentSize = fileHelper.size(); cleanOldFiles(); } void DailyAndSizeSink::flush_() { fileHelper.flush(); } uint32_t DailyAndSizeSink::lastIndex() { uint32_t index = 0; std::regex file_pattern(baseFilename + R"(\.\d{4}-\d{2}-\d{2}\.(\d+))" + baseExt); std::filesystem::path paths(basePath); for (const auto &entry: std::filesystem::directory_iterator(paths)) { if (entry.is_regular_file()) { std::string filename = entry.path().filename().string(); std::smatch match; if (std::regex_match(filename, match, file_pattern)) { std::string index_str = match[1].str(); auto index_chp = index_str.data(); int index_{}; std::from_chars(index_chp, index_chp + index_str.size(), index_); if (index_ > index) index = index_; } } } return index + 1; } uintmax_t DailyAndSizeSink::lastSize() { uintmax_t size = 0; std::filesystem::path filePath(basePath + "\\" + baseFilename + baseExt); if (std::filesystem::exists(filePath)) { size = std::filesystem::file_size(filePath); } return size; } }