292 lines
8.9 KiB
C++
292 lines
8.9 KiB
C++
#include "export.h"
|
|
|
|
#include "../system/export.h"
|
|
#include <filesystem>
|
|
#include <fstream>
|
|
#include <map>
|
|
|
|
#include "Core/Base/global_include.h"
|
|
#include "spdlog/sinks/basic_file_sink.h"
|
|
#include "spdlog/spdlog.h"
|
|
#ifdef WIN32
|
|
#define WIN32_LEAN_AND_MEAN
|
|
#include "Windows.h"
|
|
|
|
|
|
|
|
#else
|
|
std::string handle_fileName(const std::string& utf8_str) {
|
|
return utf8_str;
|
|
}
|
|
#endif
|
|
#include "../system/export.h"
|
|
#include "spdlog/async.h"
|
|
#include "spdlog/sinks/daily_file_sink.h"
|
|
#include "spdlog/sinks/rotating_file_sink.h"
|
|
#include "spdlog/spdlog.h"
|
|
#include <iostream>
|
|
#include <memory>
|
|
#include <string>
|
|
#include <unordered_map>
|
|
#include <vector>
|
|
|
|
#include "spdlog/pattern_formatter.h"
|
|
|
|
namespace fs = std::filesystem;
|
|
|
|
|
|
|
|
void spdlog_close() {
|
|
spdlog::shutdown();
|
|
}
|
|
|
|
Log_Type::Log_Type(std::vector<std::string> list) : list(list) {
|
|
|
|
}
|
|
|
|
Log_Type::Log_Type(std::vector<std::pair<std::string, std::string>> map) : map(map) {
|
|
|
|
}
|
|
|
|
Log_Type::Log_Type(std::vector<std::string> list, std::vector<std::pair<std::string, std::string>> map) : list(list), map(map) {
|
|
}
|
|
|
|
std::string get_current_date_string() {
|
|
// 获取当前时间
|
|
auto now = std::chrono::system_clock::now();
|
|
auto in_time_t = std::chrono::system_clock::to_time_t(now);
|
|
|
|
// 使用 std::put_time 格式化时间
|
|
std::ostringstream oss;
|
|
oss << std::put_time(std::localtime(&in_time_t), "%Y-%m-%d %H:%M:%S"); // 格式化为 "YYYY-MM-DD"
|
|
return oss.str();
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
std::shared_ptr<spdlog::logger> create_rotating_logger(const std::string& key, size_t byte_size, size_t num) {
|
|
std::string fileName = "@/logs/" + key + ".log";
|
|
fileName = Psc::get_abs_path(fileName);
|
|
fileName = Psc::utf8_2_platform(fileName);
|
|
Psc::create_file_if_not_exists(fileName);
|
|
auto rotating_sink = std::make_shared<spdlog::sinks::rotating_file_sink_mt>(
|
|
fileName,
|
|
byte_size,
|
|
num
|
|
);
|
|
|
|
|
|
std::vector<spdlog::sink_ptr> sinks = {rotating_sink};
|
|
auto logger = std::make_shared<spdlog::async_logger>(
|
|
key, // Logger 名称
|
|
sinks.begin(), sinks.end(), // Sinks 列表
|
|
spdlog::thread_pool(), // 使用初始化的线程池
|
|
spdlog::async_overflow_policy::block // 当队列满时,阻塞写入
|
|
);
|
|
return logger;
|
|
}
|
|
std::map<std::string, std::shared_ptr<spdlog::logger>> day_log_map;
|
|
void rotating_log(const std::string& key, const std::string& info, int size, int num) {
|
|
try {
|
|
if (day_log_map.find(key) == day_log_map.end()) {
|
|
day_log_map.insert({key, create_rotating_logger(key, size, num)});
|
|
}
|
|
std::shared_ptr<spdlog::logger> daily_logger = day_log_map[key];
|
|
daily_logger->set_pattern("%Y-%m-%d %H:%M:%S [%l] %v");
|
|
daily_logger->info(info);
|
|
daily_logger->flush();
|
|
} catch (const spdlog::spdlog_ex& e) {
|
|
std::cerr << "Log initialization failed: " << e.what() << std::endl;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void pure_log(const std::string& pure_path, const std::string& info, bool close_after_write) {
|
|
auto path = Psc::get_abs_path(pure_path);
|
|
static std::map<std::string, std::shared_ptr<spdlog::logger>> file_logger_map;
|
|
static std::mutex mtx; // 用于保护file_logger_map
|
|
static std::mutex mtx2; // 用于保护file_logger_map
|
|
static auto create_pure_logger = [](const std::string& fileName) {
|
|
Psc::create_file_if_not_exists( fileName);
|
|
auto c = spdlog::basic_logger_mt(fileName, fileName);
|
|
auto formatter = std::make_unique<spdlog::pattern_formatter>("%v", spdlog::pattern_time_type::local, "", spdlog::pattern_formatter::custom_flags());
|
|
c->set_formatter(std::move(formatter));
|
|
return c;
|
|
};
|
|
|
|
if (close_after_write) {
|
|
// 用完就关:每次都新建,写完就析构
|
|
std::lock_guard<std::mutex> lock(mtx2); // 加锁以保证线程安全
|
|
auto logger = create_pure_logger(path);
|
|
logger->log(spdlog::level::info, info);
|
|
logger->flush();
|
|
|
|
spdlog::drop(path);
|
|
// 离开作用域后logger自动析构,文件关闭
|
|
return;
|
|
} else {
|
|
std::lock_guard<std::mutex> lock(mtx); // 加锁以保证线程安全
|
|
auto iter = file_logger_map.find(path);
|
|
if (iter == file_logger_map.end()) {
|
|
file_logger_map.insert({path, create_pure_logger(path)});
|
|
}
|
|
std::shared_ptr<spdlog::logger> logger = file_logger_map[path];
|
|
logger->log(spdlog::level::info, info);
|
|
logger->flush();
|
|
}
|
|
}
|
|
|
|
Log_Type& Log_Type::append(std::string key) {
|
|
list.push_back(key);
|
|
return *this;
|
|
}
|
|
|
|
Log_Type& Log_Type::append(std::string key, std::string val) {
|
|
map.push_back({key, val});
|
|
return *this;
|
|
}
|
|
|
|
std::string Log_Type::to_string() const{
|
|
std::string base;
|
|
for (const auto& it : list) {
|
|
base += "[" + it + "] ";
|
|
}
|
|
for (const auto& it : map) {
|
|
if (new_line) {
|
|
base += "\n";
|
|
}
|
|
base += "[" + it.first + "~" + it.second + "] ";
|
|
|
|
}
|
|
return base;
|
|
}
|
|
|
|
Log_Type& Log_Type::set(const std::string& key, std::string val) {
|
|
append(key, val);
|
|
return *this;
|
|
}
|
|
|
|
|
|
namespace spdlog {
|
|
struct my_daily_filename_calculator {
|
|
// Create filename for the form basename.YYYY-MM-DD
|
|
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);
|
|
}
|
|
};
|
|
}
|
|
|
|
|
|
BaseLogger::BaseLogger(const std::string& log_path, size_t byte_size, size_t piece_num)
|
|
: log_path(log_path), byte_size(byte_size), piece_num(piece_num) {
|
|
std::string path = Psc::get_abs_path(log_path);
|
|
Psc::create_file_if_not_exists(path);
|
|
|
|
path = Psc::utf8_2_platform(path);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
auto rotating_sink = std::make_shared<spdlog::sinks::rotating_file_sink_mt>(
|
|
path,
|
|
byte_size,
|
|
piece_num
|
|
);
|
|
std::vector<spdlog::sink_ptr> sinks = {rotating_sink};
|
|
logger = std::make_shared<spdlog::async_logger>(
|
|
path, // Logger 名称
|
|
sinks.begin(), sinks.end(), // Sinks 列表
|
|
spdlog::thread_pool(), // 使用初始化的线程池
|
|
spdlog::async_overflow_policy::block // 当队列满时,阻塞写入
|
|
);
|
|
//logger->set_level(spdlog::level::debug);
|
|
logger->set_pattern("[%Y-%m-%d %H:%M:%S.%e] [%l] %v");
|
|
}
|
|
|
|
|
|
Base_Logger_Manager::Base_Logger_Manager() {
|
|
spdlog::set_level(spdlog::level::debug);
|
|
}
|
|
|
|
|
|
Base_Logger_Manager& Base_Logger_Manager::set_thread_num(size_t thread_num) {
|
|
this->thread_num = thread_num;
|
|
return *this;
|
|
}
|
|
|
|
Base_Logger_Manager& Base_Logger_Manager::set_flush_seconds(size_t flush_seconds) {
|
|
this->flush_seconds = flush_seconds;
|
|
return *this;
|
|
}
|
|
|
|
Base_Logger_Manager& Base_Logger_Manager::set_buffer_size(size_t buffer_size) {
|
|
this->buffer_size = buffer_size;
|
|
return *this;
|
|
}
|
|
|
|
void Base_Logger_Manager::init() const {
|
|
spdlog::init_thread_pool(buffer_size, thread_num);
|
|
spdlog::flush_every(std::chrono::seconds(flush_seconds));
|
|
std::cout << "Base_Logger_Manager sqdlog init thread pool!" + VAR_STR_3(thread_num, flush_seconds, buffer_size) << std::endl;
|
|
}
|
|
|
|
|
|
// 调用 spdlog::shutdown() 会确保:
|
|
// 所有日志被刷新到磁盘。
|
|
// 所有日志器被关闭,相关资源被释放。
|
|
Base_Logger_Manager::~Base_Logger_Manager() {
|
|
std::ostringstream oss;
|
|
oss << "Base_Logger_Manager::~Base_Logger_Manager()" << VAR_STR_3(buffer_size, flush_seconds, thread_num) << std::flush;
|
|
spdlog::shutdown();
|
|
oss << "spdlog::shutdown()!\n" << std::flush;
|
|
std::cout << oss.str();
|
|
}
|
|
|
|
std::string BaseLogger::to_log(const Log_Info& log_info) {
|
|
return "[" + std::string("func") + "~" + log_info.func_pattern + "] " + log_info.log_type.to_string() +
|
|
log_info.content;
|
|
}
|
|
|
|
|
|
void BaseLogger::log_main(const Log_Info& log_info) const {
|
|
auto msg = to_log(log_info);
|
|
if (log_info.console) {
|
|
std::cerr << msg + "\n" << std::flush;
|
|
}
|
|
//logger->log(level, msg);
|
|
logger->info(msg);
|
|
if(redirect){
|
|
redirect(log_info);
|
|
}
|
|
}
|
|
|
|
|
|
void BaseLogger::c_debug(const std::string& func_pattern, const Log_Type& log_type, const std::string& content) {
|
|
log_main({true, spdlog::level::debug, func_pattern, log_type, content});
|
|
}
|
|
|
|
void BaseLogger::debug(const std::string& func_pattern, const Log_Type& log_type, const std::string& content) {
|
|
log_main({false, spdlog::level::debug, func_pattern, log_type, content});
|
|
}
|
|
|
|
void BaseLogger::error(const std::string& func_pattern, const Log_Type& log_type, const std::string& content) {
|
|
log_main({true, spdlog::level::err, func_pattern, log_type, content});
|
|
logger->flush();
|
|
}
|