-
-
Notifications
You must be signed in to change notification settings - Fork 1.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Logging Pt.2: Predefined categories and usage examples #2782
Conversation
@@ -17,6 +16,18 @@ | |||
#include "controllers/controllerdebug.h" | |||
#include "util/assert.h" | |||
|
|||
Q_LOGGING_CATEGORY(mixxxLog, MIXXX_LOGGING_CATEGORY_ROOT) | |||
|
|||
Q_LOGGING_CATEGORY(mixxxLogConfig, MIXXX_LOGGING_CATEGORY_CONFIG) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there any advantage from defining them all in one place?
Personally, I think all these macros look ugly.
I'd prefer this:
bool Highscore::load(const QString &filepath) { QLoggingCategory fcIo("fc.io"); qCDebug(fcIo) << "Loading highscore ..."; QFile file(filepath); if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { qCWarning(fcIo) << "Could not open file " << filepath << "!"; return; } // ... }[...]
QLoggingCategory represents a category in code, in this case it's "fc.io". It's not a one to one mapping though ... you can have multiple instances representing the same category.
Source: https://www.qt.io/blog/2014/03/11/qt-weekly-1-categorized-logging
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The idea was to group the logs under some predefined top-level categories to allow basic filtering without needing to know all child categories. The custom macro MIXXX_LOGGING_CATEGORY_PARENT_CHILD establishes a naming convention.
The macros Q_DECLARE_LOGGING_CATEGORY/Q_LOGGING_CATEGORY help to find all categories that are available, even if they are only defined locally inside a .cpp file and not intended to be reused.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The idea was to group the logs under some predefined top-level categories to allow basic filtering without needing to know all child categories. The custom macro MIXXX_LOGGING_CATEGORY_PARENT_CHILD establishes a naming convention.
I thought this is done implicitly by separating the category name with dots.
And filtering can be done like this:
QT_LOGGING_RULES="mixxx.engine.controls.*=true"
The macros Q_DECLARE_LOGGING_CATEGORY/Q_LOGGING_CATEGORY help to find all categories that are available, even if they are only defined locally inside a .cpp file and not intended to be reused.
So you can list all categories via command line? Or do you mean by grepping through the source?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@uklotzde can you elaborate?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ping.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't like to introduce a custom macro. But so far I didn't have any idea how to achieve this in a better way.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We could put all category strings in a single header file and then include them from there. That way you only need to seach-replace in a single file.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
With this restriction the macros could be avoided.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
After 2nd thought: Not viable. A huge global file that might contain a separate logging category for each module (comprising 1 or a few .cpp files) is unmaintainable.
How is a user supposed to chose the correct one? Even the list of predefined top-level logging categories in logging.h is long already.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm. I also thought about this and I'm not even sure we need this global list or the macros. When we define the logging category inside the source file, like this it becomes much easier to find the correct logging category to enable debug messages for:
QLoggingCategory logcat("device.soundsource.portaudio");
You're right that it becomes a bit tedious to restructure logging categories later on if the fully qualified names are spread across the code base like this, but it's still possible to mass-replace them in a bash one-liner using find
/grep
/sed
. And I don' t think we want to restructure them that often, and the instant visibility of the full logging category name when reading the source file is very convenient and outweighs this potential issue IMHO.
src/sources/soundsourceffmpeg.cpp
Outdated
@@ -79,15 +79,15 @@ inline int64_t getStreamStartTime(const AVStream& avStream) { | |||
auto start_time = avStream.start_time; | |||
if (start_time == AV_NOPTS_VALUE) { | |||
// This case is not unlikely, e.g. happens when decoding WAV files. | |||
#if ENABLE_TRACING | |||
kLogger.trace() | |||
#if ENABLE_TRACE_LOG |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can't we get rid of this?
I don't think this makes a notable performance improvement:
Note: Arguments aren't processed if the debug output for that category is not enabled, so don't rely on any side effects.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Qt does not provided a detailed trace level, only debug. Until the default log level has been switched from debug to info we cannot avoid this conditional compilation to avoid log spam.
And even then log messages in real-time threads need to be disabled at compile time by using conditional compilation. That's the reason why I also picked an example from the sound device code.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do we need something more detailed than debug? IMHO it makes more sense to switch on debug messages for the logging category you're interested in and use INFO for everything else by default.
Why do they need to be disabled in RT code? If arguments aren't processed if debug logging is disabled (as the documentation states), shouldn't this just cause one additional conditional branch per log statement? That should be OK even in performance-critical code, right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
String operations are too slow for realtime code.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The logs we are talking about in the real-time code are only used for tracing execution paths in the callback loop during development. These are invoked frequently and should not be compiled into any executable version, even if they would be real-time safe.
The Qt logging facilities will have some performance impact at runtime. And they have been designed for general purpose desktop UI applications, not for performance critical code.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I will add a global define to enable verbose debug logs like in SoundSourceFFmpeg
. These could be enabled permanently once we have switched the default log level from Debug to Info.
The local defines for trace logs in SoundDevicePortAudio
are still needed as explained. I will try to add a reference to this example as blueprint.
@@ -17,6 +16,18 @@ | |||
#include "controllers/controllerdebug.h" | |||
#include "util/assert.h" | |||
|
|||
Q_LOGGING_CATEGORY(mixxxLog, MIXXX_LOGGING_CATEGORY_ROOT) | |||
|
|||
Q_LOGGING_CATEGORY(mixxxLogConfig, MIXXX_LOGGING_CATEGORY_CONFIG) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We could put all category strings in a single header file and then include them from there. That way you only need to seach-replace in a single file.
Q_DECLARE_LOGGING_CATEGORY(mixxxLogEngine) | ||
#define MIXXX_LOGGING_CATEGORY_ENGINE \ | ||
MIXXX_LOGGING_CATEGORY_PARENT_CHILD(MIXXX_LOGGING_CATEGORY_ROOT, "engine") | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
/// Base logging category for effects | |
Q_DECLARE_LOGGING_CATEGORY(mixxxLogEffects) | |
#define MIXXX_LOGGING_CATEGORY_ENGINE \ | |
MIXXX_LOGGING_CATEGORY_PARENT_CHILD(MIXXX_LOGGING_CATEGORY_ROOT, "effects") |
I can then use this in #2618 after this is merged.
/// Base logging category for scripting | ||
Q_DECLARE_LOGGING_CATEGORY(mixxxLogScript) | ||
#define MIXXX_LOGGING_CATEGORY_SCRIPT \ | ||
MIXXX_LOGGING_CATEGORY_PARENT_CHILD(MIXXX_LOGGING_CATEGORY_ROOT, "script") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
/// Base logging category for scripting | |
Q_DECLARE_LOGGING_CATEGORY(mixxxLogScript) | |
#define MIXXX_LOGGING_CATEGORY_SCRIPT \ | |
MIXXX_LOGGING_CATEGORY_PARENT_CHILD(MIXXX_LOGGING_CATEGORY_ROOT, "script") | |
/// Base logging category for controllers | |
Q_DECLARE_LOGGING_CATEGORY(mixxxLogController) | |
#define MIXXX_LOGGING_CATEGORY_SCRIPT \ | |
MIXXX_LOGGING_CATEGORY_PARENT_CHILD(MIXXX_LOGGING_CATEGORY_ROOT, "controller") |
There is info logged by the controller system apart from scripts. ControllerEngine could create a mixxx.controller.CONTROLLERNAME.script subcategory for messages from the script.
/// in your local repo while debugging. Disable it before submitting a pull | ||
/// request. Use qCDebug() for these trace logs. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
/// in your local repo while debugging. Disable it before submitting a pull | |
/// request. Use qCDebug() for these trace logs. | |
/// in your local repo while debugging. Disable it before committing. | |
/// Use qCDebug() for these trace logs. |
/// Base logging category for hardware I/O sound devices | ||
Q_DECLARE_LOGGING_CATEGORY(mixxxLogDevice) | ||
#define MIXXX_LOGGING_CATEGORY_DEVICE \ | ||
MIXXX_LOGGING_CATEGORY_PARENT_CHILD(MIXXX_LOGGING_CATEGORY_ROOT, "device") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
/// Base logging category for hardware I/O sound devices | |
Q_DECLARE_LOGGING_CATEGORY(mixxxLogDevice) | |
#define MIXXX_LOGGING_CATEGORY_DEVICE \ | |
MIXXX_LOGGING_CATEGORY_PARENT_CHILD(MIXXX_LOGGING_CATEGORY_ROOT, "device") | |
/// Base logging category for hardware I/O sound devices | |
Q_DECLARE_LOGGING_CATEGORY(mixxxLogAudioDevice) | |
#define MIXXX_LOGGING_CATEGORY_DEVICE \ | |
MIXXX_LOGGING_CATEGORY_PARENT_CHILD(MIXXX_LOGGING_CATEGORY_ROOT, "audiodevice") |
"Device" by itself could mean lots of things.
# Conflicts: # src/sources/soundsourceffmpeg.cpp
# Conflicts: # src/sources/soundsourceffmpeg.cpp
- Document and illustrate all steps in detail - Verify assumptions by debug assertions
# Conflicts: # src/sources/soundsourceffmpeg.cpp
Can we have an update on this PR? Do people like where it is going? What do we need to do to make it not a draft? |
I am not able to continue working on this until other PRs have been finished and merged. |
# Conflicts: # src/soundio/sounddeviceportaudio.cpp # src/soundio/sounddeviceportaudio.h # src/sources/soundsourceffmpeg.cpp # src/sources/soundsourceffmpeg.h
This PR is marked as stale because it has been open 90 days with no activity. |
I am tired to work on C++ code and don't plan to revive this PR. |
I will delete the corresponding branches in my fork eventually to get rid of the cognitive load. |
TODO
The documentation can be found in logging.h.
SoundDevicePortAudio logs:
SoundSourceFFmpeg logs: