1
0
mirror of https://github.com/nginxinc/nginx-prometheus-exporter.git synced 2025-08-09 16:02:43 +03:00

Simple parsing nginx metrics [parseStubStats] (#207)

This commit is contained in:
Andrei Grazhdankov
2021-07-21 23:49:29 +03:00
committed by GitHub
parent d14781a6bd
commit c636d826c1
2 changed files with 29 additions and 75 deletions

View File

@@ -1,14 +1,19 @@
package client
import (
"bytes"
"context"
"fmt"
"io"
"net/http"
"strconv"
"strings"
)
const templateMetrics string = `Active connections: %d
server accepts handled requests
%d %d %d
Reading: %d Writing: %d Waiting: %d
`
// NginxClient allows you to fetch NGINX metrics from the stub_status page.
type NginxClient struct {
apiEndpoint string
@@ -66,79 +71,26 @@ func (client *NginxClient) GetStubStats() (*StubStats, error) {
return nil, fmt.Errorf("failed to read the response body: %w", err)
}
var stats StubStats
err = parseStubStats(body, &stats)
r := bytes.NewReader(body)
stats, err := parseStubStats(r)
if err != nil {
return nil, fmt.Errorf("failed to parse response body %q: %w", string(body), err)
}
return &stats, nil
return stats, nil
}
func parseStubStats(data []byte, stats *StubStats) error {
dataStr := string(data)
parts := strings.Split(dataStr, "\n")
if len(parts) != 5 {
return fmt.Errorf("invalid input %q", dataStr)
func parseStubStats(r io.Reader) (*StubStats, error) {
var s StubStats
if _, err := fmt.Fscanf(r, templateMetrics,
&s.Connections.Active,
&s.Connections.Accepted,
&s.Connections.Handled,
&s.Requests,
&s.Connections.Reading,
&s.Connections.Writing,
&s.Connections.Waiting); err != nil {
return nil, fmt.Errorf("failed to scan template metrics: %w", err)
}
activeConsParts := strings.Split(strings.TrimSpace(parts[0]), " ")
if len(activeConsParts) != 3 {
return fmt.Errorf("invalid input for active connections %q", parts[0])
}
actCons, err := strconv.ParseInt(activeConsParts[2], 10, 64)
if err != nil {
return fmt.Errorf("invalid input for active connections %q: %w", activeConsParts[2], err)
}
stats.Connections.Active = actCons
miscParts := strings.Split(strings.TrimSpace(parts[2]), " ")
if len(miscParts) != 3 {
return fmt.Errorf("invalid input for connections and requests %q", parts[2])
}
acceptedCons, err := strconv.ParseInt(miscParts[0], 10, 64)
if err != nil {
return fmt.Errorf("invalid input for accepted connections %q: %w", miscParts[0], err)
}
stats.Connections.Accepted = acceptedCons
handledCons, err := strconv.ParseInt(miscParts[1], 10, 64)
if err != nil {
return fmt.Errorf("invalid input for handled connections %q: %w", miscParts[1], err)
}
stats.Connections.Handled = handledCons
requests, err := strconv.ParseInt(miscParts[2], 10, 64)
if err != nil {
return fmt.Errorf("invalid input for requests %q: %w", miscParts[2], err)
}
stats.Requests = requests
consParts := strings.Split(strings.TrimSpace(parts[3]), " ")
if len(consParts) != 6 {
return fmt.Errorf("invalid input for connections %q", parts[3])
}
readingCons, err := strconv.ParseInt(consParts[1], 10, 64)
if err != nil {
return fmt.Errorf("invalid input for reading connections %q: %w", consParts[1], err)
}
stats.Connections.Reading = readingCons
writingCons, err := strconv.ParseInt(consParts[3], 10, 64)
if err != nil {
return fmt.Errorf("invalid input for writing connections %q: %w", consParts[3], err)
}
stats.Connections.Writing = writingCons
waitingCons, err := strconv.ParseInt(consParts[5], 10, 64)
if err != nil {
return fmt.Errorf("invalid input for waiting connections %q: %w", consParts[5], err)
}
stats.Connections.Waiting = waitingCons
return nil
return &s, nil
}