mirror of
https://github.com/open-cluster-management-io/ocm.git
synced 2026-05-12 20:28:54 +00:00
94 lines
2.6 KiB
Go
94 lines
2.6 KiB
Go
package serviceability
|
|
|
|
import (
|
|
"encoding/json"
|
|
"strings"
|
|
"time"
|
|
|
|
"k8s.io/klog"
|
|
|
|
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
|
|
"k8s.io/apimachinery/pkg/version"
|
|
)
|
|
|
|
// BehaviorOnPanic is a helper for setting the crash mode of OpenShift when a panic is caught.
|
|
// It returns a function that should be the defer handler for the caller.
|
|
func BehaviorOnPanic(modeString string, productVersion version.Info) func() {
|
|
modes := []string{}
|
|
if err := json.Unmarshal([]byte(modeString), &modes); err != nil {
|
|
return behaviorOnPanic(modeString, productVersion)
|
|
}
|
|
|
|
fns := []func(){}
|
|
|
|
for _, mode := range modes {
|
|
fns = append(fns, behaviorOnPanic(mode, productVersion))
|
|
}
|
|
|
|
return func() {
|
|
for _, fn := range fns {
|
|
fn()
|
|
}
|
|
}
|
|
}
|
|
|
|
func behaviorOnPanic(mode string, productVersion version.Info) func() {
|
|
doNothing := func() {}
|
|
|
|
switch {
|
|
case mode == "crash":
|
|
klog.Infof("Process will terminate as soon as a panic occurs.")
|
|
utilruntime.ReallyCrash = true
|
|
return doNothing
|
|
|
|
case strings.HasPrefix(mode, "crash-after-delay:"):
|
|
delayDurationString := strings.TrimPrefix(mode, "crash-after-delay:")
|
|
delayDuration, err := time.ParseDuration(delayDurationString)
|
|
if err != nil {
|
|
klog.Errorf("Unable to start crash-after-delay. Crashing immediately instead: %v", err)
|
|
utilruntime.ReallyCrash = true
|
|
return doNothing
|
|
}
|
|
klog.Infof("Process will terminate %v after a panic occurs.", delayDurationString)
|
|
utilruntime.ReallyCrash = false
|
|
utilruntime.PanicHandlers = append(utilruntime.PanicHandlers, crashOnDelay(delayDuration, delayDurationString))
|
|
return doNothing
|
|
|
|
case strings.HasPrefix(mode, "sentry:"):
|
|
url := strings.TrimPrefix(mode, "sentry:")
|
|
m, err := NewSentryMonitor(url, productVersion)
|
|
if err != nil {
|
|
klog.Errorf("Unable to start Sentry for panic tracing: %v", err)
|
|
return doNothing
|
|
}
|
|
klog.Infof("Process will log all panics and errors to Sentry.")
|
|
utilruntime.ReallyCrash = false
|
|
utilruntime.PanicHandlers = append(utilruntime.PanicHandlers, m.CapturePanic)
|
|
utilruntime.ErrorHandlers = append(utilruntime.ErrorHandlers, m.CaptureError)
|
|
return func() {
|
|
if r := recover(); r != nil {
|
|
m.CapturePanicAndWait(r, 2*time.Second)
|
|
panic(r)
|
|
}
|
|
}
|
|
case len(mode) == 0:
|
|
// default panic behavior
|
|
utilruntime.ReallyCrash = false
|
|
return doNothing
|
|
|
|
default:
|
|
klog.Errorf("Unrecognized panic behavior")
|
|
return doNothing
|
|
}
|
|
}
|
|
|
|
func crashOnDelay(delay time.Duration, delayString string) func(interface{}) {
|
|
return func(in interface{}) {
|
|
go func() {
|
|
klog.Errorf("Panic happened. Process will crash in %v.", delayString)
|
|
time.Sleep(delay)
|
|
panic(in)
|
|
}()
|
|
}
|
|
}
|