使用spdlog打印std::to_string生成的矩阵时如何添加行首偏移和前缀
实现方案
以下是完全基于现有spdlog工具栈的轻量实现,不需要引入额外依赖,可根据场景灵活选择:
方案1:多行内容预处理函数(最轻量,无侵入)
先封装通用的字符串处理工具,对转换后的矩阵/向量多行字符串做格式化处理,调用时直接传入处理后的结果即可,不需要修改原有日志配置。
#include <string> #include <sstream> /** * @param raw_str 原始多行字符串 * @param indent 后续行缩进长度,填日志前缀的总字符数即可对齐首行 * @param line_prefix 可选行前缀字符,传'\0'则不添加 * @return 格式化后的多行字符串 */ std::string format_multiline_log(const std::string& raw_str, int indent = 0, char line_prefix = '\0') { std::istringstream iss(raw_str); std::ostringstream oss; std::string line; bool first_line = true; std::string indent_str(indent, ' '); while (std::getline(iss, line)) { if (!first_line) { oss << '\n' << indent_str; } if (line_prefix != '\0') { oss << line_prefix << ' '; } oss << line; first_line = false; } return oss.str(); }
调用示例:
// 假设你的日志前缀总长度为22(日期+级别等字段总字符数) std::string raw_matrix = your_matrix_to_string_func(); spdlog::info("Matrix output:\n{}", format_multiline_log(raw_matrix, 22, '|'));
方案2:自定义spdlog formatter(全局生效,无需每次手动处理)
如果需要所有多行日志都自动对齐,可自定义spdlog格式化器,全局生效不需要修改业务打印代码:
#include "spdlog/spdlog.h" #include "spdlog/formatter.h" class aligned_multiline_formatter : public spdlog::formatter { public: aligned_multiline_formatter(int prefix_len, char line_prefix = '\0') : prefix_len_(prefix_len), line_prefix_(line_prefix) {} void format(const spdlog::details::log_msg& msg, spdlog::memory_buf_t& dest) override { // 按原有日志pattern格式化前缀,此处替换为你自己的前缀格式化逻辑即可 std::string prefix = get_origin_log_prefix(msg); std::string content(msg.payload.data(), msg.payload.size()); std::istringstream iss(content); std::ostringstream oss; std::string line; bool first_line = true; std::string indent(prefix_len_, ' '); while (std::getline(iss, line)) { if (!first_line) { oss << '\n' << indent; } if (line_prefix_ != '\0') { oss << line_prefix_ << ' '; } oss << line; first_line = false; } std::string final_log = prefix + oss.str() + '\n'; dest.append(final_log.data(), final_log.data() + final_log.size()); } std::unique_ptr<formatter> clone() const override { return std::make_unique<aligned_multiline_formatter>(prefix_len_, line_prefix_); } private: int prefix_len_; char line_prefix_; std::string get_origin_log_prefix(const spdlog::details::log_msg& msg) { // 示例:如果原有pattern是"[%Y-%m-%d %H:%M:%S] [%l] ",此处返回对应格式化后的前缀即可 return "[2024-05-20 14:30:00] [info] "; } }; // 注册到logger即可全局生效 auto logger = spdlog::stdout_color_mt("console"); logger->set_formatter(std::make_unique<aligned_multiline_formatter>(22, '|'));
方案3:配合矩阵库自带格式化能力
如果项目中使用Eigen等线性代数库,可直接用库自带的IO配置实现自定义前缀,再配合方案1的缩进逻辑即可:
#include <Eigen/Dense> Eigen::Matrix3f mat; mat << 1,2,3,4,5,6,7,8,9; // 配置每行开头加| 前缀 Eigen::IOFormat mat_fmt(4, 0, ", ", "\n", "| ", "| "); std::string raw_mat_str = [&](){ std::ostringstream oss; oss << mat.format(mat_fmt); return oss.str(); }(); spdlog::info("Matrix:\n{}", format_multiline_log(raw_mat_str, 22));
注意事项
- 如果日志前缀是动态长度(比如不同级别名称长度不同),可以在格式化函数中动态计算当前日志前缀的实际长度,再对应补缩进
- 仅需要矩阵/向量类特殊格式化的场景优先选方案1,侵入性最低,和现有代码完全兼容
- 行前缀可根据日志级别设置不同字符,比如debug用
>,error用!,进一步提升可读性
内容的提问来源于stack exchange,提问作者Alejandro
相关产品推荐
相关产品推荐

