Skip to content

Commit c636d82

Browse files
authored
Simple parsing nginx metrics [parseStubStats] (#207)
1 parent d14781a commit c636d82

File tree

2 files changed

+30
-76
lines changed

2 files changed

+30
-76
lines changed

client/nginx.go

Lines changed: 23 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,19 @@
11
package client
22

33
import (
4+
"bytes"
45
"context"
56
"fmt"
67
"io"
78
"net/http"
8-
"strconv"
9-
"strings"
109
)
1110

11+
const templateMetrics string = `Active connections: %d
12+
server accepts handled requests
13+
%d %d %d
14+
Reading: %d Writing: %d Waiting: %d
15+
`
16+
1217
// NginxClient allows you to fetch NGINX metrics from the stub_status page.
1318
type NginxClient struct {
1419
apiEndpoint string
@@ -66,79 +71,26 @@ func (client *NginxClient) GetStubStats() (*StubStats, error) {
6671
return nil, fmt.Errorf("failed to read the response body: %w", err)
6772
}
6873

69-
var stats StubStats
70-
err = parseStubStats(body, &stats)
74+
r := bytes.NewReader(body)
75+
stats, err := parseStubStats(r)
7176
if err != nil {
7277
return nil, fmt.Errorf("failed to parse response body %q: %w", string(body), err)
7378
}
7479

75-
return &stats, nil
80+
return stats, nil
7681
}
7782

78-
func parseStubStats(data []byte, stats *StubStats) error {
79-
dataStr := string(data)
80-
81-
parts := strings.Split(dataStr, "\n")
82-
if len(parts) != 5 {
83-
return fmt.Errorf("invalid input %q", dataStr)
84-
}
85-
86-
activeConsParts := strings.Split(strings.TrimSpace(parts[0]), " ")
87-
if len(activeConsParts) != 3 {
88-
return fmt.Errorf("invalid input for active connections %q", parts[0])
89-
}
90-
91-
actCons, err := strconv.ParseInt(activeConsParts[2], 10, 64)
92-
if err != nil {
93-
return fmt.Errorf("invalid input for active connections %q: %w", activeConsParts[2], err)
94-
}
95-
stats.Connections.Active = actCons
96-
97-
miscParts := strings.Split(strings.TrimSpace(parts[2]), " ")
98-
if len(miscParts) != 3 {
99-
return fmt.Errorf("invalid input for connections and requests %q", parts[2])
100-
}
101-
102-
acceptedCons, err := strconv.ParseInt(miscParts[0], 10, 64)
103-
if err != nil {
104-
return fmt.Errorf("invalid input for accepted connections %q: %w", miscParts[0], err)
105-
}
106-
stats.Connections.Accepted = acceptedCons
107-
108-
handledCons, err := strconv.ParseInt(miscParts[1], 10, 64)
109-
if err != nil {
110-
return fmt.Errorf("invalid input for handled connections %q: %w", miscParts[1], err)
111-
}
112-
stats.Connections.Handled = handledCons
113-
114-
requests, err := strconv.ParseInt(miscParts[2], 10, 64)
115-
if err != nil {
116-
return fmt.Errorf("invalid input for requests %q: %w", miscParts[2], err)
117-
}
118-
stats.Requests = requests
119-
120-
consParts := strings.Split(strings.TrimSpace(parts[3]), " ")
121-
if len(consParts) != 6 {
122-
return fmt.Errorf("invalid input for connections %q", parts[3])
123-
}
124-
125-
readingCons, err := strconv.ParseInt(consParts[1], 10, 64)
126-
if err != nil {
127-
return fmt.Errorf("invalid input for reading connections %q: %w", consParts[1], err)
128-
}
129-
stats.Connections.Reading = readingCons
130-
131-
writingCons, err := strconv.ParseInt(consParts[3], 10, 64)
132-
if err != nil {
133-
return fmt.Errorf("invalid input for writing connections %q: %w", consParts[3], err)
134-
}
135-
stats.Connections.Writing = writingCons
136-
137-
waitingCons, err := strconv.ParseInt(consParts[5], 10, 64)
138-
if err != nil {
139-
return fmt.Errorf("invalid input for waiting connections %q: %w", consParts[5], err)
140-
}
141-
stats.Connections.Waiting = waitingCons
142-
143-
return nil
83+
func parseStubStats(r io.Reader) (*StubStats, error) {
84+
var s StubStats
85+
if _, err := fmt.Fscanf(r, templateMetrics,
86+
&s.Connections.Active,
87+
&s.Connections.Accepted,
88+
&s.Connections.Handled,
89+
&s.Requests,
90+
&s.Connections.Reading,
91+
&s.Connections.Writing,
92+
&s.Connections.Waiting); err != nil {
93+
return nil, fmt.Errorf("failed to scan template metrics: %w", err)
94+
}
95+
return &s, nil
14496
}

client/nginx_test.go

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
package client
22

3-
import "testing"
3+
import (
4+
"bytes"
5+
"testing"
6+
)
47

58
const validStabStats = "Active connections: 1457 \nserver accepts handled requests\n 6717066 6717066 65844359 \nReading: 1 Writing: 8 Waiting: 1448 \n"
69

@@ -32,15 +35,14 @@ func TestParseStubStatsValidInput(t *testing.T) {
3235
}
3336

3437
for _, test := range tests {
35-
var result StubStats
36-
37-
err := parseStubStats(test.input, &result)
38+
r := bytes.NewReader(test.input)
39+
result, err := parseStubStats(r)
3840

3941
if err != nil && !test.expectedError {
4042
t.Errorf("parseStubStats() returned error for valid input %q: %v", string(test.input), err)
4143
}
4244

43-
if !test.expectedError && test.expectedResult != result {
45+
if !test.expectedError && test.expectedResult != *result {
4446
t.Errorf("parseStubStats() result %v != expected %v for input %q", result, test.expectedResult, test.input)
4547
}
4648
}

0 commit comments

Comments
 (0)