src/go/plugin/go.d/modules/phpfpm/decode.go
// SPDX-License-Identifier: GPL-3.0-or-later
package phpfpm
import (
"bufio"
"encoding/json"
"errors"
"io"
"strconv"
"strings"
)
type decoder func(r io.Reader, s *status) error
func decodeJSON(r io.Reader, s *status) error {
return json.NewDecoder(r).Decode(s)
}
func decodeText(r io.Reader, s *status) error {
parts := readParts(r)
if len(parts) == 0 {
return errors.New("invalid text format")
}
part, parts := parts[0], parts[1:]
if err := readStatus(part, s); err != nil {
return err
}
return readProcesses(parts, s)
}
func readParts(r io.Reader) [][]string {
sc := bufio.NewScanner(r)
var parts [][]string
var lines []string
for sc.Scan() {
line := strings.Trim(sc.Text(), "\r\n ")
// Split parts by star border
if strings.HasPrefix(line, "***") {
parts = append(parts, lines)
lines = []string{}
continue
}
// Skip empty lines
if line == "" {
continue
}
lines = append(lines, line)
}
if len(lines) > 0 {
parts = append(parts, lines)
}
return parts
}
func readStatus(data []string, s *status) error {
for _, line := range data {
key, val, err := parseLine(line)
if err != nil {
return err
}
switch key {
case "active processes":
s.Active = parseInt(val)
case "max active processes":
s.MaxActive = parseInt(val)
case "idle processes":
s.Idle = parseInt(val)
case "accepted conn":
s.Requests = parseInt(val)
case "max children reached":
s.Reached = parseInt(val)
case "slow requests":
s.Slow = parseInt(val)
}
}
return nil
}
func readProcesses(procs [][]string, s *status) error {
for _, part := range procs {
var proc proc
for _, line := range part {
key, val, err := parseLine(line)
if err != nil {
return err
}
switch key {
case "state":
proc.State = val
case "request duration":
proc.Duration = requestDuration(parseInt(val))
case "last request cpu":
proc.CPU = parseFloat(val)
case "last request memory":
proc.Memory = parseInt(val)
}
}
s.Processes = append(s.Processes, proc)
}
return nil
}
func parseLine(s string) (string, string, error) {
kv := strings.SplitN(s, ":", 2)
if len(kv) != 2 {
return "", "", errors.New("invalid text format line")
}
return strings.TrimSpace(kv[0]), strings.TrimSpace(kv[1]), nil
}
func parseInt(s string) int64 {
val, err := strconv.ParseInt(strings.TrimSpace(s), 10, 64)
if err != nil {
return 0
}
return val
}
func parseFloat(s string) float64 {
val, err := strconv.ParseFloat(strings.TrimSpace(s), 64)
if err != nil {
return 0
}
return val
}