-
Notifications
You must be signed in to change notification settings - Fork 13
/
xml_stats_v3.go
161 lines (138 loc) · 4.34 KB
/
xml_stats_v3.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
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
package bind
import (
"encoding/xml"
"fmt"
"net"
"net/http"
"net/url"
"strings"
"time"
"github.com/circonus-labs/circonus-unified-agent/cua"
"github.com/circonus-labs/circonus-unified-agent/metric"
)
// XML path: //statistics
// Omitted branches: socketmgr, taskmgr
type v3Stats struct {
Server v3Server `xml:"server"`
Views []v3View `xml:"views>view"`
Memory v3Memory `xml:"memory"`
}
// XML path: //statistics/memory
type v3Memory struct {
Contexts []struct {
// Omitted nodes: references, maxinuse, blocksize, pools, hiwater, lowater
ID string `xml:"id"`
Name string `xml:"name"`
Total int64 `xml:"total"`
InUse int64 `xml:"inuse"`
} `xml:"contexts>context"`
Summary struct {
TotalUse int64
InUse int64
BlockSize int64
ContextSize int64
Lost int64
} `xml:"summary"`
}
// XML path: //statistics/server
type v3Server struct {
CounterGroups []v3CounterGroup `xml:"counters"`
}
// XML path: //statistics/views/view
type v3View struct {
// Omitted branches: zones
Name string `xml:"name,attr"`
CounterGroups []v3CounterGroup `xml:"counters"`
Caches []struct {
Name string `xml:"name,attr"`
RRSets []struct {
Name string `xml:"name"`
Value int64 `xml:"counter"`
} `xml:"rrset"`
} `xml:"cache"`
}
// Generic XML v3 doc fragment used in multiple places
type v3CounterGroup struct {
Type string `xml:"type,attr"`
Counters []struct {
Name string `xml:"name,attr"`
Value int64 `xml:",chardata"`
} `xml:"counter"`
}
// addStatsXMLv3 walks a v3Stats struct and adds the values to the cua.Accumulator.
func (b *Bind) addStatsXMLv3(stats v3Stats, acc cua.Accumulator, hostPort string) {
grouper := metric.NewSeriesGrouper()
ts := time.Now()
host, port, _ := net.SplitHostPort(hostPort)
// Counter groups
for _, cg := range stats.Server.CounterGroups {
for _, c := range cg.Counters {
if cg.Type == "opcode" && strings.HasPrefix(c.Name, "RESERVED") {
continue
}
tags := map[string]string{"url": hostPort, "source": host, "port": port, "type": cg.Type}
_ = grouper.Add("bind_counter", tags, ts, c.Name, c.Value)
}
}
// Memory stats
fields := map[string]interface{}{
"total_use": stats.Memory.Summary.TotalUse,
"in_use": stats.Memory.Summary.InUse,
"block_size": stats.Memory.Summary.BlockSize,
"context_size": stats.Memory.Summary.ContextSize,
"lost": stats.Memory.Summary.Lost,
}
acc.AddGauge("bind_memory", fields, map[string]string{"url": hostPort, "source": host, "port": port})
// Detailed, per-context memory stats
if b.GatherMemoryContexts {
for _, c := range stats.Memory.Contexts {
tags := map[string]string{"url": hostPort, "source": host, "port": port, "id": c.ID, "name": c.Name}
fields := map[string]interface{}{"total": c.Total, "in_use": c.InUse}
acc.AddGauge("bind_memory_context", fields, tags)
}
}
// Detailed, per-view stats
if b.GatherViews {
for _, v := range stats.Views {
for _, cg := range v.CounterGroups {
for _, c := range cg.Counters {
tags := map[string]string{
"url": hostPort,
"source": host,
"port": port,
"view": v.Name,
"type": cg.Type,
}
_ = grouper.Add("bind_counter", tags, ts, c.Name, c.Value)
}
}
}
}
// Add grouped metrics
for _, metric := range grouper.Metrics() {
acc.AddMetric(metric)
}
}
// readStatsXMLv3 takes a base URL to probe, and requests the individual statistics documents that
// we are interested in. These individual documents have a combined size which is significantly
// smaller than if we requested everything at once (e.g. taskmgr and socketmgr can be omitted).
func (b *Bind) readStatsXMLv3(addr *url.URL, acc cua.Accumulator) error {
var stats v3Stats
// Progressively build up full v3Stats struct by parsing the individual HTTP responses
for _, suffix := range [...]string{"/server", "/net", "/mem"} {
scrapeURL := addr.String() + suffix
resp, err := client.Get(scrapeURL)
if err != nil {
return fmt.Errorf("http get (%s): %w", scrapeURL, err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return fmt.Errorf("%s returned HTTP status: %s", scrapeURL, resp.Status)
}
if err := xml.NewDecoder(resp.Body).Decode(&stats); err != nil {
return fmt.Errorf("Unable to decode XML document: %w", err)
}
}
b.addStatsXMLv3(stats, acc, addr.Host)
return nil
}