rmm2/agent/collector/haproxy.go

133 lines
3.4 KiB
Go

package collector
import (
"os"
"os/exec"
"strconv"
"strings"
)
type HAProxyInfo struct {
Uptime string `json:"uptime"`
CurrentConns int `json:"current_conns"`
TotalConns int `json:"total_conns"`
TotalReqs int `json:"total_requests"`
CurrentSSL int `json:"current_ssl"`
TotalSSL int `json:"total_ssl"`
MaxConns int `json:"max_conns"`
}
type HAProxyEntry struct {
ProxyName string `json:"proxy_name"`
ServerName string `json:"server_name"`
Type string `json:"type"`
Status string `json:"status"`
CurrentSessions int `json:"current_sessions"`
TotalSessions int `json:"total_sessions"`
BytesIn int64 `json:"bytes_in"`
BytesOut int64 `json:"bytes_out"`
RequestsTotal int `json:"requests_total"`
ErrorsReq int `json:"errors_req"`
ErrorsConn int `json:"errors_conn"`
ErrorsResp int `json:"errors_resp"`
}
type HAProxyData struct {
Info HAProxyInfo `json:"info"`
Entries []HAProxyEntry `json:"entries"`
}
const haproxySocket = "/var/run/haproxy.socket"
func CollectHAProxy() *HAProxyData {
if _, err := os.Stat(haproxySocket); err != nil {
return nil
}
data := &HAProxyData{}
// show info
if out, err := exec.Command("/bin/sh", "-c", `echo "show info" | /usr/bin/nc -U `+haproxySocket).Output(); err == nil {
info := parseHAProxyInfo(string(out))
data.Info = info
}
// show stat
if out, err := exec.Command("/bin/sh", "-c", `echo "show stat" | /usr/bin/nc -U `+haproxySocket).Output(); err == nil {
data.Entries = parseHAProxyStats(string(out))
}
return data
}
func parseHAProxyInfo(output string) HAProxyInfo {
info := HAProxyInfo{}
for _, line := range strings.Split(output, "\n") {
parts := strings.SplitN(line, ":", 2)
if len(parts) != 2 {
continue
}
key := strings.TrimSpace(parts[0])
val := strings.TrimSpace(parts[1])
switch key {
case "Uptime":
info.Uptime = val
case "CurrConns":
info.CurrentConns, _ = strconv.Atoi(val)
case "CumConns":
info.TotalConns, _ = strconv.Atoi(val)
case "CumReq":
info.TotalReqs, _ = strconv.Atoi(val)
case "CurrSslConns":
info.CurrentSSL, _ = strconv.Atoi(val)
case "CumSslConns":
info.TotalSSL, _ = strconv.Atoi(val)
case "Maxconn":
info.MaxConns, _ = strconv.Atoi(val)
}
}
return info
}
func parseHAProxyStats(output string) []HAProxyEntry {
var entries []HAProxyEntry
lines := strings.Split(output, "\n")
for _, line := range lines {
if strings.HasPrefix(line, "#") || strings.TrimSpace(line) == "" {
continue
}
fields := strings.Split(line, ",")
if len(fields) < 18 {
continue
}
svname := fields[1]
entryType := "server"
if svname == "FRONTEND" {
entryType = "frontend"
} else if svname == "BACKEND" {
entryType = "backend"
}
e := HAProxyEntry{
ProxyName: fields[0],
ServerName: svname,
Type: entryType,
Status: fields[17],
}
e.CurrentSessions, _ = strconv.Atoi(fields[4])
e.TotalSessions, _ = strconv.Atoi(fields[7])
e.BytesIn, _ = strconv.ParseInt(fields[8], 10, 64)
e.BytesOut, _ = strconv.ParseInt(fields[9], 10, 64)
e.ErrorsReq, _ = strconv.Atoi(fields[12])
e.ErrorsConn, _ = strconv.Atoi(fields[13])
e.ErrorsResp, _ = strconv.Atoi(fields[14])
if len(fields) > 48 {
e.RequestsTotal, _ = strconv.Atoi(fields[48])
}
entries = append(entries, e)
}
return entries
}