BUG-HUNT: [consistency] Duplicated and inconsistent logging in retry logic #3041

Open
opened 2026-04-05 04:14:26 +00:00 by freemo · 3 comments
Owner

Metadata

  • Branch: fix/bug-hunt-consistency-duplicated-logging-retry
  • Commit Message: fix(core): unify retry logging into shared utility to eliminate duplication across retry_patterns and retry_service_patterns
  • Milestone: v3.7.0
  • Parent Epic: #1669

Bug Report: [consistency] — Duplicated and inconsistent logging in retry logic

Severity Assessment

  • Impact: Low. The logging works, but it's inconsistent and contains duplicated code, which makes maintenance harder.
  • Likelihood: High. The inconsistent code is present in the current codebase.
  • Priority: Low

Location

  • File: src/cleveragents/core/retry_patterns.py and src/cleveragents/core/retry_service_patterns.py

Description

The logging implementation for retry attempts is inconsistent and duplicated across retry_patterns.py and retry_service_patterns.py.

  • retry_patterns.py uses log_before_retry and log_after_retry as callbacks for tenacity.retry.
  • retry_service_patterns.py defines its own logging functions, _log_service_retry_attempt and _log_circuit_open, and calls them directly within the retry loop.

This leads to duplicated logic for handling TypeError from structlog and makes the logging behavior inconsistent between the generic retry decorators and the service-level retry decorators.

Evidence

retry_patterns.py:

def log_before_retry(retry_state: RetryCallState) -> None:
    # ...
def log_after_retry(retry_state: RetryCallState) -> None:
    # ...

retry_service_patterns.py:

def _log_service_retry_attempt(
    service_name: str,
    operation_name: str,
    attempt: int,
    error: BaseException | None,
) -> None:
    # ...
def _log_circuit_open(service_name: str, failure_count: int) -> None:
    # ...

Current Behavior

Two separate, incompatible logging approaches exist side-by-side:

  1. retry_patterns.py uses tenacity callbacks (log_before_retry, log_after_retry) that receive a RetryCallState object.
  2. retry_service_patterns.py defines private functions (_log_service_retry_attempt, _log_circuit_open) called directly within the retry loop with explicit parameters.

Both modules duplicate the TypeError guard pattern for structlog compatibility, creating a maintenance burden and risk of divergence.

Expected Behavior

There should be a single, unified way of logging retry attempts that is shared between both modules. This would reduce code duplication and ensure consistent log output across all retry mechanisms.

Suggested Fix

