From a6070847f075296458e1afef0210f9c89aca4b2a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kai=20K=C3=B6hne?= Date: Sun, 11 May 2025 15:06:36 +0200 Subject: [PATCH] qlogging: Journal: Log thread id, suppress empty fields The TID field can be used to differentiate the threads of a process where the message originates from. This allows to create a timeline of events when identical messages are created from multiple threads, or filter out messages from "uninteresting" threads in post-processing. The file/line/func fields are typically empty for non-debug builds, so storing these in the journal with dummy values is a waste of CPU time and storage. Use sd_journal_sendv instead of sd_journal_send, as that allows to vary the number of sent fields, and skip the ones without actual information. It is also slightly more performant, as it avoids the var-arg handling, sprintf parsing and formatting etc. done by sd_journal_send. [ChangeLog][QtCore][Logging] Qt now logs the thread id (TID) in journal, allowing separation of identical messages from multiple threads. Fixes: QTBUG-120047 Fixes: QTBUG-120048 Change-Id: Iccf3fe708dc4b896161693e13fb9012686bd1871 Reviewed-by: Thiago Macieira --- src/corelib/global/qlogging.cpp | 40 +++++++++++++++++++++++++++------ 1 file changed, 33 insertions(+), 7 deletions(-) diff --git a/src/corelib/global/qlogging.cpp b/src/corelib/global/qlogging.cpp index 26d50af3a30..170ccfa7ebf 100644 --- a/src/corelib/global/qlogging.cpp +++ b/src/corelib/global/qlogging.cpp @@ -1846,13 +1846,39 @@ static bool systemd_default_message_handler(QtMsgType type, break; } - sd_journal_send("MESSAGE=%s", message.toUtf8().constData(), - "PRIORITY=%i", priority, - "CODE_FUNC=%s", context.function ? context.function : "unknown", - "CODE_LINE=%d", context.line, - "CODE_FILE=%s", context.file ? context.file : "unknown", - "QT_CATEGORY=%s", context.category ? context.category : "unknown", - NULL); + // Explicit QByteArray instead of auto, to resolve the QStringBuilder proxy + const QByteArray messageField = "MESSAGE="_ba + message.toUtf8().constData(); + const QByteArray priorityField = "PRIORITY="_ba + QByteArray::number(priority); + const QByteArray tidField = "TID="_ba + QByteArray::number(qlonglong(qt_gettid())); + const QByteArray fileField = context.file + ? "CODE_FILE="_ba + context.file : QByteArray(); + const QByteArray funcField = context.function + ? "CODE_FUNC="_ba + context.function : QByteArray(); + const QByteArray lineField = context.line + ? "CODE_LINE="_ba + QByteArray::number(context.line) : QByteArray(); + const QByteArray categoryField = context.category + ? "QT_CATEGORY="_ba + context.category : QByteArray(); + + auto toIovec = [](const QByteArray &ba) { + return iovec{const_cast(ba.data()), ba.size()}; + }; + + struct iovec fields[7] = { + toIovec(messageField), + toIovec(priorityField), + toIovec(tidField), + }; + int nFields = 3; + if (context.file) + fields[nFields++] = toIovec(fileField); + if (context.function) + fields[nFields++] = toIovec(funcField); + if (context.line) + fields[nFields++] = toIovec(lineField); + if (context.category) + fields[nFields++] = toIovec(categoryField); + + sd_journal_sendv(fields, nFields); return true; // Prevent further output to stderr }