//local #include "logger_impl.h" //stl #include #include #include //boost #include namespace robotics::v3 { logger_impl::~logger_impl() { thread_pool_.join(); } void logger_impl::write(int color, std::string const& type, std::string const& time, std::string const& file, std::string const& func, int line, std::thread::id thread_id, std::string const& text) { if (!thread_pool_.executor().running_in_this_thread()) { asio::post(thread_pool_, std::bind(&logger_impl::write, this, color, type, time, file, func, line, thread_id, text)); return; } static time_t g_remove_ergodic = 0; union __thread_id__ { __thread_id__(std::thread::id d) : id(d) { } std::thread::id id; unsigned int iid; }; __thread_id__ th_id = thread_id; if (save_.find(type) == save_.end()) { std::cout << fmt::format("\033[{}m{} [{}] [{}#{}#{}#{}] ==>>\033[0m{}", color, time, type, file, func, line, th_id.iid, text) << std::endl; } else { if (!std::filesystem::is_directory("log")) { std::filesystem::create_directory("log"); } std::string log_text = fmt::format("{} [{}] [{}#{}#{}#{}] ==>>{}", time, type, file, func, line, th_id.iid, text); std::string log_filename = fmt::format("log/{}_{}.log", type, datetime::current_datetime().to_string("yyyy-MM-dd")); std::fstream fs(log_filename, std::ios::out | std::ios::app); if (fs.is_open()) { fs << log_text; fs << std::endl; fs.close(); backup(log_filename); time_t current_time = datetime::current_time_stamp(); if (g_remove_ergodic == 0 || g_remove_ergodic + 43200000 < current_time) { g_remove_ergodic = current_time; remove(); } } } } logger_impl& logger_impl::instance() { static logger_impl g_instance; return g_instance; } void logger_impl::install(std::string const& filename) { instance().max_time_ = config::read("LOGGER", "TIME", 30); instance().max_size_ = config::read("LOGGER", "SIZE", 10); auto type = config::read("LOGGER", "TYPE", "info,debug,warn,error"); std::vector types; boost::split(types, type, boost::is_any_of(",")); for (auto& it : types) { if (it.empty()) continue; instance().save_.insert(it); } } logger_impl::logger_impl() : thread_pool_(1) { } void logger_impl::backup(std::string const& filename) { if (!std::filesystem::exists(filename) || std::filesystem::file_size(filename) <= max_size_ * 1024 * 1024) return; for (int i = 0; i < 10; i++) { std::string backup_filename = filename; std::random_device r; std::default_random_engine e1(r()); std::uniform_int_distribution uniform_dist(10000, 99999); std::string mean = "__" + std::to_string(uniform_dist(e1)); backup_filename.insert(backup_filename.begin() + backup_filename.size() - 4, mean.begin(), mean.end()); if (std::filesystem::exists(backup_filename)) continue; std::filesystem::copy(filename, backup_filename); std::fstream fout(filename, std::ios::out | std::ios::trunc); fout.close(); break; } } void logger_impl::remove() { datetime remove_time = datetime::current_datetime(); remove_time.add_day(-this->max_time_); const std::filesystem::path path_to_directory = "log"; try { if (std::filesystem::exists(path_to_directory) && std::filesystem::is_directory(path_to_directory)) { for (const auto& entry : std::filesystem::recursive_directory_iterator(path_to_directory)) { const auto& path = entry.path(); if (std::filesystem::is_regular_file(path)) { auto create_time = std::filesystem::last_write_time(path); time_t elapse = std::chrono::duration_cast(std::filesystem::file_time_type::clock::now().time_since_epoch() - std::chrono::system_clock::now().time_since_epoch()).count(); std::chrono::milliseconds secs = std::chrono::duration_cast(create_time.time_since_epoch()); v3::datetime time = (secs.count() - elapse); if (remove_time > time) { std::filesystem::remove(path); } } } } } catch (...) {} } logger_stream::logger_stream( int color, std::string const& type, std::string const& time, std::string const& file, std::string const& func, int line, std::thread::id thread_id) : color_(color), type_(type), time_(time), file_(file), func_(func), line_(line), thread_id_(thread_id) { } logger_stream::~logger_stream() { std::string text = stream.str(); if (!text.empty()) logger_impl::instance().write(color_, type_, time_, file_, func_, line_, thread_id_, text); } }