Detailed explanation of qDebug usage

Posted by bleh on Wed, 22 Dec 2021 00:40:07 +0100

1. Usage

Stream mode output

Instead of std::out, you need to add endl at the end, which is more convenient to use. It supports direct output of common types. It also supports QT built-in data type output, such as QMap, QList, QVaraint, etc. QT is a powerful debugging tool

QString strText = "hello";
bool bOk = true;
qDebug()<< strText << bOk;

Occupancy mode output

The usage is exactly the same as printf, because the internal implementation is printf

qDebug("%s","hello");

Qt5 source code

#define Q_ATTRIBUTE_FORMAT_PRINTF(A, B) \
         __attribute__((format(printf, (A), (B))))
         
void debug(const char *msg, ...) const Q_ATTRIBUTE_FORMAT_PRINTF(2, 3);

2. Let qDebug support the output of custom structures

Custom structures are very common in projects, but printing custom structures is cumbersome. Each time you use them, you need to print them one by one, which is cumbersome to output.

Common implementation

struct StInfo{
    int id;
    QString dev_id;
};

Common usage

StInfo stInfo;
qDebug()<< stInfo.id << stInfo.dev_id;

Another simple way is to implement a toString() method, and call toString() when you need to output the structure.

Upgrade implementation

struct StInfo{
    int id;
    QString dev_id;
    QString toString()
    {
        return QString("StInfo(%1 %2)").arg(id).arg(dev_id);    
    }
};

Upgrade usage

StInfo stInfo;
qDebug()<< stInfo.toString();

However, we can overload qDebug through friend functions to support custom type output. In addition, you can add marks at will before, after or in the middle of the structure, such as structure prefix and member variable mark, so as to more clearly see which structure this is.

Ultimate realization

struct StInfo{
    int id;
    QString dev_id;

    friend inline QDebug operator<<(QDebug out, const StInfo& info)
    {
        out <<" StInfo("<<info.id<<info.dev_id<<") ";
        return out;
    }
};

Ultimate usage

StInfo info;
qDebug()<< info;

3. Redirect the output of qDebug

qDebug is very comfortable. At this time, you need to output debug information to a file, which can be done in the following ways
//Declare a global callback function
void outputMsg(QtMsgType type, const QMessageLogContext &context, const QString &msg)
{
    ...
    //Open the file and organize string writing
    ...
}

int main()
{
    ...
    //Install callback function
    qInstallMessageHandler(outputMsg);
    ...
}

For the convenience of debugging, we can also output logs to windows, files, socket s, console, etc. The implementation method can be customized.

be careful

1. The implementation in the callback function cannot use qDebug, otherwise dead recursion will be caused. If printing debugging is required, printf and std::out can be used.

2. Pay attention to locking to support multithreading qDebug();

Call qInstallMessageHandler and pass in the callback function pointer. The final output of qDebug will be sent to the callback function. QMessageLogContext contains file name, function name, line number and other information. msg is the output information. The number of times can be written to the file.

Declaration in Qt5 source code

class QMessageLogContext
{
    ...
    int version;
    int line;
    const char *file;
    const char *function;
    const char *category;
    ...
};

4. Specify the output format of qDebug

A simple use example

int main()
{
    //Set the output format of qDebug
    qSetMessagePattern("[%{type}] %{time yyyy-MM-dd hh:mm:ss.zzz}  %{function}:%{line} %{message}");

    qDebug()<<"hello";
}

console output

[warning] 2021-08-19 10:10:59.886  main:32 hello

Output supported formats

Support fieldsdescribe
%{appname}QCoreApplication::applicationName()
%{category}Log category
%{file}Source file path
%{function}Function name
%{line}Line number in source file
%{message}Actual information
%{pid}QCoreApplication::applicationPid()
%{threadid}Thread Id
%{qthreadptr}Current thread pointer
%{type}"debug", "warning", "critical" or "fatal"
%{time process}Time since the process started
%{time boot}Time since the software was run
%{time [format]}Current time. Supports custom timestamp format
%{backtrace [depth=N] [separator="..."]}Stack information in case of program exception

The default output format is
"%{if-category}%{category}: %{endif}%{message}"

There are two ways to set the output format: environment variable and function call. When used at the same time, environment variable takes precedence.
When specifying the format, you can also use type condition judgment. The judgment condition is included in% {}.% {endif} indicates the logical end of the judgment. You can specify the output marks of different types of messages through this function, and control different types to output different colors on the console.

 QT_MESSAGE_PATTERN="[%{time yyyyMMdd h:mm:ss.zzz t}
 %{if-debug}D%{endif}%{if-info}I%{endif}%{if-warning}W
 %{endif}%{if-critical}C%{endif}%{if-fatal}F%{endif}] %{file}:%{line} - %{message}"

Console color output code example

Different types of logs are prefixed with different color codes, and after the log is output, the color needs to be restored to the original state (\ 033[0m), otherwise the output of the subsequent third-party library calling printf will always maintain this color, resulting in disordered color display.

//CLogEvent is a structure defined by the author, including log type (debug info...), function name, line number and other information, focusing on the output implementation of different types of colors
void CConsoleAppender::append(CLogEvent &event)
{
    if(event.level < m_enmLevel)
        return ;

    static QString arrColor[] = {"","\033[32m","\033[33m","\033[31m","\033[35m"};// Default green yellow red purple

    fprintf(stdout,"%s %s\n\033[0m",arrColor[event.level].toStdString().c_str(),m_fmtter.fmt(event).toLocal8Bit().constData());
    fflush(stdout);
}

5. Relevant configuration in pro file

#The release mode does not display the function name, line number and other information by default. Add the following to display it
DEFINES += QT_MESSAGELOGCONTEXT

#The log format can be configured through the environment variable
QT_MESSAGE_PATTERN="[%{time yyyyMMdd h:mm:ss.zzz t}
  %{if-debug}D%{endif}%{if-info}I%{endif}%{if-warning}W
  %{endif}%{if-critical}C%{endif}%{if-fatal}F%{endif}] %{file}:%{line} - %{message}"

Topics: Qt