🔍 Duplicate Code Pattern: Logger Functions with Mutex Lock Patterns
Part of duplicate code analysis: #970
Summary
The logger package contains 12+ nearly identical functions with repeated mutex lock/unlock patterns across three files. Each set of 4 functions (Info/Warn/Error/Debug) follows the exact same structure, differing only in the log level parameter.
Duplication Details
Pattern: Repeated Logger Function Structure
- Severity: High
- Occurrences: 12+ instances across 3 files
- Locations:
internal/logger/file_logger.go - Lines 114-151 (4 functions: LogInfo, LogWarn, LogError, LogDebug)
internal/logger/server_file_logger.go - Lines 162-211 (4 functions: LogInfoWithServer, LogWarnWithServer, LogErrorWithServer, LogDebugWithServer)
internal/logger/markdown_logger.go - Lines 187-204 (4 functions: LogInfoMd, LogWarnMd, LogErrorMd, LogDebugMd)
Code Sample - file_logger.go Pattern:
func LogInfo(category, format string, args ...interface{}) {
globalLoggerMu.RLock()
defer globalLoggerMu.RUnlock()
if globalFileLogger != nil {
globalFileLogger.Log(LogLevelInfo, category, format, args...)
}
}
func LogWarn(category, format string, args ...interface{}) {
globalLoggerMu.RLock()
defer globalLoggerMu.RUnlock()
if globalFileLogger != nil {
globalFileLogger.Log(LogLevelWarn, category, format, args...)
}
}
// ... LogError and LogDebug follow the same pattern
Code Sample - server_file_logger.go Pattern:
func LogInfoWithServer(serverID, category, format string, args ...interface{}) {
globalServerLoggerMu.RLock()
defer globalServerLoggerMu.RUnlock()
if globalServerFileLogger != nil {
globalServerFileLogger.Log(serverID, LogLevelInfo, category, format, args...)
}
// Also log to the main log file for unified view
LogInfo(category, "[%s] %s", serverID, fmt.Sprintf(format, args...))
}
// ... LogWarnWithServer, LogErrorWithServer, LogDebugWithServer follow the same pattern
Impact Analysis
- Maintainability: High Impact - Any change to logging behavior (e.g., adding tracing, modifying mutex strategy) requires updating 12+ functions identically
- Bug Risk: High - If one function is updated but others are missed, inconsistent logging behavior results
- Code Bloat: ~120+ lines of repetitive code (12 functions × ~10 lines each)
- Testing Complexity: Each function requires separate testing, increasing test maintenance
Refactoring Recommendations
1. Extract Generic Logger Helper Function (Recommended)
Extract common mutex lock/unlock and nil-check pattern into a generic helper:
// In file_logger.go
func logWithLevel(level LogLevel, category, format string, args ...interface{}) {
globalLoggerMu.RLock()
defer globalLoggerMu.RUnlock()
if globalFileLogger != nil {
globalFileLogger.Log(level, category, format, args...)
}
}
func LogInfo(category, format string, args ...interface{}) {
logWithLevel(LogLevelInfo, category, format, args...)
}
func LogWarn(category, format string, args ...interface{}) {
logWithLevel(LogLevelWarn, category, format, args...)
}
func LogError(category, format string, args ...interface{}) {
logWithLevel(LogLevelError, category, format, args...)
}
func LogDebug(category, format string, args ...interface{}) {
logWithLevel(LogLevelDebug, category, format, args...)
}
- Location:
internal/logger/file_logger.go (add logWithLevel helper)
- Estimated Effort: 2-3 hours
- Benefits:
- Reduces code from ~40 lines to ~20 lines per file
- Centralizes mutex handling logic
- Makes future changes safer (single point of modification)
2. Apply Same Pattern to server_file_logger.go
// In server_file_logger.go
func logWithLevelAndServer(serverID string, level LogLevel, category, format string, args ...interface{}) {
globalServerLoggerMu.RLock()
defer globalServerLoggerMu.RUnlock()
if globalServerFileLogger != nil {
globalServerFileLogger.Log(serverID, level, category, format, args...)
}
// Also log to the main log file for unified view
switch level {
case LogLevelInfo:
LogInfo(category, "[%s] %s", serverID, fmt.Sprintf(format, args...))
case LogLevelWarn:
LogWarn(category, "[%s] %s", serverID, fmt.Sprintf(format, args...))
// ... other levels
}
}
- Location:
internal/logger/server_file_logger.go
- Estimated Effort: 2-3 hours
- Benefits: Same as above, plus eliminates redundant dual-logging logic
3. Apply Same Pattern to markdown_logger.go
Similar refactoring for LogInfoMd, LogWarnMd, LogErrorMd, LogDebugMd:
// In markdown_logger.go
func logWithMarkdownLevel(level LogLevel, category, format string, args ...interface{}) {
logFn := getLogFunctionForLevel(level)
logWithMarkdown(level, logFn, category, format, args...)
}
- Location:
internal/logger/markdown_logger.go
- Estimated Effort: 1-2 hours
Implementation Checklist
Parent Issue
See parent analysis report: #970
Related to #970
AI generated by Duplicate Code Detector
🔍 Duplicate Code Pattern: Logger Functions with Mutex Lock Patterns
Part of duplicate code analysis: #970
Summary
The logger package contains 12+ nearly identical functions with repeated mutex lock/unlock patterns across three files. Each set of 4 functions (Info/Warn/Error/Debug) follows the exact same structure, differing only in the log level parameter.
Duplication Details
Pattern: Repeated Logger Function Structure
internal/logger/file_logger.go- Lines 114-151 (4 functions: LogInfo, LogWarn, LogError, LogDebug)internal/logger/server_file_logger.go- Lines 162-211 (4 functions: LogInfoWithServer, LogWarnWithServer, LogErrorWithServer, LogDebugWithServer)internal/logger/markdown_logger.go- Lines 187-204 (4 functions: LogInfoMd, LogWarnMd, LogErrorMd, LogDebugMd)Code Sample - file_logger.go Pattern:
Code Sample - server_file_logger.go Pattern:
Impact Analysis
Refactoring Recommendations
1. Extract Generic Logger Helper Function (Recommended)
Extract common mutex lock/unlock and nil-check pattern into a generic helper:
internal/logger/file_logger.go(addlogWithLevelhelper)2. Apply Same Pattern to server_file_logger.go
internal/logger/server_file_logger.go3. Apply Same Pattern to markdown_logger.go
Similar refactoring for
LogInfoMd,LogWarnMd,LogErrorMd,LogDebugMd:internal/logger/markdown_logger.goImplementation Checklist
logWithLevelinfile_logger.gologWithLevelAndServerinserver_file_logger.gomake test-allto verify no functionality brokenmake lintto ensure code qualityParent Issue
See parent analysis report: #970
Related to #970