Skip to content

[duplicate-code] Duplicate Code Pattern: Duplicated write-and-sync logic in FileLogger and ServerFileLogger #3738

@github-actions

Description

@github-actions

Part of duplicate code analysis: #3735

Summary

FileLogger.Log and ServerFileLogger.Log in internal/logger/ share identical core logic: format a log line with formatLogLine, write it with Println, then immediately Sync the underlying file. The sync-and-warn pattern is copy-pasted between the two implementations.

Duplication Details

Pattern: Duplicated write-and-sync core in file-based Log methods

  • Severity: Low
  • Occurrences: 2
  • Locations:
    • internal/logger/file_logger.go (lines 82–98, FileLogger.Log)
    • internal/logger/server_file_logger.go (lines 82–105, ServerFileLogger.Log)
  • Code Sample:
// FileLogger.Log (file_logger.go:82)
logLine := formatLogLine(level, category, format, args...)
fl.logger.Println(logLine)
if fl.logFile != nil {
    if err := fl.logFile.Sync(); err != nil {
        log.Printf("WARNING: Failed to sync log file: %v", err)
    }
}

// ServerFileLogger.Log (server_file_logger.go:93)
logLine := formatLogLine(level, category, format, args...)
logger.Println(logLine)
sfl.mu.RLock()
if file, exists := sfl.files[serverID]; exists {
    if err := file.Sync(); err != nil {
        log.Printf("WARNING: Failed to sync log file for server %s: %v", serverID, err)
    }
}
sfl.mu.RUnlock()

The formatLogLine + Println + Sync + warning-on-error sequence is the same in both methods, varying only in whether the serverID is included in the warning message.

Impact Analysis

  • Maintainability: A change to the sync-and-warn pattern (e.g., adding metrics, changing the warning message format, using fsync instead of Sync) requires editing 2 separate methods
  • Bug Risk: Low but real — the warning messages have drifted slightly ("sync log file" vs "sync log file for server %s"), suggesting the two copies are already diverging
  • Code Bloat: ~12 lines of near-identical logic

Refactoring Recommendations

  1. Extract a writeLine helper to common.go

    // writeLine writes a formatted log line to logger and syncs the file.
    // file may be nil (for stdout-backed loggers).
    func writeLine(logger *log.Logger, file *os.File, serverID, line string) {
        logger.Println(line)
        if file != nil {
            if err := file.Sync(); err != nil {
                if serverID != "" {
                    log.Printf("WARNING: Failed to sync log file for server %s: %v", serverID, err)
                } else {
                    log.Printf("WARNING: Failed to sync log file: %v", err)
                }
            }
        }
    }
  2. Both FileLogger.Log and ServerFileLogger.Log can then call writeLine with appropriate arguments.

  3. Estimated effort: 30–45 minutes

  4. Benefits: Single sync-and-warn implementation; future changes (e.g., adding write counters, structured errors) apply to one place

Implementation Checklist

  • Add writeLine helper (or equivalent) to internal/logger/common.go
  • Refactor FileLogger.Log to use the helper
  • Refactor ServerFileLogger.Log to use the helper
  • Run make test-unit to confirm no regressions

Parent Issue

See parent analysis report: #3735
Related to #3735

Generated by Duplicate Code Detector · ● 2.4M ·

  • expires on Apr 21, 2026, 6:13 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