1
1
package serviceability
2
2
3
3
import (
4
+ "encoding/json"
4
5
"strings"
5
6
"time"
6
7
7
8
"github.com/golang/glog"
9
+
8
10
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
9
11
)
10
12
11
13
// BehaviorOnPanic is a helper for setting the crash mode of OpenShift when a panic is caught.
12
14
// It returns a function that should be the defer handler for the caller.
13
- func BehaviorOnPanic (mode string ) (fn func ()) {
14
- fn = func () {}
15
+ func BehaviorOnPanic (modeString string ) func () {
16
+ modes := []string {}
17
+ if err := json .Unmarshal ([]byte (modeString ), & modes ); err != nil {
18
+ return behaviorOnPanic (modeString )
19
+ }
20
+
21
+ fns := []func (){}
22
+
23
+ for _ , mode := range modes {
24
+ fns = append (fns , behaviorOnPanic (mode ))
25
+ }
26
+
27
+ return func () {
28
+ for _ , fn := range fns {
29
+ fn ()
30
+ }
31
+ }
32
+ }
33
+
34
+ func behaviorOnPanic (mode string ) func () {
35
+ doNothing := func () {}
36
+
15
37
switch {
16
38
case mode == "crash" :
17
39
glog .Infof ("Process will terminate as soon as a panic occurs." )
18
40
utilruntime .ReallyCrash = true
41
+ return doNothing
42
+
43
+ case strings .HasPrefix (mode , "crash-after-delay:" ):
44
+ delayDurationString := strings .TrimPrefix (mode , "crash-after-delay:" )
45
+ delayDuration , err := time .ParseDuration (delayDurationString )
46
+ if err != nil {
47
+ glog .Errorf ("Unable to start crash-after-delay. Crashing immediately instead: %v" , err )
48
+ utilruntime .ReallyCrash = true
49
+ return doNothing
50
+ }
51
+ glog .Infof ("Process will terminate %v after a panic occurs." , delayDurationString )
52
+ utilruntime .ReallyCrash = false
53
+ utilruntime .PanicHandlers = append (utilruntime .PanicHandlers , crashOnDelay (delayDuration , delayDurationString ))
54
+ return doNothing
55
+
19
56
case strings .HasPrefix (mode , "sentry:" ):
20
57
url := strings .TrimPrefix (mode , "sentry:" )
21
58
m , err := NewSentryMonitor (url )
22
59
if err != nil {
23
60
glog .Errorf ("Unable to start Sentry for panic tracing: %v" , err )
24
- return
61
+ return doNothing
25
62
}
26
63
glog .Infof ("Process will log all panics and errors to Sentry." )
27
64
utilruntime .ReallyCrash = false
28
65
utilruntime .PanicHandlers = append (utilruntime .PanicHandlers , m .CapturePanic )
29
66
utilruntime .ErrorHandlers = append (utilruntime .ErrorHandlers , m .CaptureError )
30
- fn = func () {
67
+ return func () {
31
68
if r := recover (); r != nil {
32
69
m .CapturePanicAndWait (r , 2 * time .Second )
33
70
panic (r )
@@ -36,8 +73,20 @@ func BehaviorOnPanic(mode string) (fn func()) {
36
73
case len (mode ) == 0 :
37
74
// default panic behavior
38
75
utilruntime .ReallyCrash = false
76
+ return doNothing
77
+
39
78
default :
40
79
glog .Errorf ("Unrecognized panic behavior" )
80
+ return doNothing
81
+ }
82
+ }
83
+
84
+ func crashOnDelay (delay time.Duration , delayString string ) func (interface {}) {
85
+ return func (in interface {}) {
86
+ go func () {
87
+ glog .Errorf ("Panic happened. Process will crash in %v." , delayString )
88
+ time .Sleep (delay )
89
+ panic (in )
90
+ }()
41
91
}
42
- return
43
92
}
0 commit comments