Skip to content

Sonar Bucket B (part 1): structured logging templates (CA2254/S2629)#190

Merged
blehnen merged 2 commits into
masterfrom
sonar-bucketB-logging
Jul 8, 2026
Merged

Sonar Bucket B (part 1): structured logging templates (CA2254/S2629)#190
blehnen merged 2 commits into
masterfrom
sonar-bucketB-logging

Conversation

@blehnen

@blehnen blehnen commented Jul 8, 2026

Copy link
Copy Markdown
Owner

Fifth SonarCloud sweep (Bucket B, part 1) — structured logging, following #184, #186, #188, #189.

What changed

Converted 69 interpolated logging calls ($"...{x}...") to static message templates with named placeholders + arguments:

// before
_log.LogError($"Message with ID {message.MessageId} has failed{Environment.NewLine}{exception}");
// after
_log.LogError("Message with ID {MessageId} has failed{NewLine}{Exception}", message.MessageId, System.Environment.NewLine, exception);

Across core, all transports (SqlServer/PostgreSQL/SQLite/Redis/LiteDB/Shared/Memory), and the integration-test notification helper. Clears CA2254 and its Sonar mirror S2629 (~62 shared + 7 test sites).

Output preserved exactly — where Environment.NewLine was interpolated it's passed as an argument (rather than dropped or hardcoded), so multi-line log formatting is unchanged.

Not in this PR

CA1873 ("argument may be expensive if logging is disabled", 37) is a different fix (IsEnabled guards / LoggerMessage). ~25 of its sites are the same calls converted here, so templating clears the cheap-arg ones automatically; the residual (Dashboard services + a few method-call args) is a focused follow-up.

Verification

  • Full solution builds clean, 0 errors (net10.0 + net8.0)
  • 0 interpolated Log*($"...") calls remain
  • Unit suites green (core 915, Memory, Redis)

