Skip to content

Comments

Improve diagnostics#415

Open
jgeudens wants to merge 9 commits intomasterfrom
dev/diagnostics
Open

Improve diagnostics#415
jgeudens wants to merge 9 commits intomasterfrom
dev/diagnostics

Conversation

@jgeudens
Copy link
Member

@jgeudens jgeudens commented Feb 11, 2026

Summary by CodeRabbit

  • Changes

    • Reduced default logging verbosity and moved more messages to debug scope; improved error logging formatting.
    • Removed some informational startup and intermediate log emissions for cleaner output.
    • Adjusted several UI/display string formats for consistent placeholder indexing.
  • Tests

    • Added a unit test validating the string representation of a modbus data unit.
  • Chores

    • Version bumped to 4.2.1.

@coderabbitai
Copy link

coderabbitai bot commented Feb 11, 2026

Walkthrough

Reworked diagnostic logging: removed ModbusMaster signal-based logging, renamed logInfo → logDebug and switched to scoped/debug streams; removed ModbusPoll handlers for those signals; updated ScopeLogging signatures/formatting; reduced an initial startup log; bumped version to 4.2.1.

Changes

Cohort / File(s) Summary
ModbusMaster logging changes
src/communication/modbusmaster.cpp, src/communication/modbusmaster.h
Removed modbusLogInfo/modbusLogError signals; replaced signal-based emission with scoped logging (qCDebug/qCWarning); added util/scopelogging.h; renamed logInfo(QString)logDebug(const QString&); adjusted logError signature and guarded debug emission.
ModbusPoll handler removals
src/communication/modbuspoll.cpp, src/communication/modbuspoll.h
Removed connections to and implementations of handleModbusError(QString) and handleModbusInfo(QString) and updated related log-format indices in startCommunication.
Scoped logging implementation
src/util/scopelogging.cpp, src/util/scopelogging.h
Reformatted and changed parameter types to const references for message handler and ScopeLogging::handleLog; reorganised namespace formatting and switch-case style; no behavioural changes to severity mapping.
Startup, tests & metadata
src/mainapp.cpp, CHANGELOG.md, CMakeLists.txt, tests/communication/tst_modbusdataunit.*
Removed an initial timestamp log line; added changelog entries about logging and debug behaviour; bumped project version 4.2.0 → 4.2.1; added test for ModbusDataUnit::toString().
Miscellaneous formatting/placeholder fixes
src/communication/modbusconnection.cpp, src/communication/modbusdataunit.cpp, src/customwidgets/markerinfo.cpp, src/dialogs/*, src/importexport/datafileexporter.cpp, src/models/*
Adjusted multiple QString placeholder indices (%0 → %1, etc.) and small message-format tweaks; removed one debug log ("Connection already open") in connection preparation.

Possibly related PRs

  • Improve diagnostics dialog #416: Overlapping changes to scoped logging implementation and callsites (src/util/scopelogging.*) that align with the logging API and usage modifications in this PR.
🚥 Pre-merge checks | ✅ 1 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 5.26% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The title 'Improve diagnostics' is vague and overly broad, failing to convey the specific technical nature of the changes. Consider a more descriptive title that captures the core change, such as 'Rework diagnostic logging with scoped logging' or 'Reduce diagnostic logs when debug mode disabled'.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch dev/diagnostics

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/dialogs/diagnosticdialog.cpp (1)

202-215: ⚠️ Potential issue | 🔴 Critical

Bug: proxy model indices are used against the source model without mapping.

_pUi->listError uses _pSeverityProxyFilter as its model, so selectedRows() returns proxy indices. Using index.row() directly with _pDiagnosticModel->toString(...) will copy the wrong rows whenever the filter hides any entries.

🐛 Proposed fix: map proxy index to source index
     foreach (QModelIndex index, indexlist)
     {
-        clipboardText.append(QString("%1\n").arg(_pDiagnosticModel->toString(index.row())));
+        QModelIndex sourceIndex = _pSeverityProxyFilter->mapToSource(index);
+        clipboardText.append(QString("%1\n").arg(_pDiagnosticModel->toString(sourceIndex.row())));
     }
🧹 Nitpick comments (2)
src/communication/modbusmaster.cpp (1)

240-248: Consider passing QString by const reference.

Both logDebug and logError take QString by value. Since they only read the string, const QString& avoids unnecessary copies.

♻️ Suggested change

In the header (modbusmaster.h):

-    void logDebug(QString msg);
-    void logError(QString msg);
+    void logDebug(const QString& msg);
+    void logError(const QString& msg);

In the implementation:

-void ModbusMaster::logDebug(QString msg)
+void ModbusMaster::logDebug(const QString& msg)
 {
     qCDebug(scopeCommConnection) << QString("[Conn %0] %1").arg(_connectionId + 1).arg(msg);
 }

-void ModbusMaster::logError(QString msg)
+void ModbusMaster::logError(const QString& msg)
 {
     qCWarning(scopeCommConnection) << QString("[Conn %0] %1").arg(_connectionId + 1).arg(msg);
 }
src/util/scopelogging.cpp (1)

34-34: Commented-out code.

This commented-out filter rule could be removed if it's no longer needed, or given a short comment explaining when it might be re-enabled.

@jgeudens jgeudens force-pushed the dev/diagnostics branch 2 times, most recently from 56504a6 to 698bf3e Compare February 17, 2026 20:34
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/communication/modbusmaster.cpp (1)

224-232: ⚠️ Potential issue | 🟠 Major

Bug: dStream << &list prints the pointer address, not the list contents.

Line 229 passes the address of list to QDebug, which prints a hexadecimal pointer value instead of the list elements. This is inconsistent with line 219 where map is passed by value and prints the map contents. QDebug has an overload for const QList<T>& that prints contents, but the pointer overload prints only the address.

🐛 Proposed fix
-    dStream << &list;
+    dStream << list;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/communication/modbusmaster.cpp` around lines 224 - 232, In
ModbusMaster::dumpToString, replace the pointer being streamed (dStream <<
&list) with the actual QList to print its contents: change the QDebug call to
stream `list` (i.e., dStream << list) so QDebug uses the QList overload and
outputs elements; optionally consider accepting the parameter as const
QList<ModbusDataUnit>& to avoid copying, but the immediate fix is to stop
passing &list and pass list directly in the dStream << expression.
🧹 Nitpick comments (2)
src/util/scopelogging.cpp (1)

34-34: Commented-out code left behind.

If this filter rule is no longer needed, consider removing it rather than leaving it commented out. If it's kept as a developer reference, a short explanatory comment would help.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/util/scopelogging.cpp` at line 34, Remove the leftover commented-out call
to QLoggingCategory::setFilterRules("*=false\n") or add a concise explanatory
comment if it must remain for developers; locate the occurrence of the commented
line mentioning QLoggingCategory::setFilterRules in scopelogging.cpp and either
delete that commented line or replace it with a short note explaining why the
filter rule is kept commented (when/where to enable it) so the intent is clear.
src/communication/modbusmaster.cpp (1)

58-58: String formatting overhead when debug logging is disabled.

dumpToString() and string concatenation at each call site are evaluated unconditionally, even when the scopeCommConnection debug category is disabled. On a hot polling path this is wasteful. Consider guarding with an early check:

void ModbusMaster::logDebug(const QString& msg)
{
    if (scopeCommConnection().isDebugEnabled())
        qCDebug(scopeCommConnection) << QString("[Conn %0] %1").arg(_connectionId + 1).arg(msg);
}

However, note this only avoids the qCDebug formatting — the caller-side string building (including dumpToString) still runs. For a complete fix, callers would need to check scopeCommConnection().isDebugEnabled() before constructing the message, or use a macro/lambda pattern.

Also applies to: 119-119, 179-180, 236-236

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/communication/modbusmaster.cpp` at line 58, The debug message
construction currently calls dumpToString() and concatenates strings
unconditionally (e.g., in the register read log site that calls
logDebug("Register list read: " + dumpToString(registerList))), causing
unnecessary work when scopeCommConnection() debug is disabled; fix by guarding
caller-side message construction with if
(scopeCommConnection().isDebugEnabled()) before calling dumpToString() and
logDebug(), or change usages to pass already-checked/lazy-evaluated messages
into ModbusMaster::logDebug; locate references to dumpToString, the logDebug
method, and call sites in ModbusMaster where messages are built (including the
Register list read call and the other occurrences noted) and wrap those call
sites with the debug-enabled check to avoid unneeded string formatting.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@CHANGELOG.md`:
- Line 15: The changelog entry uses incorrect grammar ("less logs"); update the
sentence in CHANGELOG.md where the line reads "Rework diagnostic logging to
generate less logs when extensive logging is disabled" to use "fewer logs"
instead of "less logs" so it reads "Rework diagnostic logging to generate fewer
logs when extensive logging is disabled".

---

Outside diff comments:
In `@src/communication/modbusmaster.cpp`:
- Around line 224-232: In ModbusMaster::dumpToString, replace the pointer being
streamed (dStream << &list) with the actual QList to print its contents: change
the QDebug call to stream `list` (i.e., dStream << list) so QDebug uses the
QList overload and outputs elements; optionally consider accepting the parameter
as const QList<ModbusDataUnit>& to avoid copying, but the immediate fix is to
stop passing &list and pass list directly in the dStream << expression.

---

Nitpick comments:
In `@src/communication/modbusmaster.cpp`:
- Line 58: The debug message construction currently calls dumpToString() and
concatenates strings unconditionally (e.g., in the register read log site that
calls logDebug("Register list read: " + dumpToString(registerList))), causing
unnecessary work when scopeCommConnection() debug is disabled; fix by guarding
caller-side message construction with if
(scopeCommConnection().isDebugEnabled()) before calling dumpToString() and
logDebug(), or change usages to pass already-checked/lazy-evaluated messages
into ModbusMaster::logDebug; locate references to dumpToString, the logDebug
method, and call sites in ModbusMaster where messages are built (including the
Register list read call and the other occurrences noted) and wrap those call
sites with the debug-enabled check to avoid unneeded string formatting.

In `@src/util/scopelogging.cpp`:
- Line 34: Remove the leftover commented-out call to
QLoggingCategory::setFilterRules("*=false\n") or add a concise explanatory
comment if it must remain for developers; locate the occurrence of the commented
line mentioning QLoggingCategory::setFilterRules in scopelogging.cpp and either
delete that commented line or replace it with a short note explaining why the
filter rule is kept commented (when/where to enable it) so the intent is clear.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/communication/modbusmaster.cpp`:
- Around line 182-183: The log call in handleTriggerNextRequest builds a QString
with invalid %0 placeholder so readItem.count() is never shown; change the
format to use valid %1 and %2 placeholders (e.g. "Start address (%1) and count
(%2)"), keep the arg(...) order as
arg(readItem.address().toString()).arg(readItem.count()), and wrap the
logDebug(...) invocation in an isDebugEnabled() check to avoid unneeded string
construction when debug logging is off; target the logDebug(...) call that
references readItem in handleTriggerNextRequest.
- Around line 247-254: The format strings in ModbusMaster logging use invalid
"%0" placeholders which prevents proper substitution; update the format
templates in ModbusMaster::logDebug and ModbusMaster::logError from "[Conn %0]
%1" to "[Conn %1] %2" and adjust the corresponding .arg() call order to
.arg(_connectionId + 1).arg(msg); also fix the similar string "Start address
(%0) and count (%1)" to "Start address (%1) and count (%2)"; review other
affected messages referenced in the comment (e.g., the "Modbus Exception: %0"
and "Request Failed: %0 (%1)" call sites) and replace %0/%1 with %1/%2 as needed
so all .arg() substitutions match valid %1..%99 placeholders.

Comment on lines 182 to 183
logDebug("Partial list read: " +
QString("Start address (%0) and count (%1)").arg(readItem.address().toString()).arg(readItem.count()));
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Same %0 bug at this call site — readItem.count() is silently dropped

QString("Start address (%0) and count (%1)")
    .arg(readItem.address().toString())   // replaces %1 with address
    .arg(readItem.count())                // %0 is invalid → count never appears

The partial-read log message will show the address but never the count, and will contain a literal %0.

Additionally, unlike the comparable blocks at lines 58–61 and 239–242, this string is constructed unconditionally on every iteration of handleTriggerNextRequest. Wrapping it in isDebugEnabled() would keep the pattern consistent — although the individual arg() calls here are cheap.

🐛 Proposed fix
-        logDebug("Partial list read: " +
-                 QString("Start address (%0) and count (%1)").arg(readItem.address().toString()).arg(readItem.count()));
+        if (scopeCommConnection().isDebugEnabled())
+        {
+            logDebug("Partial list read: " +
+                     QString("Start address (%1) and count (%2)").arg(readItem.address().toString()).arg(readItem.count()));
+        }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/communication/modbusmaster.cpp` around lines 182 - 183, The log call in
handleTriggerNextRequest builds a QString with invalid %0 placeholder so
readItem.count() is never shown; change the format to use valid %1 and %2
placeholders (e.g. "Start address (%1) and count (%2)"), keep the arg(...) order
as arg(readItem.address().toString()).arg(readItem.count()), and wrap the
logDebug(...) invocation in an isDebugEnabled() check to avoid unneeded string
construction when debug logging is off; target the logDebug(...) call that
references readItem in handleTriggerNextRequest.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (2)
tests/communication/tst_modbusdataunit.cpp (1)

68-73: LGTM — test correctly validates the fixed format string.

As a nice-to-have, consider covering the other ObjectType variants (e.g. COIL, HOLDING_REGISTER) to pin the full range of ModbusAddress::toString() output alongside the slave-id suffix:

🧪 Optional: parametrised object-type coverage
 void TestModbusDataUnit::toString()
 {
     ModbusDataUnit unit(123, ModbusAddress::ObjectType::INPUT_REGISTER, 42);
     QString expected = "input register, 123, slave id 42";
     QCOMPARE(unit.toString(), expected);
+
+    ModbusDataUnit unit2(1, ModbusAddress::ObjectType::COIL, 1);
+    QVERIFY(unit2.toString().endsWith(", slave id 1"));
+
+    ModbusDataUnit unit3(40001, ModbusAddress::ObjectType::HOLDING_REGISTER, 255);
+    QVERIFY(unit3.toString().endsWith(", slave id 255"));
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/communication/tst_modbusdataunit.cpp` around lines 68 - 73, Current
test only asserts the INPUT_REGISTER output; extend TestModbusDataUnit::toString
to cover all ModbusAddress::ObjectType variants by adding parametrised cases (or
a small loop) that constructs ModbusDataUnit with each ObjectType (e.g., COIL,
DISCRETE_INPUT, HOLDING_REGISTER, INPUT_REGISTER), builds the corresponding
expected string using ModbusAddress::toString() semantic (e.g., "coil,
<address>, slave id <id>" / "holding register, <address>, slave id <id>"), and
QCOMPAREs unit.toString() against each expected value so the test pins full
range of ModbusAddress::toString() outputs plus the slave-id suffix; reference
TestModbusDataUnit::toString, ModbusDataUnit, and ModbusAddress::ObjectType when
locating the code to modify.
src/importexport/datafileexporter.cpp (1)

361-370: Correct %0-based → %1-based fix; consider hardening against %N in substituted values.

The 9-placeholder chained .arg() approach is functionally correct for typical serial port names. However, with chained calls, if any earlier substituted value (e.g. portName()) happened to contain a %2%9 literal, subsequent .arg() calls would over-substitute it. Direct concatenation removes this ambiguity entirely:

♻️ Optional: use string concatenation to avoid phantom substitution
-        strSettings = QString("%1%2%3%4%5%6%7%8%9")
-                        .arg(connData->portName())
-                        .arg(Util::separatorCharacter())
-                        .arg(connData->baudrate())
-                        .arg(Util::separatorCharacter())
-                        .arg(strParity)
-                        .arg(Util::separatorCharacter())
-                        .arg(strDataBits)
-                        .arg(Util::separatorCharacter())
-                        .arg(strStopBits);
+        const QChar sep = Util::separatorCharacter();
+        strSettings = connData->portName()
+                      + sep + QString::number(connData->baudrate())
+                      + sep + strParity
+                      + sep + strDataBits
+                      + sep + strStopBits;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/importexport/datafileexporter.cpp` around lines 361 - 370, Replace the
chained nine-placeholder QString::arg() call that builds strSettings with direct
concatenation of the individual components to avoid accidental "%N" substitution
in values; specifically build strSettings from connData->portName(),
Util::separatorCharacter(), connData->baudrate() (convert to QString if
numeric), Util::separatorCharacter(), strParity, Util::separatorCharacter(),
strDataBits, Util::separatorCharacter(), and strStopBits so no .arg() chaining
is used and embedded percent sequences in portName() or other values cannot be
re-interpreted.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/communication/modbusmaster.cpp`:
- Line 167: The log message passed to logError contains an accidental double
space in the QString literal used in the call logError(QString("Request Failed: 
%1 (%2)").arg(errorString).arg(error)); — fix it by removing the extra space so
the literal becomes "Request Failed: %1 (%2)" (update the QString passed to
logError accordingly).

---

Duplicate comments:
In `@src/communication/modbusmaster.cpp`:
- Around line 182-183: The logDebug call that builds the "Partial list read"
string should be guarded by isDebugEnabled() to avoid unconditional string
construction; wrap the existing logDebug(...) that references
readItem.address().toString() and readItem.count() in an if (isDebugEnabled()) {
... } block (or equivalent check) to match the pattern used in the other debug
blocks and keep consistency with functions/methods using logDebug and
isDebugEnabled in ModbusMaster.

---

Nitpick comments:
In `@src/importexport/datafileexporter.cpp`:
- Around line 361-370: Replace the chained nine-placeholder QString::arg() call
that builds strSettings with direct concatenation of the individual components
to avoid accidental "%N" substitution in values; specifically build strSettings
from connData->portName(), Util::separatorCharacter(), connData->baudrate()
(convert to QString if numeric), Util::separatorCharacter(), strParity,
Util::separatorCharacter(), strDataBits, Util::separatorCharacter(), and
strStopBits so no .arg() chaining is used and embedded percent sequences in
portName() or other values cannot be re-interpreted.

In `@tests/communication/tst_modbusdataunit.cpp`:
- Around line 68-73: Current test only asserts the INPUT_REGISTER output; extend
TestModbusDataUnit::toString to cover all ModbusAddress::ObjectType variants by
adding parametrised cases (or a small loop) that constructs ModbusDataUnit with
each ObjectType (e.g., COIL, DISCRETE_INPUT, HOLDING_REGISTER, INPUT_REGISTER),
builds the corresponding expected string using ModbusAddress::toString()
semantic (e.g., "coil, <address>, slave id <id>" / "holding register, <address>,
slave id <id>"), and QCOMPAREs unit.toString() against each expected value so
the test pins full range of ModbusAddress::toString() outputs plus the slave-id
suffix; reference TestModbusDataUnit::toString, ModbusDataUnit, and
ModbusAddress::ObjectType when locating the code to modify.

void ModbusMaster::handleRequestError(QString errorString, QModbusDevice::Error error)
{
logError(QString("Request Failed: %0 (%1)").arg(errorString).arg(error));
logError(QString("Request Failed: %1 (%2)").arg(errorString).arg(error));
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Double space in log message string.

"Request Failed: %1 (%2)" contains two consecutive spaces before %1.

🔧 Proposed fix
-    logError(QString("Request Failed:  %1 (%2)").arg(errorString).arg(error));
+    logError(QString("Request Failed: %1 (%2)").arg(errorString).arg(error));
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
logError(QString("Request Failed: %1 (%2)").arg(errorString).arg(error));
logError(QString("Request Failed: %1 (%2)").arg(errorString).arg(error));
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/communication/modbusmaster.cpp` at line 167, The log message passed to
logError contains an accidental double space in the QString literal used in the
call logError(QString("Request Failed:  %1 (%2)").arg(errorString).arg(error));
— fix it by removing the extra space so the literal becomes "Request Failed: %1
(%2)" (update the QString passed to logError accordingly).

@sonarqubecloud
Copy link

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant