improve(go.d/proxysql): add hostgroup summary metrics (#21549)
Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
Ilya Mashchenko committed
Jan 13, 2026 at 06:58 UTC
edffdbe9b06d03999fcb7fb48d381245c6f14bd8
6 files changed
+157
-8
src/go/plugin/go.d/collector/proxysql/cache.go
+20
-3
@@ -4,9 +4,10 @@ package proxysql
4
5
type (
6
cache struct {
7
- commands map[string]*commandCache
8
- users map[string]*userCache
9
- backends map[string]*backendCache
7
+ commands map[string]*commandCache
8
+ users map[string]*userCache
9
+ backends map[string]*backendCache
10
+ hostgroups map[string]*hostgroupCache
11
}
12
commandCache struct {
13
command string
@@ -20,6 +21,10 @@ type (
21
hg, host, port string
22
hasCharts, updated bool
23
}
24
+ hostgroupCache struct {
25
+ hg string
26
+ hasCharts, updated bool
27
+ }
28
)
29
30
func (c *cache) reset() {
@@ -32,6 +37,9 @@ func (c *cache) reset() {
37
for k, m := range c.backends {
38
c.backends[k] = &backendCache{hg: m.hg, host: m.host, port: m.port, hasCharts: m.hasCharts}
39
}
40
+ for k, m := range c.hostgroups {
41
+ c.hostgroups[k] = &hostgroupCache{hg: m.hg, hasCharts: m.hasCharts}
42
+ }
43
}
44
45
func (c *cache) getCommand(command string) *commandCache {
@@ -61,3 +69,12 @@ func (c *cache) getBackend(hg, host, port string) *backendCache {
69
}
70
return v
71
}
72
+
73
+func (c *cache) getHostgroup(hg string) *hostgroupCache {
74
+ v, ok := c.hostgroups[hg]
75
+ if !ok {
76
+ v = &hostgroupCache{hg: hg}
77
+ c.hostgroups[hg] = v
78
+ }
79
+ return v
80
+}
src/go/plugin/go.d/collector/proxysql/charts.go
+58
@@ -44,6 +44,7 @@ const (
44
prioMySQLCommandExecutionDurationHistogram
45
prioMySQLUserConnectionsUtilization
46
prioMySQLUserConnectionsCount
47
+ prioHostgroupStatus
48
prioBackendStatus
49
prioBackendConnectionsUsage
50
prioBackendConnectionsRate
@@ -604,6 +605,62 @@ func (c *Collector) removeMySQLUserCharts(user string) {
605
}
606
}
607
608
+var (
609
+ hostgroupChartsTmpl = module.Charts{
610
+ hostgroupBackendsStatusChartTmpl.Copy(),
611
+ }
612
+
613
+ hostgroupBackendsStatusChartTmpl = module.Chart{
614
+ ID: "hostgroup_%s_backends_status",
615
+ Title: "Hostgroup backends count in each status",
616
+ Units: "backends",
617
+ Fam: "hostgroup backends",
618
+ Ctx: "proxysql.hostgroup_backends_status",
619
+ Priority: prioHostgroupStatus,
620
+ Dims: module.Dims{
621
+ {ID: "hostgroup_%s_backends_ONLINE", Name: "online"},
622
+ {ID: "hostgroup_%s_backends_SHUNNED", Name: "shunned"},
623
+ {ID: "hostgroup_%s_backends_OFFLINE_SOFT", Name: "offline_soft"},
624
+ {ID: "hostgroup_%s_backends_OFFLINE_HARD", Name: "offline_hard"},
625
+ },
626
+ }
627
+)
628
+
629
+func newHostgroupCharts(hg string) *module.Charts {
630
+ charts := hostgroupChartsTmpl.Copy()
631
+
632
+ for _, chart := range *charts {
633
+ chart.ID = fmt.Sprintf(chart.ID, hg)
634
+ chart.Labels = []module.Label{
635
+ {Key: "hostgroup", Value: hg},
636
+ }
637
+ for _, dim := range chart.Dims {
638
+ dim.ID = fmt.Sprintf(dim.ID, hg)
639
+ }
640
+ }
641
+
642
+ return charts
643
+}
644
+
645
+func (c *Collector) addHostgroupCharts(hg string) {
646
+ charts := newHostgroupCharts(hg)
647
+
648
+ if err := c.Charts().Add(*charts...); err != nil {
649
+ c.Warning(err)
650
+ }
651
+}
652
+
653
+func (c *Collector) removeHostgroupCharts(hg string) {
654
+ prefix := "hostgroup_" + hg + "_"
655
+
656
+ for _, chart := range *c.Charts() {
657
+ if strings.HasPrefix(chart.ID, prefix) {
658
+ chart.MarkRemove()
659
+ chart.MarkNotCreated()
660
+ }
661
+ }
662
+}
663
+
664
var (
665
backendChartsTmpl = module.Charts{
666
backendStatusChartTmpl.Copy(),
@@ -695,6 +752,7 @@ func newBackendCharts(hg, host, port string) *module.Charts {
752
for _, chart := range *charts {
753
chart.ID = fmt.Sprintf(chart.ID, backendID(hg, host, port))
754
chart.Labels = []module.Label{
755
+ {Key: "hostgroup", Value: hg},
756
{Key: "host", Value: host},
757
{Key: "port", Value: port},
758
}
src/go/plugin/go.d/collector/proxysql/collect.go
+37
-2
@@ -152,24 +152,48 @@ func (c *Collector) collectStatsMySQLConnectionPool(mx map[string]int64) error {
152
153
var hg, host, port string
154
var px string
155
- return c.doQuery(q, func(column, value string, rowEnd bool) {
155
+ hgStatusCounts := make(map[string]map[string]int64)
156
+ statuses := []string{"ONLINE", "SHUNNED", "OFFLINE_SOFT", "OFFLINE_HARD"}
157
+
158
+ err := c.doQuery(q, func(column, value string, rowEnd bool) {
159
switch column {
160
case "hg", "hostgroup":
161
hg = value
162
+ if _, ok := hgStatusCounts[hg]; !ok {
163
+ hgStatusCounts[hg] = make(map[string]int64)
164
+ for _, st := range statuses {
165
+ hgStatusCounts[hg][st] = 0
166
+ }
167
+ }
168
case "srv_host":
169
host = value
170
case "srv_port":
171
port = value
172
+ c.cache.getHostgroup(hg).updated = true
173
c.cache.getBackend(hg, host, port).updated = true
174
px = "backend_" + backendID(hg, host, port) + "_"
175
case "status":
166
- for _, st := range []string{"ONLINE", "SHUNNED", "OFFLINE_SOFT", "OFFLINE_HARD"} {
176
+ for _, st := range statuses {
177
mx[px+"status_"+st] = metrix.Bool(value == st)
178
}
179
+ hgStatusCounts[hg][value]++
180
default:
181
mx[px+column] = parseInt(value)
182
}
183
})
184
+ if err != nil {
185
+ return err
186
+ }
187
+
188
+ // Set hostgroup backend counts
189
+ for hg, counts := range hgStatusCounts {
190
+ hgPrefix := "hostgroup_" + hg + "_backends_"
191
+ for _, st := range statuses {
192
+ mx[hgPrefix+st] = counts[st]
193
+ }
194
+ }
195
+
196
+ return nil
197
}
198
199
func (c *Collector) updateCharts() {
@@ -206,6 +230,17 @@ func (c *Collector) updateCharts() {
230
c.addBackendCharts(m.hg, m.host, m.port)
231
}
232
}
233
+ for k, m := range c.cache.hostgroups {
234
+ if !m.updated {
235
+ delete(c.cache.hostgroups, k)
236
+ c.removeHostgroupCharts(m.hg)
237
+ continue
238
+ }
239
+ if !m.hasCharts {
240
+ m.hasCharts = true
241
+ c.addHostgroupCharts(m.hg)
242
+ }
243
+ }
244
}
245
246
func (c *Collector) openConnection() error {
src/go/plugin/go.d/collector/proxysql/collector.go
+4
-3
@@ -37,9 +37,10 @@ func New() *Collector {
37
charts: baseCharts.Copy(),
38
once: &sync.Once{},
39
cache: &cache{
40
- commands: make(map[string]*commandCache),
41
- users: make(map[string]*userCache),
42
- backends: make(map[string]*backendCache),
40
+ commands: make(map[string]*commandCache),
41
+ users: make(map[string]*userCache),
42
+ backends: make(map[string]*backendCache),
43
+ hostgroups: make(map[string]*hostgroupCache),
44
},
45
}
46
}
src/go/plugin/go.d/collector/proxysql/collector_test.go
+21
@@ -385,6 +385,26 @@ func TestCollector_Collect(t *testing.T) {
385
"backend_lagging_during_query": 8880,
386
"backend_offline_during_query": 8,
387
"generated_error_packets": 231,
388
+ "hostgroup_10_backends_OFFLINE_HARD": 0,
389
+ "hostgroup_10_backends_OFFLINE_SOFT": 0,
390
+ "hostgroup_10_backends_ONLINE": 1,
391
+ "hostgroup_10_backends_SHUNNED": 0,
392
+ "hostgroup_11_backends_OFFLINE_HARD": 0,
393
+ "hostgroup_11_backends_OFFLINE_SOFT": 0,
394
+ "hostgroup_11_backends_ONLINE": 2,
395
+ "hostgroup_11_backends_SHUNNED": 0,
396
+ "hostgroup_20_backends_OFFLINE_HARD": 0,
397
+ "hostgroup_20_backends_OFFLINE_SOFT": 0,
398
+ "hostgroup_20_backends_ONLINE": 1,
399
+ "hostgroup_20_backends_SHUNNED": 0,
400
+ "hostgroup_21_backends_OFFLINE_HARD": 1,
401
+ "hostgroup_21_backends_OFFLINE_SOFT": 0,
402
+ "hostgroup_21_backends_ONLINE": 0,
403
+ "hostgroup_21_backends_SHUNNED": 0,
404
+ "hostgroup_31_backends_OFFLINE_HARD": 0,
405
+ "hostgroup_31_backends_OFFLINE_SOFT": 1,
406
+ "hostgroup_31_backends_ONLINE": 0,
407
+ "hostgroup_31_backends_SHUNNED": 1,
408
"hostgroup_locked_queries": 0,
409
"hostgroup_locked_set_cmds": 0,
410
"jemalloc_active": 385101824,
@@ -1149,6 +1169,7 @@ func TestCollector_Collect(t *testing.T) {
1169
}
1170
1171
require.Equal(t, expected, mx)
1172
+ module.TestMetricsHasAllChartsDims(t, my.Charts(), mx)
1173
},
1174
},
1175
},
src/go/plugin/go.d/collector/proxysql/metadata.yaml
+17
@@ -389,9 +389,26 @@ modules:
389
chart_type: line
390
dimensions:
391
- name: used
392
+ - name: hostgroup
393
+ description: These metrics refer to the backends hostgroup.
394
+ labels:
395
+ - name: hostgroup
396
+ description: hostgroup identifier
397
+ metrics:
398
+ - name: proxysql.hostgroup_backends_status
399
+ description: Hostgroup backends count in each status
400
+ unit: backends
401
+ chart_type: line
402
+ dimensions:
403
+ - name: online
404
+ - name: shunned
405
+ - name: offline_soft
406
+ - name: offline_hard
407
- name: backend
408
description: These metrics refer to the backend server.
409
labels:
410
+ - name: hostgroup
411
+ description: backend server hostgroup
412
- name: host
413
description: backend server host
414
- name: port