@@ -20,9 +20,13 @@ const (
2020
2121// metricsRecorder implements the otel.Recorder interface
2222type metricsRecorder struct {
23- operationDuration metric.Float64Histogram
24- connectionCount metric.Int64UpDownCounter
25- connectionCreateTime metric.Float64Histogram
23+ operationDuration metric.Float64Histogram
24+ connectionCount metric.Int64UpDownCounter
25+ connectionCreateTime metric.Float64Histogram
26+ connectionRelaxedTimeout metric.Int64UpDownCounter
27+ connectionHandoff metric.Int64Counter
28+ clientErrors metric.Int64Counter
29+ maintenanceNotifications metric.Int64Counter
2630
2731 // Client configuration for attributes (used for operation metrics only)
2832 serverAddr string
@@ -54,7 +58,7 @@ func (r *metricsRecorder) RecordOperationDuration(
5458 attribute .Bool ("redis.client.operation.blocking" , isBlockingCommand (cmd )),
5559
5660 // Recommended attributes
57- attribute .String ("db.system" , "redis" ),
61+ attribute .String ("db.system.name " , "redis" ),
5862 attribute .String ("server.address" , r .serverAddr ),
5963 }
6064
@@ -326,6 +330,12 @@ func extractServerInfo(cn redis.ConnInfo) (addr, port string) {
326330 return host , portStr
327331}
328332
333+ // extractPeerInfo extracts peer network address and port from connection info
334+ // For client connections, this is the same as the server address (remote endpoint)
335+ func extractPeerInfo (cn redis.ConnInfo ) (addr , port string ) {
336+ return extractServerInfo (cn )
337+ }
338+
329339// RecordConnectionCreateTime records the time it took to create a new connection
330340func (r * metricsRecorder ) RecordConnectionCreateTime (
331341 ctx context.Context ,
@@ -364,3 +374,154 @@ func (r *metricsRecorder) RecordConnectionCreateTime(
364374 // Record the histogram
365375 r .connectionCreateTime .Record (ctx , durationSeconds , metric .WithAttributes (attrs ... ))
366376}
377+
378+ // RecordConnectionRelaxedTimeout records when connection timeout is relaxed/unrelaxed
379+ func (r * metricsRecorder ) RecordConnectionRelaxedTimeout (
380+ ctx context.Context ,
381+ delta int ,
382+ cn redis.ConnInfo ,
383+ poolName , notificationType string ,
384+ ) {
385+ if r .connectionRelaxedTimeout == nil {
386+ return
387+ }
388+
389+ // Extract server address from connection
390+ serverAddr , serverPort := extractServerInfo (cn )
391+
392+ // Build attributes
393+ attrs := []attribute.KeyValue {
394+ attribute .String ("db.system.name" , "redis" ),
395+ attribute .String ("server.address" , serverAddr ),
396+ attribute .String ("redis.client.library" , fmt .Sprintf ("%s:%s" , libraryName , redis .Version ())),
397+ attribute .String ("db.client.connection.pool.name" , poolName ),
398+ attribute .String ("redis.client.connection.notification" , notificationType ),
399+ }
400+
401+ // Add server.port if not default
402+ if serverPort != "" && serverPort != "6379" {
403+ attrs = append (attrs , attribute .String ("server.port" , serverPort ))
404+ }
405+
406+ // Record the counter (delta can be +1 or -1)
407+ r .connectionRelaxedTimeout .Add (ctx , int64 (delta ), metric .WithAttributes (attrs ... ))
408+ }
409+
410+ // RecordConnectionHandoff records when a connection is handed off to another node
411+ func (r * metricsRecorder ) RecordConnectionHandoff (
412+ ctx context.Context ,
413+ cn redis.ConnInfo ,
414+ poolName string ,
415+ ) {
416+ if r .connectionHandoff == nil {
417+ return
418+ }
419+
420+ // Extract server address from connection
421+ serverAddr , serverPort := extractServerInfo (cn )
422+
423+ // Build attributes
424+ attrs := []attribute.KeyValue {
425+ attribute .String ("db.system" , "redis" ),
426+ attribute .String ("server.address" , serverAddr ),
427+ attribute .String ("redis.client.library" , fmt .Sprintf ("%s:%s" , libraryName , redis .Version ())),
428+ attribute .String ("db.client.connection.pool.name" , poolName ),
429+ }
430+
431+ // Add server.port if not default
432+ if serverPort != "" && serverPort != "6379" {
433+ attrs = append (attrs , attribute .String ("server.port" , serverPort ))
434+ }
435+
436+ // Record the counter
437+ r .connectionHandoff .Add (ctx , 1 , metric .WithAttributes (attrs ... ))
438+ }
439+
440+ // RecordError records client errors (ASK, MOVED, handshake failures, etc.)
441+ func (r * metricsRecorder ) RecordError (
442+ ctx context.Context ,
443+ errorType string ,
444+ cn redis.ConnInfo ,
445+ statusCode string ,
446+ isInternal bool ,
447+ retryAttempts int ,
448+ ) {
449+ if r .clientErrors == nil {
450+ return
451+ }
452+
453+ // Extract server address and peer address from connection (may be nil for some errors)
454+ var serverAddr , serverPort , peerAddr , peerPort string
455+ if cn != nil {
456+ serverAddr , serverPort = extractServerInfo (cn )
457+ peerAddr , peerPort = extractPeerInfo (cn )
458+ }
459+
460+ // Build attributes
461+ attrs := []attribute.KeyValue {
462+ attribute .String ("db.system.name" , "redis" ),
463+ attribute .String ("error.type" , errorType ),
464+ attribute .String ("db.response.status_code" , statusCode ),
465+ attribute .Bool ("redis.client.errors.internal" , isInternal ),
466+ attribute .Int ("redis.client.operation.retry_attempts" , retryAttempts ),
467+ attribute .String ("redis.client.library" , fmt .Sprintf ("%s:%s" , libraryName , redis .Version ())),
468+ }
469+
470+ // Add server info if available
471+ if serverAddr != "" {
472+ attrs = append (attrs , attribute .String ("server.address" , serverAddr ))
473+ if serverPort != "" && serverPort != "6379" {
474+ attrs = append (attrs , attribute .String ("server.port" , serverPort ))
475+ }
476+ }
477+
478+ // Add peer info if available
479+ if peerAddr != "" {
480+ attrs = append (attrs , attribute .String ("network.peer.address" , peerAddr ))
481+ if peerPort != "" {
482+ attrs = append (attrs , attribute .String ("network.peer.port" , peerPort ))
483+ }
484+ }
485+
486+ // Record the counter
487+ r .clientErrors .Add (ctx , 1 , metric .WithAttributes (attrs ... ))
488+ }
489+
490+ // RecordMaintenanceNotification records when a maintenance notification is received
491+ func (r * metricsRecorder ) RecordMaintenanceNotification (
492+ ctx context.Context ,
493+ cn redis.ConnInfo ,
494+ notificationType string ,
495+ ) {
496+ if r .maintenanceNotifications == nil {
497+ return
498+ }
499+
500+ // Extract server address and peer address from connection
501+ serverAddr , serverPort := extractServerInfo (cn )
502+ peerAddr , peerPort := extractPeerInfo (cn )
503+
504+ // Build attributes
505+ attrs := []attribute.KeyValue {
506+ attribute .String ("db.system.name" , "redis" ),
507+ attribute .String ("server.address" , serverAddr ),
508+ attribute .String ("redis.client.library" , fmt .Sprintf ("%s:%s" , libraryName , redis .Version ())),
509+ attribute .String ("redis.client.connection.notification" , notificationType ),
510+ }
511+
512+ // Add server.port if not default
513+ if serverPort != "" && serverPort != "6379" {
514+ attrs = append (attrs , attribute .String ("server.port" , serverPort ))
515+ }
516+
517+ // Add peer info if available
518+ if peerAddr != "" {
519+ attrs = append (attrs , attribute .String ("network.peer.address" , peerAddr ))
520+ if peerPort != "" {
521+ attrs = append (attrs , attribute .String ("network.peer.port" , peerPort ))
522+ }
523+ }
524+
525+ // Record the counter
526+ r .maintenanceNotifications .Add (ctx , 1 , metric .WithAttributes (attrs ... ))
527+ }
0 commit comments