@@ -18,22 +18,53 @@ package collector
1818import (
1919 "fmt"
2020 "os"
21+ "sort"
2122 "strconv"
23+ "strings"
2224
2325 "github.com/go-kit/kit/log"
2426 "github.com/go-kit/kit/log/level"
2527 "github.com/prometheus/client_golang/prometheus"
2628 "github.com/prometheus/procfs"
29+ kingpin "gopkg.in/alecthomas/kingpin.v2"
2730)
2831
2932type ipvsCollector struct {
3033 Collector
3134 fs procfs.FS
35+ backendLabels []string
3236 backendConnectionsActive , backendConnectionsInact , backendWeight typedDesc
3337 connections , incomingPackets , outgoingPackets , incomingBytes , outgoingBytes typedDesc
3438 logger log.Logger
3539}
3640
41+ type ipvsBackendStatus struct {
42+ ActiveConn uint64
43+ InactConn uint64
44+ Weight uint64
45+ }
46+
47+ const (
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+
56+ var (
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+
3768func init () {
3869 registerCollector ("ipvs" , defaultEnabled , NewIPVSCollector )
3970}
@@ -46,19 +77,15 @@ func NewIPVSCollector(logger log.Logger) (Collector, error) {
4677
4778func newIPVSCollector (logger log.Logger ) (* ipvsCollector , error ) {
4879 var (
49- ipvsBackendLabelNames = []string {
50- "local_address" ,
51- "local_port" ,
52- "remote_address" ,
53- "remote_port" ,
54- "proto" ,
55- "local_mark" ,
56- }
5780 c ipvsCollector
5881 err error
5982 subsystem = "ipvs"
6083 )
6184
85+ if c .backendLabels , err = c .parseIpvsLabels (* ipvsLabels ); err != nil {
86+ return nil , err
87+ }
88+
6289 c .logger = logger
6390 c .fs , err = procfs .NewFS (* procPath )
6491 if err != nil {
@@ -93,17 +120,17 @@ func newIPVSCollector(logger log.Logger) (*ipvsCollector, error) {
93120 c .backendConnectionsActive = typedDesc {prometheus .NewDesc (
94121 prometheus .BuildFQName (namespace , subsystem , "backend_connections_active" ),
95122 "The current active connections by local and remote address." ,
96- ipvsBackendLabelNames , nil ,
123+ c . backendLabels , nil ,
97124 ), prometheus .GaugeValue }
98125 c .backendConnectionsInact = typedDesc {prometheus .NewDesc (
99126 prometheus .BuildFQName (namespace , subsystem , "backend_connections_inactive" ),
100127 "The current inactive connections by local and remote address." ,
101- ipvsBackendLabelNames , nil ,
128+ c . backendLabels , nil ,
102129 ), prometheus .GaugeValue }
103130 c .backendWeight = typedDesc {prometheus .NewDesc (
104131 prometheus .BuildFQName (namespace , subsystem , "backend_weight" ),
105132 "The current backend weight by local and remote address." ,
106- ipvsBackendLabelNames , nil ,
133+ c . backendLabels , nil ,
107134 ), prometheus .GaugeValue }
108135
109136 return & c , nil
@@ -130,22 +157,74 @@ func (c *ipvsCollector) Update(ch chan<- prometheus.Metric) error {
130157 return fmt .Errorf ("could not get backend status: %s" , err )
131158 }
132159
160+ sums := map [string ]ipvsBackendStatus {}
161+ labelValues := map [string ][]string {}
133162 for _ , backend := range backendStats {
134163 localAddress := ""
135164 if backend .LocalAddress .String () != "<nil>" {
136165 localAddress = backend .LocalAddress .String ()
137166 }
138- labelValues := []string {
139- localAddress ,
140- strconv .FormatUint (uint64 (backend .LocalPort ), 10 ),
141- backend .RemoteAddress .String (),
142- strconv .FormatUint (uint64 (backend .RemotePort ), 10 ),
143- backend .Proto ,
144- backend .LocalMark ,
167+ kv := make ([]string , len (c .backendLabels ))
168+ for i , label := range c .backendLabels {
169+ var labelValue string
170+ switch label {
171+ case ipvsLabelLocalAddress :
172+ labelValue = localAddress
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
145185 }
146- ch <- c .backendConnectionsActive .mustNewConstMetric (float64 (backend .ActiveConn ), labelValues ... )
147- ch <- c .backendConnectionsInact .mustNewConstMetric (float64 (backend .InactConn ), labelValues ... )
148- ch <- c .backendWeight .mustNewConstMetric (float64 (backend .Weight ), labelValues ... )
186+ key := strings .Join (kv , "-" )
187+ status := sums [key ]
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 ... )
149199 }
150200 return nil
151201}
202+
203+ func (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+ }
0 commit comments