| 1 | // SPDX-License-Identifier: GPL-3.0-or-later |
| 2 | |
| 3 | package maxscale |
| 4 | |
| 5 | import ( |
| 6 | "fmt" |
| 7 | "strings" |
| 8 | |
| 9 | "github.com/netdata/netdata/go/plugins/plugin/framework/collectorapi" |
| 10 | ) |
| 11 | |
| 12 | const ( |
| 13 | prioPollEvents = collectorapi.Priority + iota |
| 14 | |
| 15 | prioSessions |
| 16 | prioZombies |
| 17 | |
| 18 | prioServerState |
| 19 | prioServerConnections |
| 20 | |
| 21 | prioThreadsByState |
| 22 | |
| 23 | prioCurrentFDs |
| 24 | |
| 25 | prioQCCacheEfficiency |
| 26 | prioQCCacheOperations |
| 27 | |
| 28 | prioUptime |
| 29 | ) |
| 30 | |
| 31 | var charts = collectorapi.Charts{ |
| 32 | pollEventsChart.Copy(), |
| 33 | currentSessionsChart.Copy(), |
| 34 | currentZombieConnectionsChart.Copy(), |
| 35 | threadsByStateChart.Copy(), |
| 36 | currentFDsChart.Copy(), |
| 37 | qcCacheEfficiencyChart.Copy(), |
| 38 | qcCacheOperationsChart.Copy(), |
| 39 | uptimeChart.Copy(), |
| 40 | } |
| 41 | |
| 42 | var ( |
| 43 | pollEventsChart = collectorapi.Chart{ |
| 44 | ID: "poll_events", |
| 45 | Title: "Poll Events", |
| 46 | Units: "events/s", |
| 47 | Fam: "poll events", |
| 48 | Ctx: "maxscale.poll_events", |
| 49 | Priority: prioPollEvents, |
| 50 | Dims: collectorapi.Dims{ |
| 51 | {ID: "threads_reads", Name: "reads", Algo: collectorapi.Incremental}, |
| 52 | {ID: "threads_writes", Name: "writes", Algo: collectorapi.Incremental}, |
| 53 | {ID: "threads_accepts", Name: "accepts", Algo: collectorapi.Incremental}, |
| 54 | {ID: "threads_errors", Name: "errors", Algo: collectorapi.Incremental}, |
| 55 | {ID: "threads_hangups", Name: "hangups", Algo: collectorapi.Incremental}, |
| 56 | }, |
| 57 | } |
| 58 | |
| 59 | currentSessionsChart = collectorapi.Chart{ |
| 60 | ID: "current_sessions", |
| 61 | Title: "Curren Sessions", |
| 62 | Units: "sessions", |
| 63 | Fam: "sessions", |
| 64 | Ctx: "maxscale.current_sessions", |
| 65 | Priority: prioSessions, |
| 66 | Dims: collectorapi.Dims{ |
| 67 | {ID: "threads_sessions", Name: "sessions"}, |
| 68 | }, |
| 69 | } |
| 70 | currentZombieConnectionsChart = collectorapi.Chart{ |
| 71 | ID: "current_zombie_connections", |
| 72 | Title: "Current Zombie Connections", |
| 73 | Units: "connections", |
| 74 | Fam: "sessions", |
| 75 | Ctx: "maxscale.current_zombie_connections", |
| 76 | Priority: prioZombies, |
| 77 | Dims: collectorapi.Dims{ |
| 78 | {ID: "threads_zombies", Name: "zombie"}, |
| 79 | }, |
| 80 | } |
| 81 | |
| 82 | threadsByStateChart = func() collectorapi.Chart { |
| 83 | chart := collectorapi.Chart{ |
| 84 | ID: "threads_by_state", |
| 85 | Title: "Threads Count by State", |
| 86 | Units: "threads", |
| 87 | Fam: "threads", |
| 88 | Ctx: "maxscale.threads_by_state", |
| 89 | Priority: prioThreadsByState, |
| 90 | Type: collectorapi.Stacked, |
| 91 | } |
| 92 | for _, v := range threadStates { |
| 93 | chart.Dims = append(chart.Dims, &collectorapi.Dim{ |
| 94 | ID: "threads_state_" + v, |
| 95 | Name: strings.ToLower(v), |
| 96 | }) |
| 97 | } |
| 98 | return chart |
| 99 | }() |
| 100 | |
| 101 | currentFDsChart = collectorapi.Chart{ |
| 102 | ID: "current_file_descriptors", |
| 103 | Title: "Current Managed File Descriptors", |
| 104 | Units: "fds", |
| 105 | Fam: "fds", |
| 106 | Ctx: "maxscale.current_fds", |
| 107 | Priority: prioCurrentFDs, |
| 108 | Dims: collectorapi.Dims{ |
| 109 | {ID: "threads_current_fds", Name: "managed"}, |
| 110 | }, |
| 111 | } |
| 112 | |
| 113 | qcCacheEfficiencyChart = collectorapi.Chart{ |
| 114 | ID: "qc_cache_efficiency", |
| 115 | Title: "QC Cache Efficiency", |
| 116 | Units: "requests/s", |
| 117 | Fam: "qc cache", |
| 118 | Ctx: "maxscale.qc_cache_efficiency", |
| 119 | Priority: prioQCCacheEfficiency, |
| 120 | Type: collectorapi.Stacked, |
| 121 | Dims: collectorapi.Dims{ |
| 122 | {ID: "threads_qc_cache_hits", Name: "hits", Algo: collectorapi.Incremental}, |
| 123 | {ID: "threads_qc_cache_misses", Name: "misses", Algo: collectorapi.Incremental}, |
| 124 | }, |
| 125 | } |
| 126 | qcCacheOperationsChart = collectorapi.Chart{ |
| 127 | ID: "qc_cache_operations", |
| 128 | Title: "QC Cache Operations", |
| 129 | Units: "operations/s", |
| 130 | Fam: "qc cache", |
| 131 | Ctx: "maxscale.qc_cache_operations", |
| 132 | Priority: prioQCCacheOperations, |
| 133 | Type: collectorapi.Stacked, |
| 134 | Dims: collectorapi.Dims{ |
| 135 | {ID: "threads_qc_cache_inserts", Name: "inserts", Algo: collectorapi.Incremental}, |
| 136 | {ID: "threads_qc_cache_evictions", Name: "evictions", Algo: collectorapi.Incremental}, |
| 137 | }, |
| 138 | } |
| 139 | |
| 140 | uptimeChart = collectorapi.Chart{ |
| 141 | ID: "uptime", |
| 142 | Title: "Uptime", |
| 143 | Units: "seconds", |
| 144 | Fam: "uptime", |
| 145 | Ctx: "maxscale.uptime", |
| 146 | Priority: prioUptime, |
| 147 | Dims: collectorapi.Dims{ |
| 148 | {ID: "uptime"}, |
| 149 | }, |
| 150 | } |
| 151 | ) |
| 152 | |
| 153 | var serverChartsTmpl = collectorapi.Charts{ |
| 154 | serverStateChartTmpl.Copy(), |
| 155 | serverCurrentConnectionsChartTmpl.Copy(), |
| 156 | } |
| 157 | |
| 158 | var ( |
| 159 | serverStateChartTmpl = func() collectorapi.Chart { |
| 160 | chart := collectorapi.Chart{ |
| 161 | ID: "server_%s_state", |
| 162 | Title: "Server State", |
| 163 | Units: "state", |
| 164 | Fam: "servers", |
| 165 | Ctx: "maxscale.server_state", |
| 166 | Priority: prioServerState, |
| 167 | } |
| 168 | for _, v := range serverStates { |
| 169 | chart.Dims = append(chart.Dims, &collectorapi.Dim{ |
| 170 | ID: "server_%s_state_" + v, |
| 171 | Name: strings.ToLower(cleanChartID(v)), |
| 172 | }) |
| 173 | } |
| 174 | return chart |
| 175 | }() |
| 176 | serverCurrentConnectionsChartTmpl = collectorapi.Chart{ |
| 177 | ID: "server_%s_current_connections", |
| 178 | Title: "Server Current Connections", |
| 179 | Units: "connections", |
| 180 | Fam: "servers", |
| 181 | Ctx: "maxscale.server_current_connections", |
| 182 | Priority: prioServerConnections, |
| 183 | Dims: collectorapi.Dims{ |
| 184 | {ID: "server_%s_connections", Name: "connections"}, |
| 185 | }, |
| 186 | } |
| 187 | ) |
| 188 | |
| 189 | func (c *Collector) addServerCharts(id, addr string) { |
| 190 | srvCharts := serverChartsTmpl.Copy() |
| 191 | |
| 192 | for _, chart := range *srvCharts { |
| 193 | chart.ID = fmt.Sprintf(chart.ID, id) |
| 194 | chart.ID = cleanChartID(chart.ID) |
| 195 | chart.Labels = []collectorapi.Label{ |
| 196 | {Key: "server", Value: id}, |
| 197 | {Key: "address", Value: addr}, |
| 198 | } |
| 199 | for _, dim := range chart.Dims { |
| 200 | dim.ID = fmt.Sprintf(dim.ID, id) |
| 201 | } |
| 202 | } |
| 203 | |
| 204 | if err := c.Charts().Add(*srvCharts...); err != nil { |
| 205 | c.Warning(err) |
| 206 | } |
| 207 | } |
| 208 | |
| 209 | func (c *Collector) removeServerCharts(id string) { |
| 210 | px := fmt.Sprintf("server_%s_", id) |
| 211 | px = cleanChartID(px) |
| 212 | |
| 213 | for _, chart := range *c.Charts() { |
| 214 | if strings.HasPrefix(chart.ID, px) { |
| 215 | chart.MarkRemove() |
| 216 | chart.MarkNotCreated() |
| 217 | } |
| 218 | } |
| 219 | } |
| 220 | |
| 221 | func cleanChartID(id string) string { |
| 222 | r := strings.NewReplacer(".", "_", " ", "_") |
| 223 | return r.Replace(id) |
| 224 | } |