Guidelines and HOWTOs/Debugging/Using Error Messages: Difference between revisions
→Qt 5 / KDE Frameworks 5: Remove duplicated content, improve paragraph, update link to qt6 |
→Customize Logging Output: Mention OSC-8 - a standard to create hyperlink in terminal. Mention CLion issue. |
||
Line 108: | Line 108: | ||
unset c | unset c | ||
}} | }} | ||
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. | |||
If using [[Get_Involved/development/IDE_configuration/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]. | |||
== Managing Lots of Output == | == Managing Lots of Output == |
Revision as of 01:45, 29 September 2023
Qt 5 / KDE Frameworks 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"
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:
- 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; tee is useful for this. For example, you can run
<div><strong>Template error:</strong> are you trying to use the <span style="display:inline; background-color:#ebf1f5; padding: 0.1em 0.2em; font-family:monospace,monospace; color:#222;">=</span> sign? Visit [[Help:Template#Escape template-breaking characters]] for workarounds.</div>[[Category:Pages with broken templates]]
or<div><strong>Template error:</strong> are you trying to use the <span style="display:inline; background-color:#ebf1f5; padding: 0.1em 0.2em; font-family:monospace,monospace; color:#222;">=</span> sign? Visit [[Help:Template#Escape template-breaking characters]] for workarounds.</div>[[Category:Pages with broken templates]]
to save the output to the file ~/debug.log while still viewing it in the terminal.
Qt 4 / kdelibs 4
kdelibs provides a family of functions that output information to stderr, meaning that if you run an application from the terminal, it will be displayed in that terminal window. If you run the application from the desktop (using KRunner or the application menu, for example), the output will normally 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.
To use these functions in your code, you need to include the correct header file <div><strong>Template error:</strong> are you trying to use the <span style="display:inline; background-color:#ebf1f5; padding: 0.1em 0.2em; font-family:monospace,monospace; color:#222;">=</span> sign? Visit [[Help:Template#Escape template-breaking characters]] for workarounds.</div>[[Category:Pages with broken templates]]
and then you can use the functions
kDebug() << "Something happened that only developers care about" << someVariable;
kWarning() << "Something bad happened that users (end-users, or application developers using this library) should be aware of";
kError() << "Something even worse happened";
kFatal() << "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 kdelibs-provided types can be passed directly (like with someVariable in the example).
Note that the kDebug calls will only do anything if the code was compiled with debugging enabled (and so will generally not work in packages from a distribution). This means cmake should be run with the -DCMAKE_BUILD_TYPE=debugfull argument. The other functions, however, will produce output no matter how the code was compiled.
Debug Areas
The debugging output can be controlled at runtime using debugging areas. This allows enabling debugging output for only certain libraries or plugins, for example. Debugging areas are numbers, so the KStatusNotifierItemPrivate::registerToDaemon method in the kdeui library, for example, has the call
kDebug(299) << "Registering a client interface to the KStatusNotifierWatcher";
The file kdebug.areas in the kdecore directory of kdelibs indicates that the number 299 is associated with "kdeui (KNotification)".
This information is used by the kdebugdialog utility (which you can just run from the commandline or using KRunner) to turn these areas on and off, enabling or disabling those kDebug statements. It is also used by kDebug, kWarning, kError and kFatal to indicate which component output the line. For example, the line in the above example would produce the line
kwalletmanager(642)/kdeui (KNotification) KStatusNotifierItemPrivate::registerToDaemon: Registering a client interface to the KStatusNotifierWatcher
when executed from within the application kwalletmanager, with PID 642.
For applications, you can generally just omit the area number, and kDebug will use the default area. If you are developing a library or a plugin, though, you should get a number assigned (via the kde-core-devel mailing list) for your library or plugin, and use it in your code. Rather than using the number directly in every call to kDebug and friends, you can just add add_definition(-DKDE_DEFAULT_DEBUG_AREA=<number>)
to your CMakeLists.txt file.
Improving Log Output
There are a couple of useful environment variables to control the output of kDebug and friends. export KDE_COLOR_DEBUG=1
will make them produce colored output, and export KDE_DEBUG_TIMESTAMP=1
will include timestamps in the output. export KDE_DEBUG_TIMESTAMP=2
can be used to include milliseconds in the timestamps.
export KDE_DEBUG_NOPROCESSINFO=1
export KDE_DEBUG_NOAREANAME=1
export KDE_DEBUG_NOMETHODNAME=1
export KDE_DEBUG_FILELINE=1
The above commands toggle various components of the debug messages.
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:
- Use kdebugdialog to disable some logging areas 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; tee is useful for this. For example, you can run
application 2>&1 | tee debug.log
to save the output to the file debug.log while still viewing it in the terminal. This can also be used to capture output from startx.