Skip to content

Refactor: Extract triple-logging helpers to eliminate duplicate logging patterns#945

Draft
Claude wants to merge 2 commits intomainfrom
claude/remove-duplicate-logging-calls
Draft

Refactor: Extract triple-logging helpers to eliminate duplicate logging patterns#945
Claude wants to merge 2 commits intomainfrom
claude/remove-duplicate-logging-calls

Conversation

@Claude
Copy link
Contributor

@Claude Claude AI commented Feb 14, 2026

The internal/launcher/log_helpers.go file contained a repetitive triple-logging pattern where every logging operation called three different loggers in sequence: file logger (logger.LogInfoWithServer), stdout (log.Printf), and debug logger (logLauncher.Printf). This pattern appeared 6+ times across different functions.

Changes

  • Added inline helper functions (following the marshalToResponse pattern from internal/mcp/connection.go):

    • tripleLogInfo() - encapsulates info-level logging to all three destinations
    • tripleLogWarn() - encapsulates warning-level logging with variadic stdout messages
    • tripleLogError() - encapsulates error-level logging with optional debug message
  • Refactored 5 logging functions to use helpers:

    • logSecurityWarning
    • logLaunchStart
    • logLaunchError
    • logTimeoutError
    • logLaunchSuccess

Impact

  • 25% reduction in logging calls (44 → 33)
  • Single point to modify logging behavior across launcher
  • Identical logging output preserved

Example

Before:

logger.LogErrorWithServer(serverID, "backend", "Failed to launch: %v", err)
log.Printf("[LAUNCHER] ❌ FAILED to launch server '%s'", serverID)
logLauncher.Printf("Launch failed: serverID=%s, error=%v", serverID, err)

After:

tripleLogError(
    serverID, "backend",
    fmt.Sprintf("Failed to launch: %v", err),
    []string{fmt.Sprintf("❌ FAILED to launch server '%s'", serverID)},
    fmt.Sprintf("Launch failed: serverID=%s, error=%v", serverID, err),
)

Warning

Firewall rules blocked me from connecting to one or more addresses (expand for details)

