feat(gost): add debug logging for failover mechanism analysis

Add debug logs to trace failover behavior:
- FailFilter.Filter(): log node name, fail count, maxFails, timeSince, failTimeout
- hop.Select(): log excludeNodes list, node selection results
- handler retry loop: log maxRetries, selected nodes, dial failures

This helps diagnose issues where failover between multiple target nodes
is not working as expected.
This commit is contained in:
root
2026-02-05 01:06:56 +00:00
parent 583905b7ed
commit 09c58e2298
3 changed files with 29 additions and 2 deletions
@@ -192,6 +192,8 @@ func (h *forwardHandler) Handle(ctx context.Context, conn net.Conn, opts ...hand
var lastErr error
var cc net.Conn
h.options.Logger.Debugf("[handler.retry] starting retry loop: maxRetries=%d", maxRetries)
for attempt := 0; attempt < maxRetries; attempt++ {
// Select a target node, excluding previously tried nodes
selectCtx := ctxvalue.ContextWithExcludeNodes(ctx, triedNodes)
@@ -202,12 +204,15 @@ func (h *forwardHandler) Handle(ctx context.Context, conn net.Conn, opts ...hand
)
}
if target == nil {
h.options.Logger.Debugf("[handler.retry] attempt=%d target=nil, triedNodes=%v", attempt, triedNodes)
if lastErr != nil {
return lastErr
}
return errors.New("node not available")
}
h.options.Logger.Debugf("[handler.retry] attempt=%d selected node=%s addr=%s", attempt, target.Name, target.Addr)
// Track this node as tried
triedNodes = append(triedNodes, target.Addr)
@@ -233,6 +238,8 @@ func (h *forwardHandler) Handle(ctx context.Context, conn net.Conn, opts ...hand
// Mark node as failed for future selections
if marker := target.Marker(); marker != nil {
marker.Mark()
h.options.Logger.Debugf("[handler.retry] attempt=%d dial failed, marked node=%s count=%d err=%v",
attempt, target.Addr, marker.Count(), err)
}
lastErr = err
// Try next node
+5
View File
@@ -149,6 +149,9 @@ func (p *chainHop) Select(ctx context.Context, opts ...hop.SelectOption) *chain.
excludeSet[addr] = true
}
// Debug logging for failover analysis
log.Debugf("[hop.Select] excludeNodes=%v, totalNodes=%d", excludeNodes, len(p.Nodes()))
var nodes []*chain.Node
for _, node := range p.Nodes() {
if node == nil {
@@ -213,7 +216,9 @@ func (p *chainHop) Select(ctx context.Context, opts ...hop.SelectOption) *chain.
// FailFilter will exclude recently-failed nodes, allowing traffic to
// be routed to healthy alternatives.
if s := p.options.selector; s != nil {
log.Debugf("[hop.Select] calling selector.Select with %d nodes", len(nodes))
if node := s.Select(ctx, nodes...); node != nil {
log.Debugf("[hop.Select] selected node=%s addr=%s", node.Name, node.Addr)
return node
}
// All nodes filtered out by FailFilter - all are marked as failed.
+17 -2
View File
@@ -2,8 +2,10 @@ package selector
import (
"context"
"fmt"
"time"
"github.com/go-gost/core/chain"
"github.com/go-gost/core/metadata"
"github.com/go-gost/core/selector"
mdutil "github.com/go-gost/x/metadata/util"
@@ -53,8 +55,21 @@ func (f *failFilter[T]) Filter(ctx context.Context, vs ...T) []T {
if mi, _ := any(v).(selector.Markable); mi != nil {
if marker := mi.Marker(); marker != nil {
if marker.Count() < int64(maxFails) ||
time.Since(marker.Time()) >= failTimeout {
count := marker.Count()
timeSince := time.Since(marker.Time())
passed := count < int64(maxFails) || timeSince >= failTimeout
// Debug logging for failover analysis
nodeName := "unknown"
nodeAddr := "unknown"
if node, ok := any(v).(*chain.Node); ok {
nodeName = node.Name
nodeAddr = node.Addr
}
fmt.Printf("[FailFilter] node=%s addr=%s count=%d maxFails=%d timeSince=%v failTimeout=%v passed=%v\n",
nodeName, nodeAddr, count, maxFails, timeSince, failTimeout, passed)
if passed {
l = append(l, v)
}
continue