No changelog/version bump (matches the #186/#188/#189 mechanical-cleanup precedent).

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Refactor
    • Updated logging across queue processing, workers, scheduling, and transport components to use structured message templates (with named placeholders for message IDs, queue/job details, retry info, and exceptions).
    • Kept log text and behavior effectively the same, improving consistency of error, warning, and trace output.
  • Tests
    • Added logging template rendering tests to confirm structured-log placeholders produce the same output as equivalent interpolated messages (including multi-line and exception scenarios).

Convert 69 interpolated logging calls ($"...{x}...") to static message
templates with named placeholders + args across core, all transports, and the
integration-test notification helper. Output preserved exactly (Environment.NewLine
passed as an arg where it was interpolated). Clears CA2254 and its Sonar mirror S2629.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jul 8, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

This PR converts logging across core queue, worker, scheduler, transport, and test code from string interpolation to structured message templates with explicit arguments. It also adds tests that verify template rendering matches equivalent interpolated output.

Changes

Structured Logging Conversion

Layer / File(s) Summary
Core queue, worker, and scheduler logging
Source/DotNetWorkQueue/Queue/BaseMonitor.cs, MessageProcessing.cs, MessageProcessingAsync.cs, MessageExceptionHandler.cs, PrimaryWorker.cs, ProducerQueue.cs, StopWorkers.cs, Worker.cs, WorkerCollection.cs, Source/DotNetWorkQueue/TaskScheduling/TaskScheduler.cs, Source/DotNetWorkQueue/Time/BaseTime.cs
Error, warning, debug, and trace logs across worker lifecycle, message processing, task counters, and time offset reporting use templates with placeholders instead of interpolated strings.
Heartbeat, job scheduler, and notification handler logging
Source/DotNetWorkQueue/Queue/HeartBeatScheduler.cs, HeartBeatWorker.cs, Source/DotNetWorkQueue/JobScheduler/JobScheduler.cs, ScheduledJob.cs, Source/DotNetWorkQueue.IntegrationTests.Shared/CreateNotifications.cs, Source/DotNetWorkQueue/Messages/ReceivedMessage.cs
Message lifecycle notification handlers and job/heartbeat scheduling logs use structured templates with message id, exception, newline, and status placeholders.
Logging decorator classes
Source/DotNetWorkQueue/Logging/Decorator/IClearErrorMessagesDecorator.cs, IClearExpiredMessagesDecorator.cs, IReceivePoisonMessageDecorator.cs, IResetHeartBeatDecorator.cs, IRollbackMessageDecorator.cs
Decorator log calls now pass counts, queue names, newlines, and exceptions as structured placeholders.
Shared and transport receive-error logging
Source/DotNetWorkQueue.Transport.Shared/Basic/ReceiveErrorMessage.cs, Source/DotNetWorkQueue/Transport/Memory/Basic/ReceiveErrorMessage.cs
Receive-error and error-queue move logging use MessageId/NewLine/Exception placeholders.
SQL Server transport logging
Source/DotNetWorkQueue.Transport.SqlServer/Basic/Message/RollbackMessage.cs, RemoveMessage.cs, RetrySqlPolicyCreation.cs
Rollback, remove-message, and retry-policy logs use structured placeholders for exceptions and retry parameters.
PostgreSQL transport logging
Source/DotNetWorkQueue.Transport.PostgreSQL/Basic/RemoveMessage.cs, RetrySQLPolicyCreation.cs
Commit-failure, status-table deletion, and retry-warning logs use structured placeholders.
SQLite transport logging
Source/DotNetWorkQueue.Transport.SQLite/Basic/RetryTransactionPolicyCreation.cs, SqLiteMessageQueueReceive.cs, Decorator/FindExpiredRecordsToDeleteQueryHandlerErrorDecorator.cs, FindRecordsToResetByHeartBeatDecorator.cs
Retry, missing-database, and rollback-abort logs use structured placeholders.
Redis transport logging
Source/DotNetWorkQueue.Transport.Redis/Basic/Logging/Decorator/DelayedProcessingActionDecorator.cs, ReceiveMessageQueryDecorator.cs, RedisQueueReceiveMessagesError.cs
Records-moved, expired-message, and error-queue logs use structured placeholders.
LiteDB transport and integration test helper logging
Source/DotNetWorkQueue.Transport.LiteDB/Basic/DatabaseExists.cs, LiteDbQueueReceiveMessages.cs, Source/DotNetWorkQueue.IntegrationTests.Shared/OsDetectionHelper.cs
Database-not-found, missing-file, and registry-read error logs use structured placeholders.
Logging template tests
Source/DotNetWorkQueue.Tests/Logging/LogMessageTemplateTests.cs
New tests verify placeholder-based messages render the same text as equivalent interpolation for single-value, multi-value, multi-line, exception, and retry cases.

Estimated code review effort: 2 (Simple) | ~20 minutes

Poem

A rabbit hopped through logs so plain,
Turning strings to templates again,
{NewLine} and {Exception} now take their place,
No more interpolation's messy embrace,
Structured and tidy, hop by hop,
This bunny's refactor just won't stop! 🐇✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: converting interpolated logging to structured logging templates for CA2254/S2629.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch

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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick comments (2)
Source/DotNetWorkQueue/Logging/Decorator/IResetHeartBeatDecorator.cs (1)

58-58: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Typo: "where" should be "were".

The message text reads "records that where outside of the heartbeat window" — "where" should be "were". This is pre-existing but now part of the changed line, so it's a trivial fix while here.

✏️ Proposed fix
-                   "Reset the status of {Count} records that where outside of the heartbeat window of {HeartBeatSeconds} seconds", count.Count, _configuration.HeartBeat.Time.TotalSeconds);
+                   "Reset the status of {Count} records that were outside of the heartbeat window of {HeartBeatSeconds} seconds", count.Count, _configuration.HeartBeat.Time.TotalSeconds);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Source/DotNetWorkQueue/Logging/Decorator/IResetHeartBeatDecorator.cs` at line
58, The log message in IResetHeartBeatDecorator contains a typo in the text
passed to the reset-status message. Update the string in the logging call that
references Count and HeartBeatSeconds so it says “records that were outside of
the heartbeat window” instead of “where,” keeping the rest of the message
unchanged.
Source/DotNetWorkQueue/TaskScheduling/TaskScheduler.cs (1)

146-149: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Consider consistent placeholder names for the same semantic value.

The overall task count is logged as {Queue} in IncrementGroup/DecrementGroup (lines 149, 187) but as {Current} in IncrementCounter/DecrementCounter (lines 161, 172). Meanwhile, {Current} is used for the group-level count in IncrementGroup/DecrementGroup (lines 146, 184) but for the overall count in IncrementCounter/DecrementCounter. This means the same placeholder name maps to different values depending on the log source, which complicates structured log queries.

Using distinct, consistent names (e.g., {GroupTaskCount} for group-level and {TaskCount} for overall) would improve log searchability.

Also applies to: 161-161, 172-172, 184-187

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Source/DotNetWorkQueue/TaskScheduling/TaskScheduler.cs` around lines 146 -
149, The logging in TaskScheduler currently reuses placeholder names for
different meanings across IncrementGroup, DecrementGroup, IncrementCounter, and
DecrementCounter, which makes structured log queries ambiguous. Update the Log
calls in these methods to use distinct, consistent names for the group-level
count versus the overall task count, and apply the same naming scheme everywhere
the counts are logged so the semantic value of each placeholder is always the
same.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@Source/DotNetWorkQueue/Logging/Decorator/IResetHeartBeatDecorator.cs`:
- Line 58: The log message in IResetHeartBeatDecorator contains a typo in the
text passed to the reset-status message. Update the string in the logging call
that references Count and HeartBeatSeconds so it says “records that were outside
of the heartbeat window” instead of “where,” keeping the rest of the message
unchanged.

In `@Source/DotNetWorkQueue/TaskScheduling/TaskScheduler.cs`:
- Around line 146-149: The logging in TaskScheduler currently reuses placeholder
names for different meanings across IncrementGroup, DecrementGroup,
IncrementCounter, and DecrementCounter, which makes structured log queries
ambiguous. Update the Log calls in these methods to use distinct, consistent
names for the group-level count versus the overall task count, and apply the
same naming scheme everywhere the counts are logged so the semantic value of
each placeholder is always the same.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 47822fdd-8269-4d84-9176-7dd4943b0e1f

📥 Commits

Reviewing files that changed from the base of the PR and between 4484fc6 and 47afecf.

📒 Files selected for processing (39)
  • Source/DotNetWorkQueue.IntegrationTests.Shared/CreateNotifications.cs
  • Source/DotNetWorkQueue.IntegrationTests.Shared/OsDetectionHelper.cs
  • Source/DotNetWorkQueue.Transport.LiteDB/Basic/DatabaseExists.cs
  • Source/DotNetWorkQueue.Transport.LiteDB/Basic/LiteDbQueueReceiveMessages.cs
  • Source/DotNetWorkQueue.Transport.PostgreSQL/Basic/RemoveMessage.cs
  • Source/DotNetWorkQueue.Transport.PostgreSQL/Basic/RetrySQLPolicyCreation.cs
  • Source/DotNetWorkQueue.Transport.Redis/Basic/Logging/Decorator/DelayedProcessingActionDecorator.cs
  • Source/DotNetWorkQueue.Transport.Redis/Basic/Logging/Decorator/ReceiveMessageQueryDecorator.cs
  • Source/DotNetWorkQueue.Transport.Redis/Basic/RedisQueueReceiveMessagesError.cs
  • Source/DotNetWorkQueue.Transport.SQLite/Basic/RetryTransactionPolicyCreation.cs
  • Source/DotNetWorkQueue.Transport.SQLite/Basic/SqLiteMessageQueueReceive.cs
  • Source/DotNetWorkQueue.Transport.SQLite/Decorator/FindExpiredRecordsToDeleteQueryHandlerErrorDecorator.cs
  • Source/DotNetWorkQueue.Transport.SQLite/Decorator/FindRecordsToResetByHeartBeatDecorator.cs
  • Source/DotNetWorkQueue.Transport.Shared/Basic/ReceiveErrorMessage.cs
  • Source/DotNetWorkQueue.Transport.SqlServer/Basic/Message/RollbackMessage.cs
  • Source/DotNetWorkQueue.Transport.SqlServer/Basic/RemoveMessage.cs
  • Source/DotNetWorkQueue.Transport.SqlServer/Basic/RetrySqlPolicyCreation.cs
  • Source/DotNetWorkQueue/JobScheduler/JobScheduler.cs
  • Source/DotNetWorkQueue/JobScheduler/ScheduledJob.cs
  • Source/DotNetWorkQueue/Logging/Decorator/IClearErrorMessagesDecorator.cs
  • Source/DotNetWorkQueue/Logging/Decorator/IClearExpiredMessagesDecorator.cs
  • Source/DotNetWorkQueue/Logging/Decorator/IReceivePoisonMessageDecorator.cs
  • Source/DotNetWorkQueue/Logging/Decorator/IResetHeartBeatDecorator.cs
  • Source/DotNetWorkQueue/Logging/Decorator/IRollbackMessageDecorator.cs
  • Source/DotNetWorkQueue/Messages/ReceivedMessage.cs
  • Source/DotNetWorkQueue/Queue/BaseMonitor.cs
  • Source/DotNetWorkQueue/Queue/HeartBeatScheduler.cs
  • Source/DotNetWorkQueue/Queue/HeartBeatWorker.cs
  • Source/DotNetWorkQueue/Queue/MessageExceptionHandler.cs
  • Source/DotNetWorkQueue/Queue/MessageProcessing.cs
  • Source/DotNetWorkQueue/Queue/MessageProcessingAsync.cs
  • Source/DotNetWorkQueue/Queue/PrimaryWorker.cs
  • Source/DotNetWorkQueue/Queue/ProducerQueue.cs
  • Source/DotNetWorkQueue/Queue/StopWorkers.cs
  • Source/DotNetWorkQueue/Queue/Worker.cs
  • Source/DotNetWorkQueue/Queue/WorkerCollection.cs
  • Source/DotNetWorkQueue/TaskScheduling/TaskScheduler.cs
  • Source/DotNetWorkQueue/Time/BaseTime.cs
  • Source/DotNetWorkQueue/Transport/Memory/Basic/ReceiveErrorMessage.cs

coderabbitai[bot]
coderabbitai Bot previously approved these changes Jul 8, 2026
Add LogMessageTemplateTests: renders representative converted templates
(single/multi placeholder, repeated Environment.NewLine, exception arg, retry
template) through a capturing ILogger and asserts the output equals the original
string-interpolation. Guards against placeholder/argument count mismatch, which
the logging framework renders silently rather than throwing.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@Source/DotNetWorkQueue.Tests/Logging/LogMessageTemplateTests.cs`:
- Around line 1-5: Add the missing LGPL-2.1 license header to this new C# test
file so it matches the repository’s source-file policy. Place the standard
header at the top of LogMessageTemplateTests.cs before the using statements, and
keep the rest of the file unchanged.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: ff97d1c1-b090-42f0-b5a1-face819a446c

