/
panic.go
86 lines (78 loc) · 1.78 KB
/
panic.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
package utils
import (
"runtime"
"encoding/json"
"fmt"
"github.com/breezedup/goserver/core/logger"
"sync"
"sync/atomic"
"time"
)
var _panicStackMgr = &PanicStackMgr{
items: make(map[string]*PanicStackInfo),
}
type PanicStackMgr struct {
sync.RWMutex
items map[string]*PanicStackInfo
}
type PanicStackInfo struct {
FirstTime time.Time
LastTime time.Time
Times int64
ErrorMsg string
StackBuf string
}
func DumpStackIfPanic(f string) {
if err := recover(); err != nil {
defer func() { //防止二次panic
if err := recover(); err != nil {
logger.Logger.Error(f, " panic.panic,error=", err)
}
}()
logger.Logger.Error(f, " panic,error=", err)
errMsg := fmt.Sprintf("%v", err)
var buf [4096]byte
n := runtime.Stack(buf[:], false)
logger.Logger.Error("stack--->", string(buf[:n]))
stk := make([]uintptr, 32)
m := runtime.Callers(0, stk[:])
stk = stk[:m]
if len(stk) > 0 {
d, err := json.Marshal(stk)
if err == nil && len(d) > 0 {
key := string(d)
_panicStackMgr.Lock()
defer _panicStackMgr.Unlock()
tNow := time.Now()
if ps, exist := _panicStackMgr.items[key]; exist {
atomic.AddInt64(&ps.Times, 1)
ps.LastTime = tNow
} else {
ps = &PanicStackInfo{
ErrorMsg: errMsg,
Times: 1,
StackBuf: string(buf[:n]),
FirstTime: tNow,
LastTime: tNow,
}
_panicStackMgr.items[key] = ps
}
}
}
}
}
func DumpStack(f string) {
logger.Logger.Error(f)
var buf [4096]byte
len := runtime.Stack(buf[:], false)
logger.Logger.Error("stack--->", string(buf[:len]))
}
func GetPanicStats() map[string]PanicStackInfo {
stats := make(map[string]PanicStackInfo)
_panicStackMgr.RLock()
defer _panicStackMgr.RUnlock()
for k, v := range _panicStackMgr.items {
stats[k] = *v
}
return stats
}