I tried to connect to the following addresses, but was blocked by firewall rules:

  • example.com
    • Triggering command: /tmp/go-build2698919314/b001/launcher.test /tmp/go-build2698919314/b001/launcher.test -test.testlogfile=/tmp/go-build2698919314/b001/testlog.txt -test.paniconexit0 -test.timeout=10m0s -test.run=^Test 64/src/net/cgo_u--abbrev-ref 64/src/net/cgo_uHEAD /usr/local/bin/git ache/go/1.25.7/xbase64 -trimpath 64/pkg/tool/linux_amd64/vet ; \#system# !d; HEAD rev-�� --abbrev-ref HEAD k/_temp/ghcca-node/node/bin/git /opt/hostedtoolcbase64 .cfg if (a[i] < b[i]) exit(3); else if (a[i] > b[i]) exit(0) base64 (dns block)
    • Triggering command: /tmp/go-build3935831774/b001/launcher.test /tmp/go-build3935831774/b001/launcher.test -test.testlogfile=/tmp/go-build3935831774/b001/testlog.txt -test.paniconexit0 -test.timeout=10m0s -d -fmessage-length--abbrev-ref 64/pkg/tool/linuHEAD x_amd64/compile 0, length(NVM_DIdocker 5565171/b165/ cal/bin/as x_amd64/compile rev-�� --abbrev-ref HEAD cal/bin/git ache/go/1.25.7/xbase64 -I .cfg base64 (dns block)
    • Triggering command: /tmp/go-build846594381/b279/launcher.test /tmp/go-build846594381/b279/launcher.test -test.testlogfile=/tmp/go-build846594381/b279/testlog.txt -test.paniconexit0 -test.timeout=10m0s -test.v=true \t /opt/hostedtoolcache/go/1.25.7/x64/pkg/tool/linux_amd64/compile k/_temp/ghcca-node/node/bin/git ead x_amd64/compile /usr/bin/base64 base64 -d 64/pkg/tool/linu--abbrev-ref base64 64/pkg/tool/linux_amd64/vet -lang=go1.25 64/pkg/tool/linu-d /usr/sbin/git 64/pkg/tool/linux_amd64/vet (dns block)
  • invalid-host-that-does-not-exist-12345.com
    • Triggering command: /tmp/go-build4175565171/b260/config.test /tmp/go-build4175565171/b260/config.test -test.testlogfile=/tmp/go-build4175565171/b260/testlog.txt -test.paniconexit0 -test.timeout=10m0s -test.v=true go /v2/chacha8.go 64/pkg/tool/linu.c (dns block)
  • nonexistent.local
    • Triggering command: /tmp/go-build2698919314/b001/launcher.test /tmp/go-build2698919314/b001/launcher.test -test.testlogfile=/tmp/go-build2698919314/b001/testlog.txt -test.paniconexit0 -test.timeout=10m0s -test.run=^Test 64/src/net/cgo_u--abbrev-ref 64/src/net/cgo_uHEAD /usr/local/bin/git ache/go/1.25.7/xbase64 -trimpath 64/pkg/tool/linux_amd64/vet ; \#system# !d; HEAD rev-�� --abbrev-ref HEAD k/_temp/ghcca-node/node/bin/git /opt/hostedtoolcbase64 .cfg if (a[i] < b[i]) exit(3); else if (a[i] > b[i]) exit(0) base64 (dns block)
    • Triggering command: /tmp/go-build3935831774/b001/launcher.test /tmp/go-build3935831774/b001/launcher.test -test.testlogfile=/tmp/go-build3935831774/b001/testlog.txt -test.paniconexit0 -test.timeout=10m0s -d -fmessage-length--abbrev-ref 64/pkg/tool/linuHEAD x_amd64/compile 0, length(NVM_DIdocker 5565171/b165/ cal/bin/as x_amd64/compile rev-�� --abbrev-ref HEAD cal/bin/git ache/go/1.25.7/xbase64 -I .cfg base64 (dns block)
    • Triggering command: /tmp/go-build846594381/b279/launcher.test /tmp/go-build846594381/b279/launcher.test -test.testlogfile=/tmp/go-build846594381/b279/testlog.txt -test.paniconexit0 -test.timeout=10m0s -test.v=true \t /opt/hostedtoolcache/go/1.25.7/x64/pkg/tool/linux_amd64/compile k/_temp/ghcca-node/node/bin/git ead x_amd64/compile /usr/bin/base64 base64 -d 64/pkg/tool/linu--abbrev-ref base64 64/pkg/tool/linux_amd64/vet -lang=go1.25 64/pkg/tool/linu-d /usr/sbin/git 64/pkg/tool/linux_amd64/vet (dns block)
  • slow.example.com
    • Triggering command: /tmp/go-build2698919314/b001/launcher.test /tmp/go-build2698919314/b001/launcher.test -test.testlogfile=/tmp/go-build2698919314/b001/testlog.txt -test.paniconexit0 -test.timeout=10m0s -test.run=^Test 64/src/net/cgo_u--abbrev-ref 64/src/net/cgo_uHEAD /usr/local/bin/git ache/go/1.25.7/xbase64 -trimpath 64/pkg/tool/linux_amd64/vet ; \#system# !d; HEAD rev-�� --abbrev-ref HEAD k/_temp/ghcca-node/node/bin/git /opt/hostedtoolcbase64 .cfg if (a[i] < b[i]) exit(3); else if (a[i] > b[i]) exit(0) base64 (dns block)
    • Triggering command: /tmp/go-build3935831774/b001/launcher.test /tmp/go-build3935831774/b001/launcher.test -test.testlogfile=/tmp/go-build3935831774/b001/testlog.txt -test.paniconexit0 -test.timeout=10m0s -d -fmessage-length--abbrev-ref 64/pkg/tool/linuHEAD x_amd64/compile 0, length(NVM_DIdocker 5565171/b165/ cal/bin/as x_amd64/compile rev-�� --abbrev-ref HEAD cal/bin/git ache/go/1.25.7/xbase64 -I .cfg base64 (dns block)
    • Triggering command: /tmp/go-build846594381/b279/launcher.test /tmp/go-build846594381/b279/launcher.test -test.testlogfile=/tmp/go-build846594381/b279/testlog.txt -test.paniconexit0 -test.timeout=10m0s -test.v=true \t /opt/hostedtoolcache/go/1.25.7/x64/pkg/tool/linux_amd64/compile k/_temp/ghcca-node/node/bin/git ead x_amd64/compile /usr/bin/base64 base64 -d 64/pkg/tool/linu--abbrev-ref base64 64/pkg/tool/linux_amd64/vet -lang=go1.25 64/pkg/tool/linu-d /usr/sbin/git 64/pkg/tool/linux_amd64/vet (dns block)
  • this-host-does-not-exist-12345.com
    • Triggering command: /tmp/go-build4175565171/b284/mcp.test /tmp/go-build4175565171/b284/mcp.test -test.testlogfile=/tmp/go-build4175565171/b284/testlog.txt -test.paniconexit0 -test.timeout=10m0s -test.v=true go gKxUsK41W /usr/sbin/git ; s#/opt/hostedtoolcache/go/1.25.7/x64/pkg/tool/linux_amd64/vet --global nfig/composer/ve-bool 64/pkg/include ortc�� go 64/src/internal/-ifaceassert 64/pkg/tool/linu-nilfunc -b lpers.go /home/REDACTED/.lo--version 64/pkg/tool/linu-tests (dns block)

If you need me to access, download, or install something from one of these locations, you can either:

Original prompt

This section details on the original issue you should resolve

<issue_title>[duplicate-code] Multi-Level Logging Calls Duplication</issue_title>
<issue_description># 🔍 Duplicate Code Pattern: Multi-Level Logging Calls

Part of duplicate code analysis: #929

Summary

The internal/launcher/log_helpers.go file exhibits a repetitive triple-logging pattern where every logging operation calls three different loggers in sequence: logger.LogInfoWithServer() (file logger), log.Printf() (stdout), and logLauncher.Printf() (debug logger). This pattern appears 6+ times across different functions.

Duplication Details

Pattern: Triple Logging Calls

  • Severity: Medium

  • Occurrences: 6+ instances across 6 functions

  • Locations:

    • internal/launcher/log_helpers.go lines 23-27 (logSecurityWarning)
    • internal/launcher/log_helpers.go lines 33-35, 37-40 (logLaunchStart - 2x)
    • internal/launcher/log_helpers.go lines 69-75 (logLaunchError)
    • internal/launcher/log_helpers.go lines 96-105 (logTimeoutError - 2x)
    • internal/launcher/log_helpers.go lines 111-117 (logLaunchSuccess - 2x)
  • Code Sample:

    // Pattern repeated throughout:
    logger.LogInfoWithServer(serverID, "backend", "Launching MCP backend server: %s, command=%s, args=%v", serverID, serverCfg.Command, sanitize.SanitizeArgs(serverCfg.Args))
    log.Printf("[LAUNCHER] Starting MCP server: %s", serverID)
    logLauncher.Printf("Launching new server: serverID=%s, command=%s, inContainer=%v, isDirectCommand=%v", ...)
  • Another Example:

    logger.LogErrorWithServer(serverID, "backend", "Failed to launch MCP backend server%s: server=%s%s, error=%v", ...)
    log.Printf("[LAUNCHER] ❌ FAILED to launch server '%s'%s", serverID, sessionSuffix(sessionID))
    log.Printf("[LAUNCHER] Error: %v", err)

Impact Analysis

  • Maintainability: Medium impact - Adding/removing a logging level requires changes in 6+ locations
  • Bug Risk: Low-Medium - Inconsistent logging if one call is modified but others aren't
  • Code Bloat: ~30-35 lines of repetitive logging invocations
  • Readability: Reduces clarity - obscures the actual logic with verbose logging calls

Refactoring Recommendations

Option 1: Unified Launcher Logger Wrapper (Recommended)

  • Extract common pattern to: internal/launcher/launcher_logger.go
  • Estimated effort: 3-4 hours
  • Benefits:
    • Single interface for all launcher logging
    • Easier to add/remove logging levels
    • Consistent formatting across all log destinations
    • Better testability (mock single logger instead of three)
  • Implementation:
    type LauncherLogger struct {
        launcher *Launcher
    }
    
    func (ll *LauncherLogger) LogStart(serverID, sessionID string, cfg *config.ServerConfig, isDirect bool) {
        // Encapsulates triple logging with proper formatting
        logger.LogInfoWithServer(serverID, "backend", "Launching MCP backend server: ...")
        log.Printf("[LAUNCHER] Starting MCP server: %s", serverID)
        logLauncher.Printf("Launching new server: serverID=%s", serverID)
    }
    
    func (ll *LauncherLogger) LogError(serverID, sessionID string, err error, cfg *config.ServerConfig, isDirect bool) {
        // Encapsulates error logging with diagnostics
        logger.LogErrorWithServer(serverID, "backend", "Failed to launch: ...")
        log.Printf("[LAUNCHER] ❌ FAILED to launch server '%s'", serverID)
        logLauncher.Printf("Launch failed: serverID=%s, error=%v", serverID, err)
    }

Option 2: Structured Logging Event System

  • Use a single logging call with metadata that fans out to destinations
  • Estimated effort: 6-8 hours (requires broader refactoring)
  • Benefits: More flexible, supports dynamic log routing
  • Trade-off: Larger scope, affects more of the codebase

Option 3: Logging Middleware/Interceptor

  • Create a logging interceptor that handles multi-destination logging
  • Estimated effort: 4-5 hours
  • Benefits: Centralized logging control, easier to modify behavior
  • Trade-off: Adds abstraction layer

Implementation Checklist

  • Review duplication findings
  • Decide on refactoring approach (Option 1 recommended)
  • Design LauncherLogger interface
  • Implement wrapper methods for each logging scenario
  • Refactor all 6 functions to use new logger
  • Update tests to verify behavior
  • Consider extending to other launcher modules
  • Document logging patterns in AGENTS.md

Parent Issue

See parent analysis report: #929
Related to #929

AI generated by Duplicate Code Detector

  • expires on Feb 21, 2026, 10:12 AM UTC

…ng patterns

- Add inline helper functions (tripleLogInfo, tripleLogWarn, tripleLogError)
- Reduces code duplication by 25% (44 to 33 logging calls)
- Refactor logSecurityWarning, logLaunchStart, logLaunchError, logTimeoutError, logLaunchSuccess
- All helpers are inline in log_helpers.go following marshalToResponse pattern
- Maintains identical logging behavior while improving maintainability

Co-authored-by: lpcox <15877973+lpcox@users.noreply.github.com>
@Claude Claude AI changed the title [WIP] Refactor multi-level logging calls to reduce duplication Refactor: Extract triple-logging helpers to eliminate duplicate logging patterns Feb 14, 2026
@Claude Claude AI requested a review from lpcox February 14, 2026 13:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[duplicate-code] Multi-Level Logging Calls Duplication

2 participants