forked from stackimpact/stackimpact-go
/
process_reporter.go
110 lines (91 loc) · 3.28 KB
/
process_reporter.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
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
package internal
import (
"runtime"
"time"
)
type ProcessReporter struct {
agent *Agent
metrics map[string]*Metric
}
func newProcessReporter(agent *Agent) *ProcessReporter {
pr := &ProcessReporter{
agent: agent,
metrics: make(map[string]*Metric),
}
return pr
}
func (pr *ProcessReporter) start() {
go pr.report()
collectTicker := time.NewTicker(1 * time.Minute)
go func() {
defer pr.agent.recoverAndLog()
for {
select {
case <-collectTicker.C:
pr.report()
}
}
}()
}
func (pr *ProcessReporter) reportMetric(typ string, category string, name string, unit string, value float64) *Metric {
key := typ + category + name
var metric *Metric
if existingMetric, exists := pr.metrics[key]; !exists {
metric = newMetric(pr.agent, typ, category, name, unit)
pr.metrics[key] = metric
} else {
metric = existingMetric
}
metric.createMeasurement(TriggerTimer, value, nil)
if metric.hasMeasurement() {
pr.agent.messageQueue.addMessage("metric", metric.toMap())
}
return metric
}
func (pr *ProcessReporter) report() {
cpuTime, err := readCPUTime()
if err == nil {
cpuTimeMetric := pr.reportMetric(TypeCounter, CategoryCPU, NameCPUTime, UnitNanosecond, float64(cpuTime))
if cpuTimeMetric.hasMeasurement() {
cpuUsage := (float64(cpuTimeMetric.measurement.value) / float64(60*1e9)) * 100
cpuUsage = cpuUsage / float64(runtime.NumCPU())
pr.reportMetric(TypeState, CategoryCPU, NameCPUUsage, UnitPercent, float64(cpuUsage))
}
} else {
pr.agent.error(err)
}
maxRSS, err := readMaxRSS()
if err == nil {
pr.reportMetric(TypeState, CategoryMemory, NameMaxRSS, UnitKilobyte, float64(maxRSS))
} else {
pr.agent.error(err)
}
currentRSS, err := readCurrentRSS()
if err == nil {
pr.reportMetric(TypeState, CategoryMemory, NameCurrentRSS, UnitKilobyte, float64(currentRSS))
} else {
pr.agent.error(err)
}
vmSize, err := readVMSize()
if err == nil {
pr.reportMetric(TypeState, CategoryMemory, NameVMSize, UnitKilobyte, float64(vmSize))
} else {
pr.agent.error(err)
}
memStats := &runtime.MemStats{}
runtime.ReadMemStats(memStats)
pr.reportMetric(TypeState, CategoryMemory, NameAllocated, UnitByte, float64(memStats.Alloc))
pr.reportMetric(TypeCounter, CategoryMemory, NameLookups, UnitNone, float64(memStats.Lookups))
pr.reportMetric(TypeCounter, CategoryMemory, NameMallocs, UnitNone, float64(memStats.Mallocs))
pr.reportMetric(TypeCounter, CategoryMemory, NameFrees, UnitNone, float64(memStats.Frees))
pr.reportMetric(TypeState, CategoryMemory, NameHeapIdle, UnitByte, float64(memStats.HeapIdle))
pr.reportMetric(TypeState, CategoryMemory, NameHeapInuse, UnitByte, float64(memStats.HeapInuse))
pr.reportMetric(TypeState, CategoryMemory, NameHeapObjects, UnitNone, float64(memStats.HeapObjects))
pr.reportMetric(TypeCounter, CategoryGC, NameGCTotalPause, UnitNanosecond, float64(memStats.PauseTotalNs))
pr.reportMetric(TypeCounter, CategoryGC, NameNumGC, UnitNone, float64(memStats.NumGC))
pr.reportMetric(TypeState, CategoryGC, NameGCCPUFraction, UnitNone, float64(memStats.GCCPUFraction))
numGoroutine := runtime.NumGoroutine()
pr.reportMetric(TypeState, CategoryRuntime, NameNumGoroutines, UnitNone, float64(numGoroutine))
numCgoCall := runtime.NumCgoCall()
pr.reportMetric(TypeCounter, CategoryRuntime, NameNumCgoCalls, UnitNone, float64(numCgoCall))
}