-
Notifications
You must be signed in to change notification settings - Fork 205
/
Copy pathgoRoutinesAnalyser.go
93 lines (76 loc) · 2.71 KB
/
goRoutinesAnalyser.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
87
88
89
90
91
92
93
package goroutine
import (
"regexp"
"runtime"
"sort"
"strings"
"time"
"github.com/ElrondNetwork/elrond-go-core/core"
"github.com/ElrondNetwork/elrond-go-core/core/check"
logger "github.com/ElrondNetwork/elrond-go-logger"
"github.com/ElrondNetwork/elrond-go/debug"
)
var log = logger.GetOrCreate("goroutine")
const (
newRoutine = "new"
oldRoutine = "old"
)
type goRoutinesAnalyser struct {
goRoutinesProcessor debug.GoRoutinesProcessor
goRoutinesData map[string]debug.GoRoutineHandlerMap
}
// NewGoRoutinesAnalyser creates a new structure for go routine statistics analysis
func NewGoRoutinesAnalyser(processor debug.GoRoutinesProcessor) (*goRoutinesAnalyser, error) {
if check.IfNil(processor) {
return nil, core.ErrNilGoRoutineProcessor
}
emptyData := make(map[string]debug.GoRoutineHandlerMap)
emptyData[newRoutine] = make(debug.GoRoutineHandlerMap)
emptyData[oldRoutine] = make(debug.GoRoutineHandlerMap)
return &goRoutinesAnalyser{
goRoutinesProcessor: processor,
goRoutinesData: emptyData,
}, nil
}
// DumpGoRoutinesToLogWithTypes will print the currently running go routines stats in the log
func (grd *goRoutinesAnalyser) DumpGoRoutinesToLogWithTypes() {
buffer := core.GetRunningGoRoutines(log)
log.Debug("GoRoutinesAnalyser - DumpGoRoutinesToLogWithTypes", "goroutines number", runtime.NumGoroutine())
newData := grd.goRoutinesProcessor.ProcessGoRoutineBuffer(grd.goRoutinesData, buffer)
dumpGoRoutinesDataToLog(newData)
grd.goRoutinesData = newData
}
func dumpGoRoutinesDataToLog(latestData map[string]debug.GoRoutineHandlerMap) {
oldRoutines := latestData[oldRoutine]
goRoutines := make([]debug.GoRoutineHandler, 0)
for _, val := range oldRoutines {
goRoutines = append(goRoutines, val)
}
sort.Slice(goRoutines, func(i, j int) bool {
if goRoutines[i].FirstOccurrence().Equal(goRoutines[j].FirstOccurrence()) {
return goRoutines[i].ID() < goRoutines[j].ID()
}
return goRoutines[i].FirstOccurrence().Before(goRoutines[j].FirstOccurrence())
})
currentTime := time.Now()
for _, gr := range goRoutines {
runningTime := currentTime.Sub(gr.FirstOccurrence())
if runningTime > time.Hour {
log.Debug("remaining goroutine - more than an hour", "ID", gr.ID(), "running seconds", runningTime)
continue
}
log.Debug("remaining goroutine", "ID", gr.ID(), "running seconds", runningTime)
}
for _, val := range latestData[newRoutine] {
log.Debug("new goroutine", "ID", val.ID(), "\nData", val.StackTrace())
}
}
func getGoroutineId(goroutineString string) string {
rg := regexp.MustCompile(`goroutine \d+`)
matches := rg.FindAllString(goroutineString, 1)
for _, element := range matches {
replaced := strings.ReplaceAll(element, "goroutine ", "")
return replaced
}
return ""
}