故障排除¶
本文档列出 CFLogger 使用中的常见问题和解决方案。
常见问题¶
Q1: 日志没有输出¶
可能原因和解决方法¶
原因 1:没有调用 flush()
// ❌ 程序结束太快,工作线程还没处理
int main() {
info("Hello");
return 0; // 日志可能未写入
}
// ✅ 确保刷新
int main() {
info("Hello");
flush(); // 或 Logger::instance().flush_sync()
return 0;
}
原因 2:日志级别设置过高
// ❌ 日志被过滤
set_level(level::WARNING);
info("这条不会显示"); // INFO < WARNING
// ✅ 调整级别
set_level(level::INFO);
info("这条会显示");
原因 3:没有添加 Sink
// ❌ 没有输出目标
Logger::instance().log(level::INFO, "Hello", "Tag", {});
// ✅ 添加 Sink
auto sink = std::make_shared<ConsoleSink>();
Logger::instance().add_sink(sink);
Logger::instance().log(level::INFO, "Hello", "Tag", {});
Q2: 程序崩溃后日志丢失¶
原因¶
CFLogger 使用异步队列,崩溃可能导致未写入的日志丢失。
解决方法¶
// 在关键操作前同步刷新
void critical_operation() {
Logger::instance().flush_sync(); // 确保之前的日志已写入
perform_critical_task();
Logger::instance().flush_sync(); // 确保操作日志已写入
}
// 程序退出前
int main() {
// ... 应用逻辑 ...
Logger::instance().flush_sync(); // 确保所有日志写入
return 0;
}
Q3: 队列溢出导致日志丢失¶
检查方法¶
size_t overflow = Logger::instance().get_normal_queue_overflow();
if (overflow > 0) {
warning("队列溢出,丢失 " + std::to_string(overflow) + " 条日志");
}
解决方法¶
方法 1:降低日志量
// 提高日志级别
Logger::instance().setMininumLevel(level::WARNING);
// 减少详细日志
// trace() → debug() → info()
方法 2:批量日志
// ❌ 逐条记录
for (int i = 0; i < 10000; ++i) {
trace("项目: " + std::to_string(i));
}
// ✅ 批量记录
trace("开始处理 10000 个项目");
for (int i = 0; i < 10000; ++i) {
// 处理...
}
trace("完成处理 10000 个项目");
方法 3:异步处理加速
确保 Sink 写入高效:
Q4: 颜色显示异常¶
问题¶
在文件中看到 ANSI 转义码:
原因¶
在文件 Sink 中使用了带 COLOR 的 Formatter。
解决方法¶
// ❌ 文件中使用颜色
auto file_formatter = std::make_shared<AsciiColorFormatter>(
FormatterFlag::DEFAULT | FormatterFlag::COLOR
);
// ✅ 方法 1:使用 FileFormatter
auto file_formatter = std::make_shared<FileFormatter>(
FormatterFlag::DEFAULT
);
// ✅ 方法 2:禁用颜色
auto config = std::make_shared<FormatterConfig>(FormatterFlag::DEFAULT);
config->disable(FormatterFlag::COLOR);
formatter->set_config(config);
Q5: 编译错误¶
问题:找不到头文件¶
解决方法¶
# 确保 CMakeLists.txt 正确配置
find_package(CFDesktop REQUIRED)
add_executable(my_app main.cpp)
target_link_libraries(my_app PRIVATE CFDesktop::logger)
# 或者添加 include 路径
target_include_directories(my_app PRIVATE
${CMAKE_SOURCE_DIR}/desktop/base/logger/include
)
问题:链接错误¶
解决方法¶
# 确保链接了 logger 库
target_link_libraries(my_app PRIVATE CFDesktop::logger)
# 检查 logger 库是否被构建
# 确保 CMake 选项 CFDESKTOP_BUILD_LOGGER 为 ON
Q6: 多线程日志混乱¶
问题¶
日志输出交错或格式异常。
原因¶
CFLogger 是线程安全的,但如果使用非线程安全的自定义 Sink 可能出现问题。
解决方法¶
// ✅ 确保自定义 Sink 线程安全
class ThreadSafeSink : public ISink {
public:
bool write(const LogRecord& record) override {
std::lock_guard<std::mutex> lock(mutex_); // 加锁
// 写入操作...
return true;
}
private:
std::mutex mutex_;
};
Q7: 性能问题¶
问题¶
日志导致应用变慢。
诊断方法¶
// 记录性能指标
class PerformanceTracker {
public:
void log_start() {
start_ = std::chrono::steady_clock::now();
}
void log_end() {
auto end = std::chrono::steady_clock::now();
auto duration = std::chrono::duration_cast<std::chrono::microseconds>(
end - start_
).count();
if (duration > 1000) { // 超过 1ms
warning("日志操作耗时: " + std::to_string(duration) + " μs");
}
}
private:
std::chrono::steady_clock::time_point start_;
};
解决方法¶
- 提高日志级别
- 减少日志量
- 简化格式
- 使用更快的 Sink
参考 性能优化 获取更多建议。
Q8: 内存泄漏¶
问题¶
长时间运行后内存持续增长。
可能原因¶
原因 1:队列堆积
// 检查队列状态
size_t overflow = Logger::instance().get_normal_queue_overflow();
if (overflow > 0) {
// 日志产生速度 > 消费速度
}
原因 2:自定义 Sink 泄漏
// ❌ 错误的自定义 Sink
class LeakySink : public ISink {
public:
bool write(const LogRecord& record) override {
messages_.push_back(record.msg); // 无限增长
return true;
}
private:
std::vector<std::string> messages_; // 从不清理
};
解决方法
// ✅ 正确的做法
class BoundedSink : public ISink {
public:
bool write(const LogRecord& record) override {
std::lock_guard<std::mutex> lock(mutex_);
messages_.push_back(record.msg);
if (messages_.size() > max_size_) {
messages_.erase(messages_.begin());
}
return true;
}
private:
std::vector<std::string> messages_;
size_t max_size_ = 1000;
std::mutex mutex_;
};
Q9: 文件打开失败¶
问题¶
FileSink 无法创建或写入文件。
原因¶
- 目录不存在
- 权限不足
- 磁盘空间不足
解决方法¶
// ✅ 检查并创建目录
#include <filesystem>
void ensure_log_directory(const std::string& log_path) {
std::filesystem::path path(log_path);
std::filesystem::path dir = path.parent_path();
if (!dir.empty() && !std::filesystem::exists(dir)) {
std::filesystem::create_directories(dir);
}
}
// 使用
ensure_log_directory("/var/log/myapp/app.log");
auto sink = std::make_shared<FileSink>("/var/log/myapp/app.log");
Q10: 时间戳不正确¶
问题¶
日志时间与实际时间不符。
原因¶
系统时区或时间设置问题。
解决方法¶
// 自定义时间格式包含时区
auto config = std::make_shared<FormatterConfig>();
config->set_timestamp_format("%Y-%m-%d %H:%M:%S %z"); // 添加时区
formatter->set_config(config);
调试技巧¶
启用详细日志¶
// 临时启用所有日志
Logger::instance().setMininumLevel(level::TRACE);
// 添加详细格式
auto formatter = std::make_shared<AsciiColorFormatter>(
FormatterFlag::VERBOSE | FormatterFlag::COLOR
);
监控队列状态¶
class QueueMonitor {
public:
void start() {
running_ = true;
thread_ = std::thread([this]() {
while (running_) {
size_t overflow = Logger::instance().get_normal_queue_overflow();
if (overflow > last_overflow_) {
std::cout << "[监控] 队列溢出: "
<< (overflow - last_overflow_) << " 条" << std::endl;
last_overflow_ = overflow;
}
std::this_thread::sleep_for(std::chrono::seconds(1));
}
});
}
void stop() {
running_ = false;
if (thread_.joinable()) {
thread_.join();
}
}
private:
bool running_ = false;
std::thread thread_;
size_t last_overflow_ = 0;
};
捕获异常¶
// 在自定义 Sink 中捕获异常
class SafeSink : public ISink {
public:
bool write(const LogRecord& record) override {
try {
// 写入逻辑
return true;
} catch (const std::exception& e) {
// 输出到 stderr 避免递归
std::cerr << "Sink 错误: " << e.what() << std::endl;
return false;
}
}
};
获取帮助¶
如果以上方法无法解决问题:
- 参考 API 文档
- 搜索或提交 Issue 到项目仓库
常用调试命令¶
# 检查日志文件
tail -f app.log
# 查看错误日志
grep ERROR app.log
# 统计各级别日志数量
grep TRACE app.log | wc -l
grep DEBUG app.log | wc -l
grep INFO app.log | wc -l
grep WARNING app.log | wc -l
grep ERROR app.log | wc -l
# 查看特定标签
grep "\[Network\]" app.log
# 实时过滤
tail -f app.log | grep ERROR