diff --git a/.gitignore b/.gitignore index 5d947ca..1dcb1a0 100644 --- a/.gitignore +++ b/.gitignore @@ -13,6 +13,14 @@ bin-release/ *.ipa *.apk +# environment +vcpkg/ +build/ +external/ + +# build log +logs/ + # Project files, i.e. `.project`, `.actionScriptProperties` and `.flexProperties` # should NOT be excluded as they contain compiler settings and other important # information for Eclipse / Flash Builder. diff --git a/CMakeLists.txt b/CMakeLists.txt index fb03879..bd6be85 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,7 +3,23 @@ project(fastlog) set(CMAKE_CXX_STANDARD 23) set(CMAKE_BUILD_TYPE Debug) -find_package(cpptrace CONFIG REQUIRED) +include(FetchContent) + +set(FETCHCONTENT_SOURCE_DIR_CPPTRACE "${CMAKE_CURRENT_SOURCE_DIR}/external/cpptrace") + +FetchContent_Declare( + cpptrace + GIT_REPOSITORY https://github.com/jeremy-rifkin/cpptrace.git + GIT_TAG v1.0.4 + GIT_SHALLOW TRUE +) + +set(FETCHCONTENT_UPDATES_DISCONNECTED ON) +set(FETCHCONTENT_QUIET OFF) +set(FETCHCONTENT_BASE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/external") + +FetchContent_MakeAvailable(cpptrace) + set(LIB cpptrace::cpptrace) # 定义文件日志路径 add_definitions(-DFILE_LOG1_PATH="${CMAKE_CURRENT_SOURCE_DIR}/logs/log1/") diff --git a/fastlog/detail/logbuffer.hpp b/fastlog/detail/logbuffer.hpp index 32ad836..4b9dc34 100644 --- a/fastlog/detail/logbuffer.hpp +++ b/fastlog/detail/logbuffer.hpp @@ -10,9 +10,12 @@ template class FileLogBuffer { FileLogBuffer() noexcept : __cur{__data.begin()} {} void write(const std::string &str) noexcept { - assert(writeable() > str.size()); + const auto str_size = str.size(); + if (writeable() < str_size) { + return; + } std::copy(str.begin(), str.end(), __cur); - __cur += str.size(); + __cur += str_size; }; [[nodiscard]] diff --git a/fastlog/detail/logfstream.hpp b/fastlog/detail/logfstream.hpp index 75b1362..eed468d 100644 --- a/fastlog/detail/logfstream.hpp +++ b/fastlog/detail/logfstream.hpp @@ -4,8 +4,8 @@ #include #include #include -#include #include +#include namespace fastlog::detail { class logfstream { public: @@ -53,10 +53,11 @@ class logfstream { private: // 创建新文件 void create() { - auto time_str = util::get_current_time_tostring(); + auto time_str = util::get_current_time_to_string(); if (time_str.has_value()) { - std::filesystem::path log_path = - std::format("{}-{}", __file_path.string(), time_str.value()); + std::ostringstream oss; + oss << __file_path.string() << "-" << time_str.value(); + std::filesystem::path log_path = oss.str(); __file_size = 0; if (__file_stream.is_open()) { __file_stream.close(); diff --git a/fastlog/detail/logger.hpp b/fastlog/detail/logger.hpp index ba0205a..91c9a96 100644 --- a/fastlog/detail/logger.hpp +++ b/fastlog/detail/logger.hpp @@ -9,12 +9,10 @@ #include #include #include -#include #include #include #include #include -#include #include #include #include @@ -25,6 +23,35 @@ namespace fastlog::detail { +template +inline auto format_arg(std::ostringstream &oss, const T &arg) -> void { + oss << arg; +} + +template +inline auto format_arg(std::ostringstream &oss, const std::vector &vec) -> void { + oss << "["; + for (size_t i = 0; i < vec.size(); ++i) { + if (i > 0) oss << ", "; + oss << vec[i]; + } + oss << "]"; +} + +template +inline auto format_string(const std::string &fmt, Args &&...args) -> std::string { + std::ostringstream oss; + (format_arg(oss, args), ...); + return oss.str(); +} + +template +inline auto format_string(const char *fmt, Args &&...args) -> std::string { + std::ostringstream oss; + (format_arg(oss, args), ...); + return oss.str(); +} + // 日志细节模式: // Compact 适合终端阅读,Full 适合文件落盘与问题定位 enum class LogDetailMode { Compact, Full }; @@ -51,10 +78,10 @@ struct logrecord_t { template struct basic_format_string_wrapper { template requires std::convertible_to - consteval basic_format_string_wrapper( + constexpr basic_format_string_wrapper( const T &s, std::source_location loc = std::source_location::current()) : fmt(s), loc(loc) {} - std::format_string fmt; + std::string fmt; std::source_location loc; }; @@ -101,7 +128,7 @@ inline auto format_exception_block(std::string_view summary, std::string stacktrace) -> std::string { stacktrace = trim_trailing_newlines(std::move(stacktrace)); if (stacktrace.empty()) { - return std::format("Exception:\n{}", indent_multiline(summary)); + return format_string("Exception:\n{}", indent_multiline(summary)); } auto title_pos = stacktrace.find('\n'); @@ -113,11 +140,11 @@ inline auto format_exception_block(std::string_view summary, } if (body.empty()) { - return std::format("Exception:\n{}\n{}\n{}", + return format_string("Exception:\n{}\n{}\n{}", indent_multiline(summary), title, " "); } - return std::format("Exception:\n{}\n{}\n{}", indent_multiline(summary), title, + return format_string("Exception:\n{}\n{}\n{}", indent_multiline(summary), title, indent_multiline(body)); } @@ -129,7 +156,7 @@ inline auto align_multiline_message(std::string_view prefix, std::string_view message) -> std::string { const auto newline_pos = message.find('\n'); if (newline_pos == std::string_view::npos) { - return std::format("{}{}", prefix, message); + return format_string("{}{}", prefix, message); } std::string result; @@ -165,28 +192,25 @@ inline auto format_log_message(const logrecord_t &record, const auto effective_mode = record.force_full_detail ? LogDetailMode::Full : detail_mode; if (effective_mode == LogDetailMode::Full) { - const auto plain_prefix = - std::format("{} [{}] [tid:{}] [{}:{}] ", record.datetime, - level_wrapper.to_string(), record.thread_id, record.file_name, - record.line); + std::ostringstream oss1; + oss1 << record.datetime << " [" << level_wrapper.to_string() << "] [tid:" << record.thread_id << "] [" << record.file_name << ":" << record.line << "] "; + const auto plain_prefix = oss1.str(); if (enable_color) { - const auto color_prefix = std::format( - "{} [{}{}{}] [tid:{}] [{}:{}] {}", record.datetime, - level_wrapper.to_color(), level_wrapper.to_string(), reset_format(), - record.thread_id, record.file_name, record.line, ""); + std::ostringstream oss2; + oss2 << record.datetime << " [" << level_wrapper.to_color() << level_wrapper.to_string() << reset_format() << "] [tid:" << record.thread_id << "] [" << record.file_name << ":" << record.line << "] "; + const auto color_prefix = oss2.str(); return align_multiline_message(color_prefix, plain_prefix, record.log); } return align_multiline_message(plain_prefix, plain_prefix, record.log); } - const auto plain_prefix = - std::format("{} [{}] [tid:{}] ", record.datetime, level_wrapper.to_string(), - record.thread_id); + std::ostringstream oss3; + oss3 << record.datetime << " [" << level_wrapper.to_string() << "] [tid:" << record.thread_id << "] "; + const auto plain_prefix = oss3.str(); if (enable_color) { - const auto color_prefix = - std::format("{} [{}{}{}] [tid:{}] {}", record.datetime, - level_wrapper.to_color(), level_wrapper.to_string(), - reset_format(), record.thread_id, ""); + std::ostringstream oss4; + oss4 << record.datetime << " [" << level_wrapper.to_color() << level_wrapper.to_string() << reset_format() << "] [tid:" << record.thread_id << "] "; + const auto color_prefix = oss4.str(); return align_multiline_message(color_prefix, plain_prefix, record.log); } return align_multiline_message(plain_prefix, plain_prefix, record.log); @@ -197,7 +221,7 @@ inline auto format_log_message(const logrecord_t &record, // 1. 级别过滤 // 2. source_location 捕获 // 3. 异常与堆栈格式化 -template class BaseLogger : util::noncopyable { +template class BaseLogger : util::noncopyable { public: void set_level(LogLevel level) { __level = level; } [[nodiscard]] @@ -267,8 +291,7 @@ template class BaseLogger : util::noncopyable { exception(ex, loc); } catch (...) { log_preformatted( - std::format("Exception:\n {}\nStacktrace\n ", - prefix), + format_string("Exception:\n {}\nStacktrace\n ", prefix), loc); } } @@ -282,18 +305,22 @@ template class BaseLogger : util::noncopyable { return; } std::string time_str; - auto res = util::get_current_time_tostring(); + auto res = util::get_current_time_to_string(); if (res.has_value()) { time_str = res.value(); } // 调用派生类的log方法记录日志 - static_cast(this)->template log(logrecord_t{ + std::ostringstream oss; + (format_arg(oss, args), ...); + std::string log_content = oss.str(); + + static_cast(this)->template log(logrecord_t{ .datetime = time_str.c_str(), .thread_id = util::get_current_thread_id(), .file_name = fmt_w.loc.file_name(), .line = fmt_w.loc.line(), .force_full_detail = false, - .log = std::format(fmt_w.fmt, std::forward(args)...)}); + .log = log_content}); } // 预格式化日志路径: @@ -304,11 +331,11 @@ template class BaseLogger : util::noncopyable { return; } std::string time_str; - auto res = util::get_current_time_tostring(); + auto res = util::get_current_time_to_string(); if (res.has_value()) { time_str = res.value(); } - static_cast(this)->template log(logrecord_t{ + static_cast(this)->template log(logrecord_t{ .datetime = time_str.c_str(), .thread_id = util::get_current_thread_id(), .file_name = loc.file_name(), @@ -339,7 +366,7 @@ template class BaseLogger : util::noncopyable { class ConsoleLogger : public BaseLogger { public: template void log(const logrecord_t &record) { - std::print("{}\n", format_log_message(record, detail_mode(), true)); + std::cout << format_log_message(record, detail_mode(), true) << "\n"; } }; @@ -491,8 +518,9 @@ class FileLogger : public BaseLogger { // 如果缓冲区链表的缓冲区数量过多,只剩2个,其余丢弃掉 if (__full_buffers.size() > max_buffer_list_size) { - std::cerr << std::format("Dropped log messages {} larger buffers\n", - __full_buffers.size() - 2); + std::ostringstream oss; + oss << "Dropped log messages " << (__full_buffers.size() - 2) << " larger buffers\n"; + std::cerr << oss.str(); __full_buffers.resize(2); } // 消费满缓冲区列表中的缓冲区,将数据写入文件缓冲区 diff --git a/fastlog/detail/loglevel.hpp b/fastlog/detail/loglevel.hpp index 973da27..64d720c 100644 --- a/fastlog/detail/loglevel.hpp +++ b/fastlog/detail/loglevel.hpp @@ -27,7 +27,6 @@ class LogLevelWrapper { case LogLevel::Fatal: return "FATAL"; default: - std::unreachable(); return "unknown log level"; } } @@ -47,7 +46,6 @@ class LogLevelWrapper { case LogLevel::Fatal: return "\033[45m"; // purple default: - std::unreachable(); return "NOT DEFINE COLOR"; } } diff --git a/vcpkg.json b/vcpkg.json index 8530d1c..4586ee9 100644 --- a/vcpkg.json +++ b/vcpkg.json @@ -1,5 +1,9 @@ { "dependencies": [ - "cpptrace" - ] + { + "name": "cpptrace", + "platform": "windows" + } + ], + "builtin-baseline": "b472291f295551b7127359ea38fdd2ca092f6f1b" } \ No newline at end of file