forked from elastic/beats
-
Notifications
You must be signed in to change notification settings - Fork 9
/
haproxy.go
249 lines (214 loc) · 7.89 KB
/
haproxy.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
package haproxy
import (
"bytes"
"encoding/csv"
"errors"
"fmt"
"io"
"io/ioutil"
"net"
"strings"
"github.com/elastic/beats/metricbeat/mb/parse"
"github.com/gocarina/gocsv"
"github.com/mitchellh/mapstructure"
)
// HostParser is used for parsing the configured HAProxy hosts.
var HostParser = parse.URLHostParserBuilder{DefaultScheme: "tcp"}.Build()
// Stat is an instance of the HAProxy stat information
type Stat struct {
PxName string `csv:"# pxname"`
SvName string `csv:"svname"`
Qcur string `csv:"qcur"`
Qmax string `csv:"qmax"`
Scur string `csv:"scur"`
Smax string `csv:"smax"`
Slim string `csv:"slim"`
Stot string `csv:"stot"`
Bin string `csv:"bin"`
Bout string `csv:"bout"`
Dreq string `csv:"dreq"`
Dresp string `csv:"dresp"`
Ereq string `csv:"ereq"`
Econ string `csv:"econ"`
Eresp string `csv:"eresp"`
Wretr string `csv:"wretr"`
Wredis string `csv:"wredis"`
Status string `csv:"status"`
Weight string `csv:"weight"`
Act string `csv:"act"`
Bck string `csv:"bck"`
ChkFail string `csv:"chkfail"`
ChkDown string `csv:"chkdown"`
Lastchg string `csv:"lastchg"`
Downtime string `csv:"downtime"`
Qlimit string `csv:"qlimit"`
Pid string `csv:"pid"`
Iid string `csv:"iid"`
Sid string `csv:"sid"`
Throttle string `csv:"throttle"`
Lbtot string `csv:"lbtot"`
Tracked string `csv:"tracked"`
Type string `csv:"type"`
Rate string `csv:"rate"`
RateLim string `csv:"rate_lim"`
RateMax string `csv:"rate_max"`
CheckStatus string `csv:"check_status"`
CheckCode string `csv:"check_code"`
CheckDuration string `csv:"check_duration"`
Hrsp1xx string `csv:"hrsp_1xx"`
Hrsp2xx string `csv:"hrsp_2xx"`
Hrsp3xx string `csv:"hrsp_3xx"`
Hrsp4xx string `csv:"hrsp_4xx"`
Hrsp5xx string `csv:"hrsp_5xx"`
HrspOther string `csv:"hrsp_other"`
Hanafail string `csv:"hanafail"`
ReqRate string `csv:"req_rate"`
ReqRateMax string `csv:"req_rate_max"`
ReqTot string `csv:"req_tot"`
CliAbrt string `csv:"cli_abrt"`
SrvAbrt string `csv:"srv_abrt"`
CompIn string `csv:"comp_in"`
CompOut string `csv:"comp_out"`
CompByp string `csv:"comp_byp"`
CompRsp string `csv:"comp_rsp"`
LastSess string `csv:"lastsess"`
LastChk string `csv:"last_chk"`
LastAgt string `csv:"last_agt"`
Qtime string `csv:"qtime"`
Ctime string `csv:"ctime"`
Rtime string `csv:"rtime"`
Ttime string `csv:"ttime"`
}
type Info struct {
Name string `mapstructure:"Name"`
Version string `mapstructure:"Version"`
ReleaseDate string `mapstructure:"Release_date"`
Nbproc string `mapstructure:"Nbproc"`
ProcessNum string `mapstructure:"Process_num"`
Pid string `mapstructure:"Pid"`
Uptime string `mapstructure:"Uptime"`
UptimeSec string `mapstructure:"Uptime_sec"`
MemMax string `mapstructure:"Memmax_MB"`
UlimitN string `mapstructure:"Ulimit-n"`
Maxsock string `mapstructure:"Maxsock"`
Maxconn string `mapstructure:"Maxconn"`
HardMaxconn string `mapstructure:"Hard_maxconn"`
CurrConns string `mapstructure:"CurrConns"`
CumConns string `mapstructure:"CumConns"`
CumReq string `mapstructure:"CumReq"`
MaxSslConns string `mapstructure:"MaxSslConns"`
CurrSslConns string `mapstructure:"CurrSslConns"`
CumSslConns string `mapstructure:"CumSslConns"`
Maxpipes string `mapstructure:"Maxpipes"`
PipesUsed string `mapstructure:"PipesUsed"`
PipesFree string `mapstructure:"PipesFree"`
ConnRate string `mapstructure:"ConnRate"`
ConnRateLimit string `mapstructure:"ConnRateLimit"`
MaxConnRate string `mapstructure:"MaxConnRate"`
SessRate string `mapstructure:"SessRate"`
SessRateLimit string `mapstructure:"SessRateLimit"`
MaxSessRate string `mapstructure:"MaxSessRate"`
SslRate string `mapstructure:"SslRate"`
SslRateLimit string `mapstructure:"SslRateLimit"`
MaxSslRate string `mapstructure:"MaxSslRate"`
SslFrontendKeyRate string `mapstructure:"SslFrontendKeyRate"`
SslFrontendMaxKeyRate string `mapstructure:"SslFrontendMaxKeyRate"`
SslFrontendSessionReusePct string `mapstructure:"SslFrontendSessionReuse_pct"`
SslBackendKeyRate string `mapstructure:"SslBackendKeyRate"`
SslBackendMaxKeyRate string `mapstructure:"SslBackendMaxKeyRate"`
SslCacheLookups string `mapstructure:"SslCacheLookups"`
SslCacheMisses string `mapstructure:"SslCacheMisses"`
CompressBpsIn string `mapstructure:"CompressBpsIn"`
CompressBpsOut string `mapstructure:"CompressBpsOut"`
CompressBpsRateLim string `mapstructure:"CompressBpsRateLim"`
ZlibMemUsage string `mapstructure:"ZlibMemUsage"`
MaxZlibMemUsage string `mapstructure:"MaxZlibMemUsage"`
Tasks string `mapstructure:"Tasks"`
RunQueue string `mapstructure:"Run_queue"`
IdlePct string `mapstructure:"Idle_pct"`
Node string `mapstructure:"Node"`
Description string `mapstructure:"Description"`
}
// Client is an instance of the HAProxy client
type Client struct {
Address string
ProtoScheme string
}
// NewHaproxyClient returns a new instance of HaproxyClient
func NewHaproxyClient(address string) (*Client, error) {
parts := strings.Split(address, "://")
if len(parts) != 2 {
return nil, errors.New("must have protocol scheme and address")
}
if parts[0] != "tcp" && parts[0] != "unix" {
return nil, errors.New("invalid protocol scheme")
}
return &Client{
Address: parts[1],
ProtoScheme: parts[0],
}, nil
}
// Run sends a designated command to the haproxy stats socket
func (c *Client) run(cmd string) (*bytes.Buffer, error) {
var conn net.Conn
response := bytes.NewBuffer(nil)
conn, err := net.Dial(c.ProtoScheme, c.Address)
if err != nil {
return response, err
}
defer conn.Close()
_, err = conn.Write([]byte(cmd + "\n"))
if err != nil {
return response, err
}
_, err = io.Copy(response, conn)
if err != nil {
return response, err
}
if strings.HasPrefix(response.String(), "Unknown command") {
return response, fmt.Errorf("unknown command: %s", cmd)
}
return response, nil
}
// GetStat returns the result from the 'show stat' command
func (c *Client) GetStat() ([]*Stat, error) {
runResult, err := c.run("show stat")
if err != nil {
return nil, err
}
var statRes []*Stat
csvReader := csv.NewReader(runResult)
csvReader.TrailingComma = true
err = gocsv.UnmarshalCSV(csvReader, &statRes)
if err != nil {
return nil, fmt.Errorf("error parsing CSV: %s", err)
}
return statRes, nil
}
// GetInfo returns the result from the 'show stat' command
func (c *Client) GetInfo() (*Info, error) {
res, err := c.run("show info")
if err != nil {
return nil, err
}
if b, err := ioutil.ReadAll(res); err == nil {
resultMap := map[string]interface{}{}
for _, ln := range strings.Split(string(b), "\n") {
ln := strings.TrimSpace(ln)
if ln == "" {
continue
}
parts := strings.Split(ln, ":")
if len(parts) != 2 {
continue
}
resultMap[parts[0]] = strings.TrimSpace(parts[1])
}
var result *Info
if err := mapstructure.Decode(resultMap, &result); err != nil {
return nil, err
}
return result, nil
}
return nil, err
}