@cryptotaxi247 / netdata-1 / commits / edffdbe9b

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