Part of duplicate code analysis: #1882
Summary
Four logger files (file_logger.go, server_file_logger.go, markdown_logger.go, rpc_logger.go) each independently implement near-identical sets of four public wrapper functions (Info/Warn/Error/Debug). Every new log level requires updating all four files identically.
Duplication Details
Pattern: Log Level Quad-Function Sets
- Severity: High
- Occurrences: 4 files × 4 wrappers = 16+ wrapper functions
- Locations:
internal/logger/file_logger.go (LogInfo/Warn/Error/Debug → logWithLevel)
internal/logger/server_file_logger.go (LogInfoWithServer/… → logWithLevelAndServer)
internal/logger/markdown_logger.go (markdown variants)
internal/logger/rpc_logger.go (lines 62–135, RPC variants)
Code Sample (file_logger.go):
func LogInfo(category, format string, args ...any) {
logWithLevel(LogLevelInfo, category, format, args...)
}
func LogWarn(category, format string, args ...any) {
logWithLevel(LogLevelWarn, category, format, args...)
}
func LogError(category, format string, args ...any) {
logWithLevel(LogLevelError, category, format, args...)
}
func LogDebug(category, format string, args ...any) {
logWithLevel(LogLevelDebug, category, format, args...)
}
Same structure repeated in server_file_logger.go:
func LogInfoWithServer(serverID, category, format string, args ...any) {
logWithLevelAndServer(serverID, LogLevelInfo, category, format, args...)
}
// ... Warn/Error/Debug variants identical
Impact Analysis
- Maintainability: Adding a
LogTrace level requires touching 4+ files with identical 1-liner changes
- Bug Risk: Divergence risk — one file may gain a feature (e.g., rate limiting) that others miss
- Code Bloat: ~40 lines of functionally identical wrapper boilerplate
Refactoring Recommendations
- Extract a shared dispatcher — introduce a
dispatchLog(level LogLevel, category, format string, args ...any) function in a shared logger utility, then have each logger variant delegate to it with a logger-specific sink function.
- Use a logFuncs map — the
logWithLevelAndServer already uses a logFuncs map; generalise this pattern as the single dispatch mechanism and eliminate per-level wrapper functions where possible.
- Code generation — if the 1-liner wrappers must be public API, use
go generate with a template to produce them consistently.
Implementation Checklist
Parent Issue
See parent analysis report: #1882
Related to #1882
Generated by Duplicate Code Detector · ◷
Part of duplicate code analysis: #1882
Summary
Four logger files (
file_logger.go,server_file_logger.go,markdown_logger.go,rpc_logger.go) each independently implement near-identical sets of four public wrapper functions (Info/Warn/Error/Debug). Every new log level requires updating all four files identically.Duplication Details
Pattern: Log Level Quad-Function Sets
internal/logger/file_logger.go(LogInfo/Warn/Error/Debug →logWithLevel)internal/logger/server_file_logger.go(LogInfoWithServer/… →logWithLevelAndServer)internal/logger/markdown_logger.go(markdown variants)internal/logger/rpc_logger.go(lines 62–135, RPC variants)Code Sample (file_logger.go):
Same structure repeated in
server_file_logger.go:Impact Analysis
LogTracelevel requires touching 4+ files with identical 1-liner changesRefactoring Recommendations
dispatchLog(level LogLevel, category, format string, args ...any)function in a sharedloggerutility, then have each logger variant delegate to it with a logger-specific sink function.logWithLevelAndServeralready uses alogFuncsmap; generalise this pattern as the single dispatch mechanism and eliminate per-level wrapper functions where possible.go generatewith a template to produce them consistently.Implementation Checklist
make testbetween eachAGENTS.mdlogger section if naming conventions changeParent Issue
See parent analysis report: #1882
Related to #1882