我正在研究QT应用程序的记录器框架。QMessageLogger由于理解和学习目的,我没有直接使用。QMessageLogger我真的很想在记录器中拥有一种功能,但是我不知道它是如何工作的。让我们以qDebug宏为例:
#define qDebug QMessageLogger(QT_MESSAGELOG_FILE, QT_MESSAGELOG_LINE, QT_MESSAGELOG_FUNC).debug
Run Code Online (Sandbox Code Playgroud)
一个人可以通过两种方式调用此函数:第一种方式:
qDebug("abc = %u", abc);
Run Code Online (Sandbox Code Playgroud)
第二种方式:
qDebug() << "abc = " << abc;
Run Code Online (Sandbox Code Playgroud)
我正在查看库代码,但是我不太了解如何实现QMessageLogger通过使用va_args以及某些流对象来实现的功能。我怎样才能达到这样的效果?我真的很感谢所有帮助,不胜感激。
这是我的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);
}
Run Code Online (Sandbox Code Playgroud)
首先,您需要了解以下内容
QMessageLogger(QT_MESSAGELOG_FILE, QT_MESSAGELOG_LINE, QT_MESSAGELOG_FUNC).debug
Run Code Online (Sandbox Code Playgroud)
上面的代码行构造了一个QMessageLogger实例,并立即访问其调试成员。由于它是一个宏,因此紧随其后编写代码也很重要。
如果您看一下是什么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;
Run Code Online (Sandbox Code Playgroud)
现在,问题应该很简单。如果调用qDebug("abc = %u", abc),则调用第一个重载,扩展的宏如下所示:
QMessageLogger(QT_MESSAGELOG_FILE, QT_MESSAGELOG_LINE, QT_MESSAGELOG_FUNC).debug("abc = %u", abc)
Run Code Online (Sandbox Code Playgroud)
或多或少等于
QMessageLogger temp(QT_MESSAGELOG_FILE, QT_MESSAGELOG_LINE, QT_MESSAGELOG_FUNC);
temp.debug("abc = %u", abc);
Run Code Online (Sandbox Code Playgroud)
在第二种情况下,您要调用返回一个QDebug对象的重载。QDebug已超载operator<<。展开的宏如下:
QMessageLogger(QT_MESSAGELOG_FILE, QT_MESSAGELOG_LINE, QT_MESSAGELOG_FUNC).debug() << "abc = " << abc;
Run Code Online (Sandbox Code Playgroud)
或多或少等于
QMessageLogger temp(QT_MESSAGELOG_FILE, QT_MESSAGELOG_LINE, QT_MESSAGELOG_FUNC);
QDebug anotherTemp = temp.debug();
anotherTemp << "abc = " << abc;
Run Code Online (Sandbox Code Playgroud)
这是这种记录器的简单实现:
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{};
}
};
Run Code Online (Sandbox Code Playgroud)
几点注意事项:
free所返回的缓冲区vasprintf。free不能与delete或互换delete[]std::stringstream,但是将其更改为QTextStream或任何其他更改应该足够简单log << "foo" << "bar"语法而不是语法,则无需将helper作为单独的类实现log() << "foo" << "bar"