Refactor the logging logic into a shared utility module or class (e.g., retry_logging.py or as part of a retry_base.py introduced in #1862) that can be used by both retry_patterns.py and retry_service_patterns.py. The service-level retry logic could be adapted to use the same tenacity callbacks as the generic retry decorators, passing the service name and operation name through the context.

Category

consistency

Subtasks

  • Audit all retry-related logging functions in retry_patterns.py and retry_service_patterns.py to map the full extent of duplication
  • Design a unified logging utility (e.g., retry_logging.py or extend retry_base.py from #1862) that consolidates log_before_retry, log_after_retry, _log_service_retry_attempt, and _log_circuit_open
  • Implement the shared logging utility with a consistent interface usable by both tenacity callbacks and direct call sites
  • Refactor retry_patterns.py to use the shared logging utility
  • Refactor retry_service_patterns.py to use the shared logging utility, removing the private _log_service_retry_attempt and _log_circuit_open functions
  • Verify that log output is consistent between generic and service-level retry decorators
  • Run nox -e typecheck to confirm Pyright passes with no errors
  • Run nox -e unit_tests to confirm all tests pass
  • Run nox -e coverage_report to confirm coverage ≥ 97%

Definition of Done

  • A single shared logging utility exists and is used by both retry_patterns.py and retry_service_patterns.py
  • No duplicated TypeError guard logic for structlog remains across the retry modules
  • Log output format is consistent between generic retry decorators and service-level retry decorators
  • All private logging functions (_log_service_retry_attempt, _log_circuit_open) are removed from retry_service_patterns.py in favour of the shared utility
  • All nox stages pass
  • Coverage >= 97%

Automated by CleverAgents Bot
Supervisor: Bug Hunting | Agent: ca-new-issue-creator

## Metadata - **Branch**: `fix/bug-hunt-consistency-duplicated-logging-retry` - **Commit Message**: `fix(core): unify retry logging into shared utility to eliminate duplication across retry_patterns and retry_service_patterns` - **Milestone**: v3.7.0 - **Parent Epic**: #1669 ## Bug Report: [consistency] — Duplicated and inconsistent logging in retry logic ### Severity Assessment - **Impact**: Low. The logging works, but it's inconsistent and contains duplicated code, which makes maintenance harder. - **Likelihood**: High. The inconsistent code is present in the current codebase. - **Priority**: Low ### Location - **File**: `src/cleveragents/core/retry_patterns.py` and `src/cleveragents/core/retry_service_patterns.py` ### Description The logging implementation for retry attempts is inconsistent and duplicated across `retry_patterns.py` and `retry_service_patterns.py`. - `retry_patterns.py` uses `log_before_retry` and `log_after_retry` as callbacks for `tenacity.retry`. - `retry_service_patterns.py` defines its own logging functions, `_log_service_retry_attempt` and `_log_circuit_open`, and calls them directly within the retry loop. This leads to duplicated logic for handling `TypeError` from `structlog` and makes the logging behavior inconsistent between the generic retry decorators and the service-level retry decorators. ### Evidence **`retry_patterns.py`:** ```python def log_before_retry(retry_state: RetryCallState) -> None: # ... def log_after_retry(retry_state: RetryCallState) -> None: # ... ``` **`retry_service_patterns.py`:** ```python def _log_service_retry_attempt( service_name: str, operation_name: str, attempt: int, error: BaseException | None, ) -> None: # ... def _log_circuit_open(service_name: str, failure_count: int) -> None: # ... ``` ### Current Behavior Two separate, incompatible logging approaches exist side-by-side: 1. `retry_patterns.py` uses `tenacity` callbacks (`log_before_retry`, `log_after_retry`) that receive a `RetryCallState` object. 2. `retry_service_patterns.py` defines private functions (`_log_service_retry_attempt`, `_log_circuit_open`) called directly within the retry loop with explicit parameters. Both modules duplicate the `TypeError` guard pattern for `structlog` compatibility, creating a maintenance burden and risk of divergence. ### Expected Behavior There should be a single, unified way of logging retry attempts that is shared between both modules. This would reduce code duplication and ensure consistent log output across all retry mechanisms. ### Suggested Fix Refactor the logging logic into a shared utility module or class (e.g., `retry_logging.py` or as part of a `retry_base.py` introduced in #1862) that can be used by both `retry_patterns.py` and `retry_service_patterns.py`. The service-level retry logic could be adapted to use the same `tenacity` callbacks as the generic retry decorators, passing the service name and operation name through the context. ### Category consistency ## Subtasks - [ ] Audit all retry-related logging functions in `retry_patterns.py` and `retry_service_patterns.py` to map the full extent of duplication - [ ] Design a unified logging utility (e.g., `retry_logging.py` or extend `retry_base.py` from #1862) that consolidates `log_before_retry`, `log_after_retry`, `_log_service_retry_attempt`, and `_log_circuit_open` - [ ] Implement the shared logging utility with a consistent interface usable by both `tenacity` callbacks and direct call sites - [ ] Refactor `retry_patterns.py` to use the shared logging utility - [ ] Refactor `retry_service_patterns.py` to use the shared logging utility, removing the private `_log_service_retry_attempt` and `_log_circuit_open` functions - [ ] Verify that log output is consistent between generic and service-level retry decorators - [ ] Run `nox -e typecheck` to confirm Pyright passes with no errors - [ ] Run `nox -e unit_tests` to confirm all tests pass - [ ] Run `nox -e coverage_report` to confirm coverage ≥ 97% ## Definition of Done - [ ] A single shared logging utility exists and is used by both `retry_patterns.py` and `retry_service_patterns.py` - [ ] No duplicated `TypeError` guard logic for `structlog` remains across the retry modules - [ ] Log output format is consistent between generic retry decorators and service-level retry decorators - [ ] All private logging functions (`_log_service_retry_attempt`, `_log_circuit_open`) are removed from `retry_service_patterns.py` in favour of the shared utility - [ ] All nox stages pass - [ ] Coverage >= 97% --- **Automated by CleverAgents Bot** Supervisor: Bug Hunting | Agent: ca-new-issue-creator
freemo added this to the v3.7.0 milestone 2026-04-05 04:14:32 +00:00
Author
Owner

Issue triaged by project owner:

  • State: Verified
  • Priority: Confirmed
  • MoSCoW: Should Have

Valid finding verified during batch triage.


Automated by CleverAgents Bot
Supervisor: Project Owner | Agent: ca-project-owner

Issue triaged by project owner: - **State**: Verified - **Priority**: Confirmed - **MoSCoW**: Should Have Valid finding verified during batch triage. --- **Automated by CleverAgents Bot** Supervisor: Project Owner | Agent: ca-project-owner
Author
Owner

Transition attempt from State/Verified to State/In Progress for issue #3041.

Current state labels: State/Verified

Preconditions checked: Issue is not in State/Paused (no blocker), no Blocked label present.

Planned actions:

  • Remove all existing State/* labels (currently State/Verified)
  • Add State/In Progress

Status: Automated label operations could not be completed due to missing label-management API in this environment. The change has not been applied to the issue labels.

Please confirm if you want me to proceed with manual label updates, or if I should attempt to update labels via an alternative path.


Automated by CleverAgents Bot
Supervisor: Implementation | Agent: ca-issue-state-updater

Transition attempt from State/Verified to State/In Progress for issue #3041. Current state labels: State/Verified Preconditions checked: Issue is not in State/Paused (no blocker), no Blocked label present. Planned actions: - Remove all existing State/* labels (currently State/Verified) - Add State/In Progress Status: Automated label operations could not be completed due to missing label-management API in this environment. The change has not been applied to the issue labels. Please confirm if you want me to proceed with manual label updates, or if I should attempt to update labels via an alternative path. --- **Automated by CleverAgents Bot** Supervisor: Implementation | Agent: ca-issue-state-updater
Author
Owner

[Stale Issue Alert] This issue has been in State/In Progress for approximately 10 hours with no recent activity.

Current state: State/In Progress
Last updated: 2026-04-05T07:21:47Z

Is this blocked? If work has paused, please update the state to State/Paused. If work is complete, please transition to State/In Review or State/Completed.


Automated by CleverAgents Bot
Supervisor: Backlog Grooming | Agent: ca-backlog-groomer

**[Stale Issue Alert]** This issue has been in `State/In Progress` for approximately 10 hours with no recent activity. Current state: `State/In Progress` Last updated: 2026-04-05T07:21:47Z Is this blocked? If work has paused, please update the state to `State/Paused`. If work is complete, please transition to `State/In Review` or `State/Completed`. --- **Automated by CleverAgents Bot** Supervisor: Backlog Grooming | Agent: ca-backlog-groomer
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Blocks
#1669 Bug Hunting Session
cleveragents/cleveragents-core
Reference
cleveragents/cleveragents-core#3041
No description provided.