@@ -18,22 +18,53 @@ package collector
18
18
import (
19
19
"fmt"
20
20
"os"
21
+ "sort"
21
22
"strconv"
23
+ "strings"
22
24
23
25
"github.com/go-kit/kit/log"
24
26
"github.com/go-kit/kit/log/level"
25
27
"github.com/prometheus/client_golang/prometheus"
26
28
"github.com/prometheus/procfs"
29
+ kingpin "gopkg.in/alecthomas/kingpin.v2"
27
30
)
28
31
29
32
type ipvsCollector struct {
30
33
Collector
31
34
fs procfs.FS
35
+ backendLabels []string
32
36
backendConnectionsActive , backendConnectionsInact , backendWeight typedDesc
33
37
connections , incomingPackets , outgoingPackets , incomingBytes , outgoingBytes typedDesc
34
38
logger log.Logger
35
39
}
36
40
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
+
37
68
func init () {
38
69
registerCollector ("ipvs" , defaultEnabled , NewIPVSCollector )
39
70
}
@@ -46,19 +77,15 @@ func NewIPVSCollector(logger log.Logger) (Collector, error) {
46
77
47
78
func newIPVSCollector (logger log.Logger ) (* ipvsCollector , error ) {
48
79
var (
49
- ipvsBackendLabelNames = []string {
50
- "local_address" ,
51
- "local_port" ,
52
- "remote_address" ,
53
- "remote_port" ,
54
- "proto" ,
55
- "local_mark" ,
56
- }
57
80
c ipvsCollector
58
81
err error
59
82
subsystem = "ipvs"
60
83
)
61
84
85
+ if c .backendLabels , err = c .parseIpvsLabels (* ipvsLabels ); err != nil {
86
+ return nil , err
87
+ }
88
+
62
89
c .logger = logger
63
90
c .fs , err = procfs .NewFS (* procPath )
64
91
if err != nil {
@@ -93,17 +120,17 @@ func newIPVSCollector(logger log.Logger) (*ipvsCollector, error) {
93
120
c .backendConnectionsActive = typedDesc {prometheus .NewDesc (
94
121
prometheus .BuildFQName (namespace , subsystem , "backend_connections_active" ),
95
122
"The current active connections by local and remote address." ,
96
- ipvsBackendLabelNames , nil ,
123
+ c . backendLabels , nil ,
97
124
), prometheus .GaugeValue }
98
125
c .backendConnectionsInact = typedDesc {prometheus .NewDesc (
99
126
prometheus .BuildFQName (namespace , subsystem , "backend_connections_inactive" ),
100
127
"The current inactive connections by local and remote address." ,
101
- ipvsBackendLabelNames , nil ,
128
+ c . backendLabels , nil ,
102
129
), prometheus .GaugeValue }
103
130
c .backendWeight = typedDesc {prometheus .NewDesc (
104
131
prometheus .BuildFQName (namespace , subsystem , "backend_weight" ),
105
132
"The current backend weight by local and remote address." ,
106
- ipvsBackendLabelNames , nil ,
133
+ c . backendLabels , nil ,
107
134
), prometheus .GaugeValue }
108
135
109
136
return & c , nil
@@ -130,22 +157,74 @@ func (c *ipvsCollector) Update(ch chan<- prometheus.Metric) error {
130
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
162
for _ , backend := range backendStats {
134
163
localAddress := ""
135
164
if backend .LocalAddress .String () != "<nil>" {
136
165
localAddress = backend .LocalAddress .String ()
137
166
}
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
145
185
}
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 ... )
149
199
}
150
200
return nil
151
201
}
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