OSDN Git Service

dbb3b63d3b62b296c78e0ddef4311665654a22c5
[bytom/vapor.git] / toolbar / measure / method.go
1 package measure
2
3 import (
4         "fmt"
5         "runtime/debug"
6         "strings"
7         "sync"
8
9         log "github.com/sirupsen/logrus"
10 )
11
12 const (
13         logModule = "measure"
14 )
15
16 var store sync.Map
17
18 // Start trigger record of stack trace run time record as a graph view
19 func Start() {
20         routineID, stacks, err := traceStacks()
21         if err != nil {
22                 log.WithFields(log.Fields{"module": logModule, "err": err}).Error("fail on measure get stacks")
23                 return
24         }
25
26         data, ok := store.Load(routineID)
27         if !ok {
28                 store.Store(routineID, NewTimer(stacks[0]))
29                 return
30         }
31
32         if err := data.(*Timer).StartTimer(stacks); err != nil {
33                 log.WithFields(log.Fields{"module": logModule, "err": err, "routine": routineID, "stack": stacks}).Error("fail on start timer")
34         }
35 }
36
37 // End end the stack trace run time
38 func End() {
39         routineID, stacks, err := traceStacks()
40         if err != nil {
41                 log.WithFields(log.Fields{"module": logModule, "err": err}).Error("fail on measure get stacks")
42                 return
43         }
44
45         data, ok := store.Load(routineID)
46         if !ok {
47                 log.WithFields(log.Fields{"module": logModule, "err": err}).Error("fail on measure timer by routine ID")
48                 return
49         }
50
51         rootTimer := data.(*Timer)
52         if err := rootTimer.EndTimer(stacks); err != nil {
53                 log.WithFields(log.Fields{"module": logModule, "err": err, "routine": routineID, "stack": stacks}).Error("fail on end timer")
54         }
55
56         if rootTimer.IsEnd() {
57                 log.WithField("module", logModule).Info(rootTimer.String())
58                 store.Delete(routineID)
59         }
60 }
61
62 func traceStacks() (string, []string, error) {
63         stacks := []string{}
64         for _, stack := range strings.Split(string(debug.Stack()), "\n") {
65                 // skip the file path stack
66                 if strings.HasPrefix(stack, "   ") {
67                         continue
68                 }
69
70                 // delete the func memory address stuff
71                 if subPos := strings.LastIndexAny(stack, "("); subPos > 0 {
72                         stacks = append(stacks, stack[:subPos])
73                 } else {
74                         stacks = append(stacks, stack)
75                 }
76         }
77
78         if len(stacks) < 4 {
79                 return "", nil, fmt.Errorf("fail to decode stack")
80         }
81
82         return stacks[0], stacks[4:], nil
83 }