Guidelines and HOWTOs/Debugging/Using Error Messages: Difference between revisions

From KDE Community Wiki
m (Fix syntax highlighting.)
m (Replace redirect link 2)
 
(40 intermediate revisions by 13 users not shown)
Line 1: Line 1:
{{Template:I18n/Language_Navigation_Bar|Guidelines_and_HOWTOs/Debugging/Using Error Messages}}
A screen recording version is available https://www.youtube.com/watch?v=oTAfNb9Pcj4


When you start a konsole and type the commands to start an application you
This requires at least Qt version 5.
will see all sorts of statements are printed in the konsole while the
application is running. All applications print these messages, to look
at them you have to know where to look. The application will have to be
compiled with the debugging enabled. So using a precompiled package from a distribution
probably will not give you this information. If you compiled the application
yourself, make sure the configure option <tt>--disable-debug</tt> was not used.


In KDE all debugging text-output can be switched on or off based on so
== Controlling Messages ==
called '''areas'''. One application can be one or more area. One part of the kde base libraries can be another area. Enabling/disabling these areas from being printed can be done using the '''kdebugdialog''' application. For simple debugging selecting all
sections is probably wise.


When you are debugging it is best to simply start a konsole and start the
<tt>kDebug()</tt> and friends have been deprecated in KDE Frameworks 5, and you should use Qt's built-in debugging instead.  We recommend that you use [https://doc.qt.io/qt-5/qloggingcategory.html QLoggingCategory], particularly for libraries and plugins.  Note that this is only available in Qt 5.2 and later.
application from there. In a konsole you could simply type:
 
<pre>
The source code for a library, plugin, or program named "Foo" may contain statements like
kicker
{{bc-hl|lang=cpp-qt|code=
</pre>
qCDebug(LOG_FOO) << "Log something:" << someVariable;
and in the konsole kicker could return a message like:
}}
<pre>
Here, <tt>LOG_FOO</tt> is a ''logging category''.  If debug-level messages have been enabled for that logging category, then the statement will write a message to <tt>stderr</tt>.
ERROR: kicker is already running!
 
</pre>
Some source file will define the logging category:
When a lot of output is written to the konsole it might go out of view before
{{bc-hl|lang=cpp-qt|code=
you could read it, therefor it is easy to create a text file which contains
Q_LOGGING_CATEGORY(LOG_FOO, "some.namespace.foo")
all this information, to do so type the following:
}}
<pre>
Here, <tt>"some.namespace.foo"</tt> is the ''category name''.  Once you know the category's name, you can
application 2&gt;&amp;1 | tee debug.log
set the <tt>QT_LOGGING_RULES</tt> environment variable to enable debug-level messages for the category:
</pre>
{{bc-hl|lang=bash|code=
where 'application' can be replaced with the application you are debugging.
QT_LOGGING_RULES="some.namespace.foo.debug=true"
Afterwards you could open the file 'debug.log' to look at the messages again.
}}
 
You can also enable debug-level messages for the default category (when using <tt>qDebug</tt>), by setting:
{{bc-hl|lang=bash|code=
QT_LOGGING_RULES="default.debug=true"
}}
 
Logging rules can be more complex than the examples above. They can specify wildcards in the category name, enable or disable more than one message level, and control more than one logging category.
 
To specify several categories, separate them with semicolon:
{{bc-hl|lang=bash|code=
QT_LOGGING_RULES="*.debug=false;driver.usb.debug=true"
QT_LOGGING_RULES="*.debug=true;qt.*.debug=false"
}}
 
