Skip to content

Commit 0f746e7

Browse files
committed
feat: refactor logging to use a logger with severity levels
1 parent 87239bb commit 0f746e7

File tree

14 files changed

+223
-247
lines changed

14 files changed

+223
-247
lines changed

internal/log.go

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,3 +77,39 @@ func (l LogLevelT) InfoOrAbove() bool {
7777
func (l LogLevelT) DebugOrAbove() bool {
7878
return l >= LogLevelDebug
7979
}
80+
81+
// LoggerWithLevel is a logger interface with leveled logging methods
82+
type LoggerWithLevel interface {
83+
Infof(ctx context.Context, format string, v ...interface{})
84+
Warnf(ctx context.Context, format string, v ...interface{})
85+
Debugf(ctx context.Context, format string, v ...interface{})
86+
Errorf(ctx context.Context, format string, v ...interface{})
87+
}
88+
89+
// LegacyLoggerAdapter is a logger that implements LoggerWithLevel interface
90+
// using the global [Logger] and [LogLevel] variables.
91+
type LegacyLoggerAdapter struct{}
92+
93+
func (l *LegacyLoggerAdapter) Infof(ctx context.Context, format string, v ...interface{}) {
94+
if LogLevel.InfoOrAbove() {
95+
Logger.Printf(ctx, format, v...)
96+
}
97+
}
98+
99+
func (l *LegacyLoggerAdapter) Warnf(ctx context.Context, format string, v ...interface{}) {
100+
if LogLevel.WarnOrAbove() {
101+
Logger.Printf(ctx, format, v...)
102+
}
103+
}
104+
105+
func (l *LegacyLoggerAdapter) Debugf(ctx context.Context, format string, v ...interface{}) {
106+
if LogLevel.DebugOrAbove() {
107+
Logger.Printf(ctx, format, v...)
108+
}
109+
}
110+
111+
func (l LegacyLoggerAdapter) Errorf(ctx context.Context, format string, v ...interface{}) {
112+
Logger.Printf(ctx, format, v...)
113+
}
114+
115+
var LegacyLoggerWithLevel LoggerWithLevel = &LegacyLoggerAdapter{}

internal/pool/pool.go

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ type Options struct {
117117
DialerRetryTimeout time.Duration
118118

119119
// Optional logger for connection pool operations.
120-
Logger internal.Logging
120+
Logger internal.LoggerWithLevel
121121
}
122122

123123
type lastDialErrorWrap struct {
@@ -226,7 +226,7 @@ func (p *ConnPool) checkMinIdleConns() {
226226
p.idleConnsLen.Add(-1)
227227

228228
p.freeTurn()
229-
p.logf(context.Background(), "addIdleConn panic: %+v", err)
229+
p.logger().Errorf(context.Background(), "addIdleConn panic: %+v", err)
230230
}
231231
}()
232232

@@ -382,7 +382,7 @@ func (p *ConnPool) dialConn(ctx context.Context, pooled bool) (*Conn, error) {
382382
return cn, nil
383383
}
384384

385-
p.logf(ctx, "redis: connection pool: failed to dial after %d attempts: %v", maxRetries, lastErr)
385+
p.logger().Errorf(ctx, "redis: connection pool: failed to dial after %d attempts: %v", maxRetries, lastErr)
386386
// All retries failed - handle error tracking
387387
p.setLastDialError(lastErr)
388388
if atomic.AddUint32(&p.dialErrorsNum, 1) == uint32(p.cfg.PoolSize) {
@@ -455,7 +455,7 @@ func (p *ConnPool) getConn(ctx context.Context) (*Conn, error) {
455455

456456
for {
457457
if attempts >= getAttempts {
458-
p.logf(ctx, "redis: connection pool: was not able to get a healthy connection after %d attempts", attempts)
458+
p.logger().Errorf(ctx, "redis: connection pool: was not able to get a healthy connection after %d attempts", attempts)
459459
break
460460
}
461461
attempts++
@@ -482,12 +482,12 @@ func (p *ConnPool) getConn(ctx context.Context) (*Conn, error) {
482482
if hookManager != nil {
483483
acceptConn, err := hookManager.ProcessOnGet(ctx, cn, false)
484484
if err != nil {
485-
p.logf(ctx, "redis: connection pool: failed to process idle connection by hook: %v", err)
485+
p.logger().Errorf(ctx, "redis: connection pool: failed to process idle connection by hook: %v", err)
486486
_ = p.CloseConn(cn)
487487
continue
488488
}
489489
if !acceptConn {
490-
p.logf(ctx, "redis: connection pool: conn[%d] rejected by hook, returning to pool", cn.GetID())
490+
p.logger().Errorf(ctx, "redis: connection pool: conn[%d] rejected by hook, returning to pool", cn.GetID())
491491
p.Put(ctx, cn)
492492
cn = nil
493493
continue
@@ -512,7 +512,7 @@ func (p *ConnPool) getConn(ctx context.Context) (*Conn, error) {
512512
// this should not happen with a new connection, but we handle it gracefully
513513
if err != nil || !acceptConn {
514514
// Failed to process connection, discard it
515-
p.logf(ctx, "redis: connection pool: failed to process new connection conn[%d] by hook: accept=%v, err=%v", newcn.GetID(), acceptConn, err)
515+
p.logger().Errorf(ctx, "redis: connection pool: failed to process new connection conn[%d] by hook: accept=%v, err=%v", newcn.GetID(), acceptConn, err)
516516
_ = p.CloseConn(newcn)
517517
return nil, err
518518
}
@@ -706,7 +706,7 @@ func (p *ConnPool) popIdle() (*Conn, error) {
706706

707707
// If we exhausted all attempts without finding a usable connection, return nil
708708
if attempts > 1 && attempts >= maxAttempts && int32(attempts) >= p.poolSize.Load() {
709-
p.logf(context.Background(), "redis: connection pool: failed to get a usable connection after %d attempts", attempts)
709+
p.logger().Errorf(context.Background(), "redis: connection pool: failed to get a usable connection after %d attempts", attempts)
710710
return nil, nil
711711
}
712712

@@ -723,7 +723,7 @@ func (p *ConnPool) Put(ctx context.Context, cn *Conn) {
723723
// Peek at the reply type to check if it's a push notification
724724
if replyType, err := cn.PeekReplyTypeSafe(); err != nil || replyType != proto.RespPush {
725725
// Not a push notification or error peeking, remove connection
726-
p.logf(ctx, "Conn has unread data (not push notification), removing it")
726+
p.logger().Errorf(ctx, "Conn has unread data (not push notification), removing it")
727727
p.Remove(ctx, cn, err)
728728
}
729729
// It's a push notification, allow pooling (client will handle it)
@@ -736,7 +736,7 @@ func (p *ConnPool) Put(ctx context.Context, cn *Conn) {
736736
if hookManager != nil {
737737
shouldPool, shouldRemove, err = hookManager.ProcessOnPut(ctx, cn)
738738
if err != nil {
739-
p.logf(ctx, "Connection hook error: %v", err)
739+
p.logger().Errorf(ctx, "Connection hook error: %v", err)
740740
p.Remove(ctx, cn, err)
741741
return
742742
}
@@ -838,7 +838,7 @@ func (p *ConnPool) removeConn(cn *Conn) {
838838
// this can be idle conn
839839
for idx, ic := range p.idleConns {
840840
if ic.GetID() == cid {
841-
p.logf(context.Background(), "redis: connection pool: removing idle conn[%d]", cid)
841+
p.logger().Errorf(context.Background(), "redis: connection pool: removing idle conn[%d]", cid)
842842
p.idleConns = append(p.idleConns[:idx], p.idleConns[idx+1:]...)
843843
p.idleConnsLen.Add(-1)
844844
break
@@ -954,7 +954,7 @@ func (p *ConnPool) isHealthyConn(cn *Conn, now time.Time) bool {
954954
if replyType, err := cn.rd.PeekReplyType(); err == nil && replyType == proto.RespPush {
955955
// For RESP3 connections with push notifications, we allow some buffered data
956956
// The client will process these notifications before using the connection
957-
p.logf(context.Background(), "push: conn[%d] has buffered data, likely push notifications - will be processed by client", cn.GetID())
957+
p.logger().Infof(context.Background(), "push: conn[%d] has buffered data, likely push notifications - will be processed by client", cn.GetID())
958958
return true // Connection is healthy, client will handle notifications
959959
}
960960
return false // Unexpected data, not push notifications, connection is unhealthy
@@ -965,10 +965,10 @@ func (p *ConnPool) isHealthyConn(cn *Conn, now time.Time) bool {
965965
return true
966966
}
967967

968-
func (p *ConnPool) logf(ctx context.Context, format string, args ...any) {
968+
func (p *ConnPool) logger() internal.LoggerWithLevel {
969969
if p.cfg.Logger != nil {
970-
p.cfg.Logger.Printf(ctx, format, args...)
971-
} else {
972-
internal.Logger.Printf(ctx, format, args...)
970+
return p.cfg.Logger
973971
}
972+
973+
return &internal.LegacyLoggerAdapter{}
974974
}

maintnotifications/circuit_breaker.go

Lines changed: 12 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -102,9 +102,7 @@ func (cb *CircuitBreaker) Execute(fn func() error) error {
102102
if cb.state.CompareAndSwap(int32(CircuitBreakerOpen), int32(CircuitBreakerHalfOpen)) {
103103
cb.requests.Store(0)
104104
cb.successes.Store(0)
105-
if internal.LogLevel.InfoOrAbove() {
106-
cb.logf(context.Background(), logs.CircuitBreakerTransitioningToHalfOpen(cb.endpoint))
107-
}
105+
cb.logger().Infof(context.Background(), logs.CircuitBreakerTransitioningToHalfOpen(cb.endpoint))
108106
// Fall through to half-open logic
109107
} else {
110108
return ErrCircuitBreakerOpen
@@ -144,17 +142,13 @@ func (cb *CircuitBreaker) recordFailure() {
144142
case CircuitBreakerClosed:
145143
if failures >= int64(cb.failureThreshold) {
146144
if cb.state.CompareAndSwap(int32(CircuitBreakerClosed), int32(CircuitBreakerOpen)) {
147-
if internal.LogLevel.WarnOrAbove() {
148-
cb.logf(context.Background(), logs.CircuitBreakerOpened(cb.endpoint, failures))
149-
}
145+
cb.logger().Warnf(context.Background(), logs.CircuitBreakerOpened(cb.endpoint, failures))
150146
}
151147
}
152148
case CircuitBreakerHalfOpen:
153149
// Any failure in half-open state immediately opens the circuit
154150
if cb.state.CompareAndSwap(int32(CircuitBreakerHalfOpen), int32(CircuitBreakerOpen)) {
155-
if internal.LogLevel.WarnOrAbove() {
156-
cb.logf(context.Background(), logs.CircuitBreakerReopened(cb.endpoint))
157-
}
151+
cb.logger().Warnf(context.Background(), logs.CircuitBreakerReopened(cb.endpoint))
158152
}
159153
}
160154
}
@@ -176,9 +170,7 @@ func (cb *CircuitBreaker) recordSuccess() {
176170
if successes >= int64(cb.maxRequests) {
177171
if cb.state.CompareAndSwap(int32(CircuitBreakerHalfOpen), int32(CircuitBreakerClosed)) {
178172
cb.failures.Store(0)
179-
if internal.LogLevel.InfoOrAbove() {
180-
cb.logf(context.Background(), logs.CircuitBreakerClosed(cb.endpoint, successes))
181-
}
173+
cb.logger().Infof(context.Background(), logs.CircuitBreakerClosed(cb.endpoint, successes))
182174
}
183175
}
184176
}
@@ -202,12 +194,11 @@ func (cb *CircuitBreaker) GetStats() CircuitBreakerStats {
202194
}
203195
}
204196

205-
func (cb *CircuitBreaker) logf(ctx context.Context, format string, args ...interface{}) {
197+
func (cb *CircuitBreaker) logger() internal.LoggerWithLevel {
206198
if cb.config != nil && cb.config.Logger != nil {
207-
cb.config.Logger.Printf(ctx, format, args...)
208-
} else {
209-
internal.Logger.Printf(ctx, format, args...)
199+
return cb.config.Logger
210200
}
201+
return internal.LegacyLoggerWithLevel
211202
}
212203

213204
// CircuitBreakerStats provides statistics about a circuit breaker
@@ -333,8 +324,8 @@ func (cbm *CircuitBreakerManager) cleanup() {
333324
}
334325

335326
// Log cleanup results
336-
if len(toDelete) > 0 && internal.LogLevel.InfoOrAbove() {
337-
cbm.logf(context.Background(), logs.CircuitBreakerCleanup(len(toDelete), count))
327+
if len(toDelete) > 0 {
328+
cbm.logger().Infof(context.Background(), logs.CircuitBreakerCleanup(len(toDelete), count))
338329
}
339330

340331
cbm.lastCleanup.Store(now.Unix())
@@ -360,10 +351,9 @@ func (cbm *CircuitBreakerManager) Reset() {
360351
})
361352
}
362353

363-
func (cbm *CircuitBreakerManager) logf(ctx context.Context, format string, args ...interface{}) {
354+
func (cbm *CircuitBreakerManager) logger() internal.LoggerWithLevel {
364355
if cbm.config != nil && cbm.config.Logger != nil {
365-
cbm.config.Logger.Printf(ctx, format, args...)
366-
} else {
367-
internal.Logger.Printf(ctx, format, args...)
356+
return cbm.config.Logger
368357
}
358+
return internal.LegacyLoggerWithLevel
369359
}

maintnotifications/config.go

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ type Config struct {
130130
MaxHandoffRetries int
131131

132132
// Logger is an optional custom logger for maintenance notifications.
133-
Logger internal.Logging
133+
Logger internal.LoggerWithLevel
134134
}
135135

136136
func (c *Config) IsEnabled() bool {
@@ -315,10 +315,9 @@ func (c *Config) ApplyDefaultsWithPoolConfig(poolSize int, maxActiveConns int) *
315315
result.CircuitBreakerMaxRequests = c.CircuitBreakerMaxRequests
316316
}
317317

318-
if internal.LogLevel.DebugOrAbove() {
319-
internal.Logger.Printf(context.Background(), logs.DebugLoggingEnabled())
320-
internal.Logger.Printf(context.Background(), logs.ConfigDebug(result))
321-
}
318+
c.logger().Debugf(context.Background(), logs.DebugLoggingEnabled())
319+
c.logger().Debugf(context.Background(), logs.ConfigDebug(result))
320+
322321
return result
323322
}
324323

@@ -370,6 +369,13 @@ func (c *Config) applyWorkerDefaults(poolSize int) {
370369
}
371370
}
372371

372+
func (c *Config) logger() internal.LoggerWithLevel {
373+
if c.Logger != nil {
374+
return c.Logger
375+
}
376+
return internal.LegacyLoggerWithLevel
377+
}
378+
373379
// DetectEndpointType automatically detects the appropriate endpoint type
374380
// based on the connection address and TLS configuration.
375381
//

0 commit comments

Comments
 (0)