Skip to content

Commit 30bad6d

Browse files
jonyoderclaude
andcommitted
Log cluster integrity degrade/recover transitions at INFO
Surface the onset and recovery of an unhealthy episode once at INFO so they appear in default logs for customer escalations, while keeping per-tick detail at debug to avoid noise on routine self-healing mismatches. Sustained failures still escalate to error (when step-down is enabled). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent 733396b commit 30bad6d

1 file changed

Lines changed: 14 additions & 11 deletions

File tree

pkg/rselection/impls/pgx/leader.go

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -277,29 +277,32 @@ func (p *PgxLeader) clusterIntegrityErr() error {
277277
func (p *PgxLeader) evaluateHealth() bool {
278278
err := p.clusterIntegrityErr()
279279
if err == nil {
280+
if !p.unhealthySince.IsZero() {
281+
slog.Info("Cluster integrity recovered", "degradedFor", p.timeNow().Sub(p.unhealthySince))
282+
}
280283
p.unhealthySince = time.Time{}
281284
return false
282285
}
283286

287+
// Log the onset of an unhealthy episode once, at INFO, so it appears in
288+
// default logs (and is available for a customer escalation) without raising
289+
// the log level. Per-tick detail stays at debug to avoid noise on routine,
290+
// self-healing mismatches such as a rolling restart. A sustained failure
291+
// escalates to error, but only when step-down is enabled: a disabled leader
292+
// takes no recovery action and would otherwise log error every tick forever.
284293
if p.unhealthySince.IsZero() {
285294
p.unhealthySince = p.timeNow()
295+
slog.Info("Cluster integrity check failing", "error", err)
286296
}
287297
dur := p.timeNow().Sub(p.unhealthySince)
288298

289-
// Treat brief mismatches (e.g., a rolling restart) as routine; escalate only
290-
// once the condition is sustained. When step-down is disabled, stay at debug
291-
// to avoid per-tick error spam since no recovery action will be taken.
292-
switch {
293-
case p.stepDownTimeout == 0:
299+
if p.stepDownTimeout > 0 && dur >= p.stepDownTimeout/2 {
300+
slog.Error("Cluster integrity check still failing", "error", err, "unhealthyFor", dur)
301+
} else {
294302
slog.Debug("Cluster integrity check failing", "error", err, "unhealthyFor", dur)
295-
return false
296-
case dur < p.stepDownTimeout/2:
297-
slog.Debug("Cluster integrity check failing; may be transient", "error", err, "unhealthyFor", dur)
298-
default:
299-
slog.Error("Cluster integrity check failing", "error", err, "unhealthyFor", dur)
300303
}
301304

302-
return dur >= p.stepDownTimeout
305+
return p.stepDownTimeout > 0 && dur >= p.stepDownTimeout
303306
}
304307

305308
// verify gates a scheduled task on cluster health. It responds true on the

0 commit comments

Comments
 (0)