在 Qt / C++ / QML 开发嵌入式项目 这个场景下,日志选型非常关键 。经过摸索结合目前项目 嵌入式 + 车载 + Qt Quick 的实际背景,入选的有spdlog和easylogger。针对实际项目对他们两个结论先行 + 详细对比 + 推荐方案。
✅ 结论先行
👉 优先推荐:spdlog
👉 只有在极端资源受限 / 无 STL / 裸机风格项目时,才考虑 EasyLogger
车载仪表 Qt/QML 项目 → 选 spdlog 更合适。
一、从"汽车仪表项目"的真实需求出发
你的项目通常具备这些特征:
-
Qt + C++ + QML
-
Linux(Yocto / Buildroot / Ubuntu Core)
-
多线程(UI / CAN / 诊断 / 多媒体 / 网络)
-
日志需求:
-
启动日志
-
CAN/信号调试
-
性能分析(卡顿、帧率)
-
问题回溯(现场抓 log)
-
👉 日志系统必须:
-
线程安全
-
性能好(不能拖慢 UI)
-
支持文件滚动
-
支持等级过滤
-
最好能异步
二、EasyLogger vs spdlog 核心对比
| 维度 | EasyLogger | spdlog |
|---|---|---|
| 定位 | 嵌入式 C 日志 | 现代 C++ 高性能日志 |
| 语言风格 | C 风格 | C++11+ |
| 线程安全 | ❌(需自己保证) | ✅ |
| 异步日志 | ❌ | ✅(非常成熟) |
| 文件滚动 | 基础 | 非常完善 |
| 格式化 | 简单 | fmt(强大) |
| 社区活跃度 | ⭐⭐ | ⭐⭐⭐⭐⭐ |
| 车载项目可维护性 | 一般 | 非常好 |
| 与 Qt 结合 | 一般 | 非常好 |
三、为什么 不推荐 EasyLogger 用在车载 Qt/QML 项目
EasyLogger 的优势主要是:
-
代码小
-
C 风格
-
适合 MCU / RTOS
但在 车载 Qt 项目 中反而是劣势:
❌ 无异步日志 → IO 阻塞 UI
❌ 线程安全弱 → 多线程下容易出问题
❌ 维护和扩展成本高
❌ 调试体验差(格式化能力弱)
EasyLogger 更适合 MCU、RTOS、无 STL 的环境,而不是 Qt/QML 仪表系统。
四、为什么 spdlog 非常适合汽车仪表
1️⃣ 性能和实时性优秀(关键)
cpp
auto logger = spdlog::create_async<spdlog::sinks::rotating_file_sink_mt>(
"car",
"/data/logs/car.log",
5 * 1024 * 1024,
5
);
-
异步日志
-
后台线程写文件
-
UI / 渲染线程几乎无感知
👉 不会影响 QML 帧率
2️⃣ 多线程安全(车载必备)
cpp
spdlog::info("speed={}, rpm={}", speed, rpm);
CAN 线程、UI 线程、诊断线程都能安全打日志。
3️⃣ 非常适合"分模块日志"
cpp
auto canLog = spdlog::get("can");
auto uiLog = spdlog::get("ui");
canLog->info("CAN msg id={}", id);
uiLog->warn("FPS drop");
👉 非常适合仪表架构
4️⃣ 日志等级可运行时控制(车厂很爱)
cpp
spdlog::set_level(spdlog::level::warn);
-
量产只保留 warn / error
-
调试版本打开 debug
五、Qt 项目中 spdlog 的推荐用法(实战)
1️⃣ 封装一层 Qt 风格日志宏(强烈推荐)
cpp
// log.h
#include <spdlog/spdlog.h>
#define LOGI(...) spdlog::info(__VA_ARGS__)
#define LOGW(...) spdlog::warn(__VA_ARGS__)
#define LOGE(...) spdlog::error(__VA_ARGS__)
使用
cpp
LOGI("speed={}, gear={}", speed, gear);
2️⃣ 和 Qt 消息系统打通(高级)
cpp
void qtMessageHandler(QtMsgType type,
const QMessageLogContext &ctx,
const QString &msg)
{
auto m = msg.toStdString();
switch (type) {
case QtDebugMsg: spdlog::debug(m); break;
case QtWarningMsg: spdlog::warn(m); break;
case QtCriticalMsg: spdlog::error(m); break;
case QtFatalMsg: spdlog::critical(m); break;
}
}
int main() {
qInstallMessageHandler(qtMessageHandler);
}
👉 QML 的 console.log() 也会进 spdlog
六、什么时候才选 EasyLogger?
仅在以下情况才考虑:
-
MCU / RTOS
-
无 STL
-
内存极小(几十 KB)
-
非 Qt 项目
不适合你的"Qt/QML 汽车仪表"场景。
七、最终推荐架构(车载仪表最佳实践)
bash
QML / UI
↓
Qt Message Handler
↓
spdlog(异步)
↓
文件 / 串口 / 网络
八、最终建议
Qt / C++ / QML 的汽车仪表项目,请直接选 spdlog。
稳定、性能好、可维护性高、车厂也认可。