QMessageLogger魔法是如何工作的?
How does QMessageLogger magic work?
我正在为QT应用程序开发一个日志记录器框架。出于理解和学习的目的,我没有直接使用QMessageLogger
。有一件事关于一个QMessageLogger
功能,我真的很想在我的记录器,但我不知道它是如何工作的。以qDebug
宏为例:
#define qDebug QMessageLogger(QT_MESSAGELOG_FILE, QT_MESSAGELOG_LINE, QT_MESSAGELOG_FUNC).debug
可以用两种方式调用这个函数:方法1:
qDebug("abc = %u", abc);
方式2:
qDebug() << "abc = " << abc;
我正在看库代码,但我不能完全理解它是如何实现的,一个可以使用va_args
以及一些流对象与QMessageLogger
工作。我怎样才能达到这样的效果呢?我真的很感激所有的帮助,如果有一个例子我会很感激。
这是我的print
方法体。我需要用"流"的方式实现类似的功能:
/*!
* brief Adds the log line to the print queue.
* param lvl: Log level of the line.
* param text: Formatted input for va_list.
*/
void CBcLogger::print(MLL::ELogLevel lvl, const char* text, ...)
{
// check if logger initialized
if (!m_loggerStarted)
return;
// check if log level sufficient
if (lvl > m_setLogLvl)
return;
logLine_t logline;
logline.loglvl = lvl;
logline.datetime = QDateTime::currentDateTime();
va_list argptr;
va_start(argptr, text);
char* output = NULL;
if (vasprintf(&output, text, argptr))
{
logline.logstr = output;
delete output;
}
va_end(argptr);
emit addNewLogLine(logline);
}
首先,您需要理解以下内容
QMessageLogger(QT_MESSAGELOG_FILE, QT_MESSAGELOG_LINE, QT_MESSAGELOG_FUNC).debug
上面的行构造了一个QMessageLogger
实例并立即访问它的debug成员。因为它是一个宏,你在它后面写的代码也很重要。
如果您查看QMessageLogger::debug
是什么,您将看到四个重载,其中前两个与您的问题相关:
void debug(const char *msg, ...) const Q_ATTRIBUTE_FORMAT_PRINTF(2, 3);
QDebug debug() const;
QDebug debug(const QLoggingCategory &cat) const;
QDebug debug(CategoryFunction catFunc) const;
现在事情应该简单了。如果调用qDebug("abc = %u", abc)
,就调用了第一个重载,扩展后的宏如下:
QMessageLogger(QT_MESSAGELOG_FILE, QT_MESSAGELOG_LINE, QT_MESSAGELOG_FUNC).debug("abc = %u", abc)
大致等于
QMessageLogger temp(QT_MESSAGELOG_FILE, QT_MESSAGELOG_LINE, QT_MESSAGELOG_FUNC);
temp.debug("abc = %u", abc);
在第二种情况下,你调用一个重载,返回一个QDebug
对象。QDebug
已重载operator<<
。展开后的宏如下所示:
QMessageLogger(QT_MESSAGELOG_FILE, QT_MESSAGELOG_LINE, QT_MESSAGELOG_FUNC).debug() << "abc = " << abc;
大致等于
QMessageLogger temp(QT_MESSAGELOG_FILE, QT_MESSAGELOG_LINE, QT_MESSAGELOG_FUNC);
QDebug anotherTemp = temp.debug();
anotherTemp << "abc = " << abc;
下面是这样一个记录器的简单实现:
void addNewLogLine(char const* ptr){
cout << "addNewLogLine: " << ptr << endl;
}
struct LoggerHelper
{
std::stringstream s;
explicit LoggerHelper()=default;
LoggerHelper(LoggerHelper&&) = default;
~LoggerHelper(){
auto str = s.str();
addNewLogLine(str.c_str());
}
template<typename T>
LoggerHelper& operator<<(T const& val){
s << val;
return *this;
}
};
struct Logger
{
void operator()(char const* fmt, ...) const {
char* buf;
va_list args;
va_start(args, fmt);
vasprintf(&buf, fmt, args);
va_end(args);
addNewLogLine(buf);
free(buf);
}
LoggerHelper operator()() const {
return LoggerHelper{};
}
};
演示 几个笔记:
- 我坚持你的界面,但就个人而言,我会使用可变模板而不是va_args
- 你应该
free
由vasprintf
返回的缓冲区。free
与delete
或delete[]
不可互换 - 我使用
std::stringstream
,但将其更改为QTextStream
或任何其他应该足够简单 - 如果您允许
log << "foo" << "bar"
语法而不是log() << "foo" << "bar"
,则不需要将helper实现为单独的类
相关文章:
- QSqlquery prepare()和bindvalue()不工作
- 导入库可以跨dll版本工作吗
- 以螺旋方式打印矩阵的程序.(工作不好)
- 对象指针在c++中是如何工作的
- 为什么在Windows上的VS 2019和Clang 9中"size_t"在没有标题的情况下工作
- VSOMEIP-2个设备之间的通信(TCP/UDP)不工作
- 为字符串中每 N 个字符插入空格的函数没有按照我认为的方式工作?
- C++为线程工作动态地分割例程
- 为什么我的 std::ref 无法按预期工作?
- 布尔比较运算符是如何在C++中工作的
- SampleConsensusPrerejective(ext.RANSAC)是如何真正工作的
- 不确定要在我的main中放入什么才能使我的代码正常工作
- 为什么std::condition_variable notify_all的工作速度比notify_one快(对于随机请
- <<操作员在下面的行中工作
- 有人能解释一下为什么下界是这样工作的吗C++的
- ExtractIconEx:可以工作,但偶尔会崩溃
- C++中的memset函数工作不正常
- 当我在第一个循环中使用"auto"时,它工作正常,但是使用"int"它会给出错误,为什么?
- 当 int 方法工作正常时,void 方法有何不同,或者为什么我不能调用 void 方法?
- sdl软件渲染器不工作,工作在硬件加速的一个