They can also be stored in various configuration files. Please see the [https://doc.qt.io/qt-5/qloggingcategory.html#logging-rules QLoggingCategory documentation] for details.
 
If you run the application from within a terminal application, like [http://www.kde.org/applications/system/konsole/ Konsole], you will see the logging output in that terminal window.  If you use an [https://develop.kde.org/docs/getting-started/building/ide/ Integrated Development Environment] like [https://kde.org/applications/en/development/org.kde.kdevelop KDevelop] it will display the output in its windows. In Qt Creator debug messages goes to systemd journal by default. You want to see them in Application Output, so you need to specify this variable in Run Environment:
{{bc-hl|lang=bash|code=
QT_FORCE_STDERR_LOGGING=1
}}
 
Also check the [https://wiki.archlinux.org/title/Systemd/Journal systemd journal], since the application could be its direct child process. Otherwise, if you happen to still use X11, the messages will usually appear in {{path|~/.xsession-errors}} or {{path|~/.X.err}} if you use a login manager like KDM, or on the console you ran <tt>startx</tt> from if you started X that way.
 
== Adding Logging to Your Code ==
For a library or plugin called "Foo", you should have a common header that contains the following declaration  (e.g. called "foo-debug.h")
 
{{bc-hl|lang=cpp-qt|code=
#include <QLoggingCategory>
Q_DECLARE_LOGGING_CATEGORY(LOG_FOO)
}}
 
and exactly one source file containing
 
{{bc-hl|lang=cpp-qt|code=
#include "foo-debug.h"
Q_LOGGING_CATEGORY(LOG_FOO, "some.namespace.foo")
}}
 
You should treat the category name (<tt>"some.namespace.foo"</tt> in the example) as something like reverse DNS; it cannot contain spaces, and dots indicate a hierarchy.  For example, KDE PIM category names all start with <tt>"org.kde.pim."</tt>.
 
To simplify the setup, you can use the ECM macro <tt>[https://api.kde.org/ecm/module/ECMQtDeclareLoggingCategory.html ecm_qt_declare_logging_category]</tt>, which generates the respective source files for you:
 
{{bc-hl|lang=cmake|code=
include(ECMQtDeclareLoggingCategory)
ecm_qt_declare_logging_category(FOO_SRCS
    HEADER foo-debug.h
    IDENTIFIER "LOG_FOO"
    CATEGORY_NAME "some.namespace.foo"
)
}}
 
Logging lines then look like
 
{{bc-hl|lang=cpp-qt|code=
#include "foo-debug.hpp"
qCDebug(LOG_FOO) << "Log something:" << someVariable;
qCWarning(LOG_FOO) << "Something bad happened that users (end-users, or application developers using this library) should be aware of";
qCCritical(LOG_FOO) << "Something happened so bad we had to terminate the application";
}}
 
The syntax is much like <tt>cout</tt>, and most native C++ types, Qt-provided types and KF-provided types can be passed directly (like with <tt>someVariable</tt> in the example).
 
With Qt 5.2, the <tt>qCDebug</tt> line will not produce any output; this is because logging categories are disabled by default.  You need to include the line
 
{{bc-hl|lang=cpp-qt|code=
QLoggingCategory::setFilterRules(QStringLiteral("foo.debug = true"));
}}
 
somewhere in the application code, generally in the <tt>main()</tt> function.  Of course, you would typically disable this call in release versions.
 
== Customize Logging Output ==
 
Qt provides a way of controlling the output of the logging methods via an {{ic|QT_MESSAGE_PATTERN}} environment variable.  
 
You can control the message pattern depending on message type:
 
{{bc-hl|lang=bash|code=
QT_MESSAGE_PATTERN="[%{time hh:mm:ss.zzz} %{if-debug}D%{endif}%{if-info}I%{endif}%{if-warning}W%{endif}%{if-critical}C%{endif}%{if-fatal}F%{endif}] %{category} %{message}"
}}


If you are NOT starting the application from a konsole the messages will be
You can tell it to include the application name and PID, as well as the debugging category. See [https://doc.qt.io/qt-6/qtglobal.html#qSetMessagePattern qSetMessagePattern documentation] for the full list of placeholders.
logged somewhere else, or they could have been discarded by the program that
started your application.


If your application is started by clicking on an icon your best bet is to check
You even can use escape sequences to colorize the text. For example, running the following lines in your shell will produce something that looks quite like <tt>kDebug</tt>'s colored output:
the following log files. Beware; they contain logs for a lot of applications,
not just the application you are debugging!


'''Case 1: Graphical login (i.e. kdm, gdm, xdm, etc.)'''
{{bc-hl|lang=bash|code=
c=`echo -e "\033"`  # escape symbol
export QT_MESSAGE_PATTERN="%{appname}(%{pid})/(%{category}) $c\[31m%{if-debug}$c\[34m%{endif}%{function}$c\[0m: %{message}"
unset c
}}


The debug messages get redirected into the file {{path|~/.xsession-errors}} or
It is possible to create hyperlinked text with [https://github.com/Alhadis/OSC8-Adoption/ OSC-8]. For example, instead of printing the {{ic|%{file<nowiki>}</nowiki>}} (a full path to file), you may want to print a class name, which is a hyperlink to the file and line of message.
{{path|~/.X.err}} in your home directory (that is with a leading dot '.' also
watch the Capital).


'''Case 2: You are using startx:'''
If using [https://develop.kde.org/docs/getting-started/building/ide/clion/ CLion], keep in mind that colorizing the hyperlinked text is currently broken. See  [https://youtrack.jetbrains.com/issue/IDEA-218793/Provide-visual-decoration-for-terminal-HTML-like-hyperlinks IDEA-218793].


Use the following command to restart your session:
== Managing Lots of Output ==
startx 2&gt;&amp;1 | tee startx.log


so that all the debug messages of applications started at KDE's startup (and
If you have lots of debugging statements, they may appear too fast and leave the terminal window before you can read them.  There are three main ways to deal with this:
any application launched from the panel etc.) go to the file "startx.log"
# [https://doc.qt.io/qt-5/qloggingcategory.html#setFilterRules Disable some logging categories] to limit the amount of output generated
# Increase the amount of scrollback in the terminal so that output is not lost; in Konsole, you can go to Settings > Edit Current Profile... and click on the Scrollback tab to change this. Konsole also has a useful search feature: just press Ctrl+Shift+F or click Find... on the Edit menu.
# Save the output to a file. The UNIX command line <code>tee</code> is useful for this.  For example, you can run <code>application 2>&1 | tee ~/debug.log</code> or <code>application |& tee ~/debug.log</code> to save the output to the file <code>~/debug.log</code> while still viewing it in the terminal.


== Links ==
== Example ==


The debug messages are usually printed in C++ with the kDebug or kWarning statement. Example:
<pre>
<pre>
kDebug(1210) << "arbitrary message";
export QT_FORCE_STDERR_LOGGING=1
kWarning(1210) << "this rather should not happen";
export QT_MESSAGE_PATTERN="%{time yyyy.MM.dd, hh:mm:ss.zzz}, %{pid}, %{appname}, %{category}, %{type}, %{file}:%{line}, %{function} - %{message}"
export QT_LOGGING_RULES="*.debug=true;qt*.debug=false"
 
kcalc |& tee ~/a.txt
# kate ~/a.txt &
</pre>
</pre>
The number 1210 (so called ''debug area'') in this case represents kicker.  You can omit the number.


See also: [http://api.kde.org/4.0-api/kdelibs-apidocs/kdecore/html/group__kdebug.html kDebug/kWarning API documentation] and [http://websvn.kde.org/trunk/KDE/kdelibs/kdecore/kdebug.areas?view=markup kdebug.areas] for list of debug areas numbers.
You can append at the end of QT_MESSAGE_PATTERN the string ", %{backtrace}".
Note that you can use ''add_definition(-DKDE_DEFAULT_DEBUG_AREA=<number>)'' in CMakeLists.txt to specify default debug area.


''Initial Author:'' [mailto:zander@kde.org Thomas Zander]
"qt*.debug=false" is there because there are few errors in the Qt Framework source code, because there are some very verbose log lines there (e.g. "qt.qpa.events", "qt.qpa.input.events", "qt.quick.hover.trace") and because we are more interested in the KDE source code than in the Qt source code.

Latest revision as of 17:51, 18 April 2024

A screen recording version is available https://www.youtube.com/watch?v=oTAfNb9Pcj4

This requires at least Qt version 5.

Controlling Messages

kDebug() and friends have been deprecated in KDE Frameworks 5, and you should use Qt's built-in debugging instead. We recommend that you use QLoggingCategory, particularly for libraries and plugins. Note that this is only available in Qt 5.2 and later.

The source code for a library, plugin, or program named "Foo" may contain statements like

qCDebug(LOG_FOO) << "Log something:" << someVariable;

Here, LOG_FOO is a logging category. If debug-level messages have been enabled for that logging category, then the statement will write a message to stderr.

Some source file will define the logging category:

Q_LOGGING_CATEGORY(LOG_FOO, "some.namespace.foo")

Here, "some.namespace.foo" is the category name. Once you know the category's name, you can set the QT_LOGGING_RULES environment variable to enable debug-level messages for the category:

QT_LOGGING_RULES="some.namespace.foo.debug=true"

You can also enable debug-level messages for the default category (when using qDebug), by setting:

QT_LOGGING_RULES="default.debug=true"

Logging rules can be more complex than the examples above. They can specify wildcards in the category name, enable or disable more than one message level, and control more than one logging category.

To specify several categories, separate them with semicolon:

QT_LOGGING_RULES="*.debug=false;driver.usb.debug=true"
QT_LOGGING_RULES="*.debug=true;qt.*.debug=false"

They can also be stored in various configuration files. Please see the QLoggingCategory documentation for details.

If you run the application from within a terminal application, like Konsole, you will see the logging output in that terminal window. If you use an Integrated Development Environment like KDevelop it will display the output in its windows. In Qt Creator debug messages goes to systemd journal by default. You want to see them in Application Output, so you need to specify this variable in Run Environment:

QT_FORCE_STDERR_LOGGING=1

Also check the systemd journal, since the application could be its direct child process. Otherwise, if you happen to still use X11, the messages will usually appear in ~/.xsession-errors or ~/.X.err if you use a login manager like KDM, or on the console you ran startx from if you started X that way.

Adding Logging to Your Code

For a library or plugin called "Foo", you should have a common header that contains the following declaration (e.g. called "foo-debug.h")

#include <QLoggingCategory>
Q_DECLARE_LOGGING_CATEGORY(LOG_FOO)

and exactly one source file containing

#include "foo-debug.h"
Q_LOGGING_CATEGORY(LOG_FOO, "some.namespace.foo")

You should treat the category name ("some.namespace.foo" in the example) as something like reverse DNS; it cannot contain spaces, and dots indicate a hierarchy. For example, KDE PIM category names all start with "org.kde.pim.".

To simplify the setup, you can use the ECM macro ecm_qt_declare_logging_category, which generates the respective source files for you:

include(ECMQtDeclareLoggingCategory)
ecm_qt_declare_logging_category(FOO_SRCS
    HEADER foo-debug.h
    IDENTIFIER "LOG_FOO"
    CATEGORY_NAME "some.namespace.foo"
)

Logging lines then look like

#include "foo-debug.hpp"
qCDebug(LOG_FOO) << "Log something:" << someVariable;
qCWarning(LOG_FOO) << "Something bad happened that users (end-users, or application developers using this library) should be aware of";
qCCritical(LOG_FOO) << "Something happened so bad we had to terminate the application";

The syntax is much like cout, and most native C++ types, Qt-provided types and KF-provided types can be passed directly (like with someVariable in the example).

With Qt 5.2, the qCDebug line will not produce any output; this is because logging categories are disabled by default. You need to include the line

QLoggingCategory::setFilterRules(QStringLiteral("foo.debug = true"));

somewhere in the application code, generally in the main() function. Of course, you would typically disable this call in release versions.

Customize Logging Output

Qt provides a way of controlling the output of the logging methods via an QT_MESSAGE_PATTERN environment variable.

You can control the message pattern depending on message type:

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

You can tell it to include the application name and PID, as well as the debugging category. See qSetMessagePattern documentation for the full list of placeholders.

You even can use escape sequences to colorize the text. For example, running the following lines in your shell will produce something that looks quite like kDebug's colored output:

c=`echo -e "\033"`  # escape symbol
export QT_MESSAGE_PATTERN="%{appname}(%{pid})/(%{category}) $c\[31m%{if-debug}$c\[34m%{endif}%{function}$c\[0m: %{message}"
unset c

It is possible to create hyperlinked text with OSC-8. For example, instead of printing the %{file} (a full path to file), you may want to print a class name, which is a hyperlink to the file and line of message.

If using CLion, keep in mind that colorizing the hyperlinked text is currently broken. See IDEA-218793.

Managing Lots of Output

If you have lots of debugging statements, they may appear too fast and leave the terminal window before you can read them. There are three main ways to deal with this:

  1. Disable some logging categories to limit the amount of output generated
  2. Increase the amount of scrollback in the terminal so that output is not lost; in Konsole, you can go to Settings > Edit Current Profile... and click on the Scrollback tab to change this. Konsole also has a useful search feature: just press Ctrl+Shift+F or click Find... on the Edit menu.
  3. Save the output to a file. The UNIX command line tee is useful for this. For example, you can run application 2>&1 | tee ~/debug.log or application |& tee ~/debug.log to save the output to the file ~/debug.log while still viewing it in the terminal.

Example

export QT_FORCE_STDERR_LOGGING=1
export QT_MESSAGE_PATTERN="%{time yyyy.MM.dd, hh:mm:ss.zzz}, %{pid}, %{appname}, %{category}, %{type}, %{file}:%{line}, %{function} - %{message}"
export QT_LOGGING_RULES="*.debug=true;qt*.debug=false"

kcalc |& tee ~/a.txt
# kate ~/a.txt &

You can append at the end of QT_MESSAGE_PATTERN the string ", %{backtrace}".

"qt*.debug=false" is there because there are few errors in the Qt Framework source code, because there are some very verbose log lines there (e.g. "qt.qpa.events", "qt.qpa.input.events", "qt.quick.hover.trace") and because we are more interested in the KDE source code than in the Qt source code.