一种简单的 spdlog 封装
记录一种简单的 spdlog 封装
TODO: 如何在.h
中隐藏 spdlog 依赖
cmake 集成
CMakeLists.txt如下:
cmake_minimum_required(VERSION 3.14)
project(test VERSION 0.0.1 LANGUAGES CXX)
# 使用 C++17 标准
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
# 添加可执行文件
add_executable(test main.cpp mylog.h mylog.cpp)
add_subdirectory(vendor/spdlog-1.15.0/)
target_link_libraries(test PRIVATE spdlog::spdlog)
输出增强
Qt 中 UI 同步更新方法
创建UILogSink
类
// UILogSink.h
#ifndef UILOGSINK_H
#define UILOGSINK_H
#include <QMetaObject>
#include <QPlainTextEdit>
#include <QTextCursor>
#include <mutex>
#include <spdlog/sinks/base_sink.h>
template<typename Mutex>
class UILogSink : public spdlog::sinks::base_sink<Mutex>
{
public:
UILogSink(QPlainTextEdit *widget)
: widget_(widget)
{}
protected:
void sink_it_(const spdlog::details::log_msg &msg) override
{
// 格式化为字符串
spdlog::memory_buf_t formatted;
this->formatter_->format(msg, formatted);
QString qtext = QString::fromStdString(fmt::to_string(formatted));
// UI 更新必须在主线程
if (widget_) {
QMetaObject::invokeMethod(
widget_,
[=]() {
widget_->appendPlainText(qtext);
widget_->moveCursor(QTextCursor::End);
},
Qt::QueuedConnection);
}
}
void flush_() override {}
private:
QPlainTextEdit *widget_;
};
using UILogSink_mt = UILogSink<std::mutex>;
#endif // UILOGSINK_H
使用
#include "formlog.h"
#include "UILogSink.h"
#include "mylog.h"
#include "ui_formlog.h"
FormLog::FormLog(QWidget *parent)
: QWidget(parent)
, ui(new Ui::FormLog)
{
ui->setupUi(this);
auto ui_sink = std::make_shared<UILogSink_mt>(ui->txtLog);
ui_sink->set_pattern("[%H:%M:%S] [%l] %v");
MY_LOG.getLogger()->sinks().push_back(ui_sink);
}
FormLog::~FormLog()
{
delete ui;
}
Qt 中输出 QString 等类型
Qt 中想直接输出 QString 类型数据,但是报错:
E:\project\train\tool\myYolo\vendor\spdlog-1.15.0\include\spdlog\fmt\bundled\base.h:1641: error: C2079: “_”使用未定义的 struct“fmt::v11::detail::type_is_unformattable_for<T,fmt::v11::context::char_type>”
参考 https://fmt.dev/9.1.0/api.html#formatting-user-defined-types
QString
template <> struct fmt::formatter<QString>: formatter<std::string> {
template <typename FormatContext>
auto format(QString s, FormatContext& ctx) const {
return formatter<std::string>::format(s.toStdString(), ctx);
}
};
QByteArray
template<>
struct fmt::formatter<QByteArray> : fmt::formatter<std::string>
{
template<typename FormatContext>
auto format(const QByteArray &s, FormatContext &ctx) const
{
return fmt::formatter<std::string>::format(s.toStdString(), ctx);
}
};
QStringList
template <>
struct fmt::formatter<QStringList> : formatter<std::string>
{
template <typename FormatContext>
auto format(QStringList s, FormatContext &ctx) const
{
return formatter<std::string>::format(s.join(',').toStdString(), ctx);
}
};
最终代码
mylog.h
#ifndef MYLOG_H
#define MYLOG_H
#include <QByteArray>
#include <QJsonDocument>
#include <QJsonObject>
#include <QString>
#include <memory>
#include "spdlog/spdlog.h"
class MyLog
{
public:
static MyLog &getInstance();
~MyLog();
void init(const std::string &file_name = "./log/myLog.log",
size_t max_size = 10 * 1024 * 1024,
size_t max_files = 10);
static std::shared_ptr<spdlog::logger> getLogger();
private:
MyLog();
static std::shared_ptr<spdlog::logger> s_logger;
};
template<>
struct fmt::formatter<QString> : formatter<std::string>
{
template<typename FormatContext>
auto format(QString s, FormatContext &ctx) const
{
return formatter<std::string>::format(s.toStdString(), ctx);
}
};
template<>
struct fmt::formatter<QByteArray> : fmt::formatter<std::string>
{
template<typename FormatContext>
auto format(const QByteArray &s, FormatContext &ctx) const
{
return fmt::formatter<std::string>::format(s.toStdString(), ctx);
}
};
template<>
struct fmt::formatter<QStringList> : formatter<std::string>
{
template<typename FormatContext>
auto format(QStringList s, FormatContext &ctx) const
{
return formatter<std::string>::format(s.join(',').toStdString(), ctx);
}
};
#define MY_LOG MyLog::getInstance()
#endif // MYLOG_H
mylog.cpp
#include "mylog.h"
#include "spdlog/sinks/rotating_file_sink.h"
#include "spdlog/sinks/stdout_color_sinks.h"
std::shared_ptr<spdlog::logger> MyLog::s_logger = nullptr;
MyLog &MyLog::getInstance()
{
static MyLog instance;
return instance;
}
MyLog::~MyLog()
{
spdlog::drop_all();
}
void MyLog::init(const std::string &file_name, size_t max_size, size_t max_files)
{
std::vector<spdlog::sink_ptr> logSinks;
logSinks.emplace_back(std::make_shared<spdlog::sinks::stdout_color_sink_mt>());
logSinks.emplace_back(
std::make_shared<spdlog::sinks::rotating_file_sink_mt>(file_name, max_size, max_files));
logSinks[0]->set_pattern("%^[%T] %n: %v%$");
logSinks[1]->set_pattern("[%T] [%l] %n: %v");
s_logger = std::make_shared<spdlog::logger>("MySerial", begin(logSinks), end(logSinks));
spdlog::register_logger(s_logger);
s_logger->set_level(spdlog::level::trace);
s_logger->flush_on(spdlog::level::trace);
}
std::shared_ptr<spdlog::logger> MyLog::getLogger()
{
return s_logger;
}
MyLog::MyLog()
{
init();
}
comment:
- Valine
- LiveRe
- ChangYan