📥 Commits

Reviewing files that changed from the base of the PR and between 47afecf and fee7708.

📒 Files selected for processing (1)
  • Source/DotNetWorkQueue.Tests/Logging/LogMessageTemplateTests.cs

Comment on lines +1 to +5
using System;
using Microsoft.Extensions.Logging;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace DotNetWorkQueue.Tests.Logging

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Add LGPL-2.1 license header.

Per coding guidelines, all .cs source files must include an LGPL-2.1 license header. This new file is missing it.

As per coding guidelines: **/*.cs: All source files must include LGPL-2.1 license headers.

📄 Add license header
+// Copyright (c) DotNetWorkQueue contributors
+// Licensed under the LGPL-2.1 license. See LICENSE file in the project root for full license information.
+
 using System;
 using Microsoft.Extensions.Logging;
 using Microsoft.VisualStudio.TestTools.UnitTesting;
📝 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
using System;
using Microsoft.Extensions.Logging;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace DotNetWorkQueue.Tests.Logging
// Copyright (c) DotNetWorkQueue contributors
// Licensed under the LGPL-2.1 license. See LICENSE file in the project root for full license information.
using System;
using Microsoft.Extensions.Logging;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace DotNetWorkQueue.Tests.Logging
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Source/DotNetWorkQueue.Tests/Logging/LogMessageTemplateTests.cs` around lines
1 - 5, Add the missing LGPL-2.1 license header to this new C# test file so it
matches the repository’s source-file policy. Place the standard header at the
top of LogMessageTemplateTests.cs before the using statements, and keep the rest
of the file unchanged.

Source: Coding guidelines

@sonarqubecloud

sonarqubecloud Bot commented Jul 8, 2026

Copy link
Copy Markdown

Quality Gate Failed Quality Gate failed

Failed conditions
5.7% Duplication on New Code (required ≤ 3%)
C Maintainability Rating on New Code (required ≥ A)

See analysis details on SonarQube Cloud

Catch issues before they fail your Quality Gate with our IDE extension SonarQube for IDE

@codecov

codecov Bot commented Jul 8, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 51.61290% with 30 lines in your changes missing coverage. Please review.
✅ Project coverage is 87.51%. Comparing base (f31bd27) to head (fee7708).
⚠️ Report is 4 commits behind head on master.

Files with missing lines Patch % Lines
Source/DotNetWorkQueue/Queue/HeartBeatScheduler.cs 16.66% 5 Missing ⚠️
...ce/DotNetWorkQueue/TaskScheduling/TaskScheduler.cs 33.33% 4 Missing ⚠️
...kQueue.Transport.PostgreSQL/Basic/RemoveMessage.cs 0.00% 2 Missing ⚠️
...rkQueue.Transport.SqlServer/Basic/RemoveMessage.cs 0.00% 2 Missing ⚠️
...ource/DotNetWorkQueue/JobScheduler/ScheduledJob.cs 50.00% 2 Missing ⚠️
Source/DotNetWorkQueue/Queue/MessageProcessing.cs 0.00% 2 Missing ⚠️
...ce/DotNetWorkQueue/Queue/MessageProcessingAsync.cs 0.00% 2 Missing ⚠️
...ansport.LiteDB/Basic/LiteDbQueueReceiveMessages.cs 0.00% 1 Missing ⚠️
...ransport.SQLite/Basic/SqLiteMessageQueueReceive.cs 0.00% 1 Missing ⚠️
...xpiredRecordsToDeleteQueryHandlerErrorDecorator.cs 0.00% 1 Missing ⚠️
... and 8 more
Additional details and impacted files
@@            Coverage Diff             @@
##           master     #190      +/-   ##
==========================================
- Coverage   87.54%   87.51%   -0.04%     
==========================================
  Files        1023     1023              
  Lines       33614    33614              
  Branches     2803     2803              
==========================================
- Hits        29429    29418      -11     
- Misses       3324     3332       +8     
- Partials      861      864       +3     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@blehnen blehnen merged commit 0fed4a1 into master Jul 8, 2026
5 of 7 checks passed
@blehnen blehnen deleted the sonar-bucketB-logging branch July 8, 2026 23:34
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