Skip to content

[duplicate-code] Duplicate Code Pattern: Logger Initialization Closure Structure #2755

@github-actions

Description

@github-actions

Part of duplicate code analysis: #2754

Summary

Six logger types in internal/logger/ each implement nearly identical initialization code using the same initLogger(...) call pattern with inline setup and error-handler closures. This results in ~26 lines of structural boilerplate repeated per logger type.

Duplication Details

Pattern: Repeated initLogger setup/error-handler closures per logger type

  • Severity: High
  • Occurrences: 6 logger initializers
  • Locations:
    • internal/logger/file_logger.go (lines ~29–54)
    • internal/logger/markdown_logger.go (lines ~29–54)
    • internal/logger/jsonl_logger.go (lines ~42–68)
    • internal/logger/server_file_logger.go (lines ~28–54)
    • internal/logger/tools_logger.go (lines ~44–82)
    • internal/logger/rpc_logger.go (similar pattern)

Code Sample — FileLogger:

logger, err := initLogger(
    logDir, fileName, os.O_APPEND,
    func(file *os.File, logDir, fileName string) (*FileLogger, error) {
        fl := &FileLogger{
            logDir:   logDir,
            fileName: fileName,
            logFile:  file,
            logger:   log.New(file, "", 0),
        }
        log.Printf("Logging to file: %s", filepath.Join(logDir, fileName))
        return fl, nil
    },
    func(err error, logDir, fileName string) (*FileLogger, error) {
        log.Printf("WARNING: Failed to initialize log file: %v", err)
        log.Printf("WARNING: Falling back to stdout for logging")
        fl := &FileLogger{
            logDir:      logDir,
            fileName:    fileName,
            useFallback: true,
            logger:      log.New(os.Stdout, "", 0),
        }
        return fl, nil
    },
)
initGlobalFileLogger(logger)

MarkdownLogger has an identical outer structure with a different struct type and flag values. Same applies to JSONL, RPC, ServerFile, and Tools loggers.

Impact Analysis

  • Maintainability: Any change to the init pattern (e.g., adding a new field) must be repeated in all 6 files
  • Bug Risk: Divergence between loggers is already present (some log startup messages, others silently fall back)
  • Code Bloat: ~150 lines that could be reduced to ~30 lines with named setup/error functions

Refactoring Recommendations

  1. Extract named setup and error functions per logger type

    • Replace closures with named setupXLogger and handleXLoggerError functions
    • Estimated effort: 2–3 hours
    • File: keep in respective *_logger.go files
  2. Standardize fallback logging across all loggers (currently inconsistent: some print warnings, others are silent)

Implementation Checklist

  • Review all 6 logger init functions side-by-side
  • Extract named setup/error functions to replace inline closures
  • Standardize fallback behavior and startup log messages
  • Run make test-unit to verify no regressions
  • Run make agent-finished to confirm build and lint pass

Parent Issue

See parent analysis report: #2754
Related to #2754

Generated by Duplicate Code Detector ·

  • expires on Apr 5, 2026, 6:00 AM UTC

Metadata

Metadata

Assignees

No one assigned

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions