aboutsummaryrefslogtreecommitdiff
path: root/collector/ipvs_linux.go
diff options
context:
space:
mode:
Diffstat (limited to 'collector/ipvs_linux.go')
-rw-r--r--collector/ipvs_linux.go121
1 files changed, 100 insertions, 21 deletions
diff --git a/collector/ipvs_linux.go b/collector/ipvs_linux.go
index 11adf0f..b5c8d73 100644
--- a/collector/ipvs_linux.go
+++ b/collector/ipvs_linux.go
@@ -18,22 +18,53 @@ package collector
18import ( 18import (
19 "fmt" 19 "fmt"
20 "os" 20 "os"
21 "sort"
21 "strconv" 22 "strconv"
23 "strings"
22 24
23 "github.com/go-kit/kit/log" 25 "github.com/go-kit/kit/log"
24 "github.com/go-kit/kit/log/level" 26 "github.com/go-kit/kit/log/level"
25 "github.com/prometheus/client_golang/prometheus" 27 "github.com/prometheus/client_golang/prometheus"
26 "github.com/prometheus/procfs" 28 "github.com/prometheus/procfs"
29 kingpin "gopkg.in/alecthomas/kingpin.v2"
27) 30)
28 31
29type ipvsCollector struct { 32type ipvsCollector struct {
30 Collector 33 Collector
31 fs procfs.FS 34 fs procfs.FS
35 backendLabels []string
32 backendConnectionsActive, backendConnectionsInact, backendWeight typedDesc 36 backendConnectionsActive, backendConnectionsInact, backendWeight typedDesc
33 connections, incomingPackets, outgoingPackets, incomingBytes, outgoingBytes typedDesc 37 connections, incomingPackets, outgoingPackets, incomingBytes, outgoingBytes typedDesc
34 logger log.Logger 38 logger log.Logger
35} 39}
36 40
41type ipvsBackendStatus struct {
42 ActiveConn uint64
43 InactConn uint64
44 Weight uint64
45}
46
47const (
48 ipvsLabelLocalAddress = "local_address"
49 ipvsLabelLocalPort = "local_port"
50 ipvsLabelRemoteAddress = "remote_address"
51 ipvsLabelRemotePort = "remote_port"
52 ipvsLabelProto = "proto"
53 ipvsLabelLocalMark = "local_mark"
54)
55
56var (
57 fullIpvsBackendLabels = []string{
58 ipvsLabelLocalAddress,
59 ipvsLabelLocalPort,
60 ipvsLabelRemoteAddress,
61 ipvsLabelRemotePort,
62 ipvsLabelProto,
63 ipvsLabelLocalMark,
64 }
65 ipvsLabels = kingpin.Flag("collector.ipvs.backend-labels", "Comma separated list for IPVS backend stats labels.").Default(strings.Join(fullIpvsBackendLabels, ",")).String()
66)
67
37func init() { 68func init() {
38 registerCollector("ipvs", defaultEnabled, NewIPVSCollector) 69 registerCollector("ipvs", defaultEnabled, NewIPVSCollector)
39} 70}
@@ -46,19 +77,15 @@ func NewIPVSCollector(logger log.Logger) (Collector, error) {
46 77
47func newIPVSCollector(logger log.Logger) (*ipvsCollector, error) { 78func newIPVSCollector(logger log.Logger) (*ipvsCollector, error) {
48 var ( 79 var (
49 ipvsBackendLabelNames = []string{
50 "local_address",
51 "local_port",
52 "remote_address",
53 "remote_port",
54 "proto",
55 "local_mark",
56 }
57 c ipvsCollector 80 c ipvsCollector
58 err error 81 err error
59 subsystem = "ipvs" 82 subsystem = "ipvs"
60 ) 83 )
61 84
85 if c.backendLabels, err = c.parseIpvsLabels(*ipvsLabels); err != nil {
86 return nil, err
87 }
88
62 c.logger = logger 89 c.logger = logger
63 c.fs, err = procfs.NewFS(*procPath) 90 c.fs, err = procfs.NewFS(*procPath)
64 if err != nil { 91 if err != nil {
@@ -93,17 +120,17 @@ func newIPVSCollector(logger log.Logger) (*ipvsCollector, error) {
93 c.backendConnectionsActive = typedDesc{prometheus.NewDesc( 120 c.backendConnectionsActive = typedDesc{prometheus.NewDesc(
94 prometheus.BuildFQName(namespace, subsystem, "backend_connections_active"), 121 prometheus.BuildFQName(namespace, subsystem, "backend_connections_active"),
95 "The current active connections by local and remote address.", 122 "The current active connections by local and remote address.",
96 ipvsBackendLabelNames, nil, 123 c.backendLabels, nil,
97 ), prometheus.GaugeValue} 124 ), prometheus.GaugeValue}
98 c.backendConnectionsInact = typedDesc{prometheus.NewDesc( 125 c.backendConnectionsInact = typedDesc{prometheus.NewDesc(
99 prometheus.BuildFQName(namespace, subsystem, "backend_connections_inactive"), 126 prometheus.BuildFQName(namespace, subsystem, "backend_connections_inactive"),
100 "The current inactive connections by local and remote address.", 127 "The current inactive connections by local and remote address.",
101 ipvsBackendLabelNames, nil, 128 c.backendLabels, nil,
102 ), prometheus.GaugeValue} 129 ), prometheus.GaugeValue}
103 c.backendWeight = typedDesc{prometheus.NewDesc( 130 c.backendWeight = typedDesc{prometheus.NewDesc(
104 prometheus.BuildFQName(namespace, subsystem, "backend_weight"), 131 prometheus.BuildFQName(namespace, subsystem, "backend_weight"),
105 "The current backend weight by local and remote address.", 132 "The current backend weight by local and remote address.",
106 ipvsBackendLabelNames, nil, 133 c.backendLabels, nil,
107 ), prometheus.GaugeValue} 134 ), prometheus.GaugeValue}
108 135
109 return &c, nil 136 return &c, nil
@@ -130,22 +157,74 @@ func (c *ipvsCollector) Update(ch chan<- prometheus.Metric) error {
130 return fmt.Errorf("could not get backend status: %s", err) 157 return fmt.Errorf("could not get backend status: %s", err)
131 } 158 }
132 159
160 sums := map[string]ipvsBackendStatus{}
161 labelValues := map[string][]string{}
133 for _, backend := range backendStats { 162 for _, backend := range backendStats {
134 localAddress := "" 163 localAddress := ""
135 if backend.LocalAddress.String() != "<nil>" { 164 if backend.LocalAddress.String() != "<nil>" {
136 localAddress = backend.LocalAddress.String() 165 localAddress = backend.LocalAddress.String()
137 } 166 }
138 labelValues := []string{ 167 kv := make([]string, len(c.backendLabels))
139 localAddress, 168 for i, label := range c.backendLabels {
140 strconv.FormatUint(uint64(backend.LocalPort), 10), 169 var labelValue string
141 backend.RemoteAddress.String(), 170 switch label {
142 strconv.FormatUint(uint64(backend.RemotePort), 10), 171 case ipvsLabelLocalAddress:
143 backend.Proto, 172 labelValue = localAddress
144 backend.LocalMark, 173 case ipvsLabelLocalPort:
174 labelValue = strconv.FormatUint(uint64(backend.LocalPort), 10)
175 case ipvsLabelRemoteAddress:
176 labelValue = backend.RemoteAddress.String()
177 case ipvsLabelRemotePort:
178 labelValue = strconv.FormatUint(uint64(backend.RemotePort), 10)
179 case ipvsLabelProto:
180 labelValue = backend.Proto
181 case ipvsLabelLocalMark:
182 labelValue = backend.LocalMark
183 }
184 kv[i] = labelValue
145 } 185 }
146 ch <- c.backendConnectionsActive.mustNewConstMetric(float64(backend.ActiveConn), labelValues...) 186 key := strings.Join(kv, "-")
147 ch <- c.backendConnectionsInact.mustNewConstMetric(float64(backend.InactConn), labelValues...) 187 status := sums[key]
148 ch <- c.backendWeight.mustNewConstMetric(float64(backend.Weight), labelValues...) 188 status.ActiveConn += backend.ActiveConn
189 status.InactConn += backend.InactConn
190 status.Weight += backend.Weight
191 sums[key] = status
192 labelValues[key] = kv
193 }
194 for key, status := range sums {
195 kv := labelValues[key]
196 ch <- c.backendConnectionsActive.mustNewConstMetric(float64(status.ActiveConn), kv...)
197 ch <- c.backendConnectionsInact.mustNewConstMetric(float64(status.InactConn), kv...)
198 ch <- c.backendWeight.mustNewConstMetric(float64(status.Weight), kv...)
149 } 199 }
150 return nil 200 return nil
151} 201}
202
203func (c *ipvsCollector) parseIpvsLabels(labelString string) ([]string, error) {
204 labels := strings.Split(labelString, ",")
205 labelSet := make(map[string]bool, len(labels))
206 results := make([]string, 0, len(labels))
207 for _, label := range labels {
208 if label != "" {
209 labelSet[label] = true
210 }
211 }
212
213 for _, label := range fullIpvsBackendLabels {
214 if labelSet[label] {
215 results = append(results, label)
216 }
217 delete(labelSet, label)
218 }
219
220 if len(labelSet) > 0 {
221 keys := make([]string, 0, len(labelSet))
222 for label := range labelSet {
223 keys = append(keys, label)
224 }
225 sort.Strings(keys)
226 return nil, fmt.Errorf("unknown IPVS backend labels: %q", strings.Join(keys, ", "))
227 }
228
229 return results, nil
230}