|
1 | 1 | package client
|
2 | 2 |
|
3 | 3 | import (
|
| 4 | + "bytes" |
4 | 5 | "context"
|
5 | 6 | "fmt"
|
6 | 7 | "io"
|
7 | 8 | "net/http"
|
8 |
| - "strconv" |
9 |
| - "strings" |
10 | 9 | )
|
11 | 10 |
|
| 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 | + |
12 | 17 | // NginxClient allows you to fetch NGINX metrics from the stub_status page.
|
13 | 18 | type NginxClient struct {
|
14 | 19 | apiEndpoint string
|
@@ -66,79 +71,26 @@ func (client *NginxClient) GetStubStats() (*StubStats, error) {
|
66 | 71 | return nil, fmt.Errorf("failed to read the response body: %w", err)
|
67 | 72 | }
|
68 | 73 |
|
69 |
| - var stats StubStats |
70 |
| - err = parseStubStats(body, &stats) |
| 74 | + r := bytes.NewReader(body) |
| 75 | + stats, err := parseStubStats(r) |
71 | 76 | if err != nil {
|
72 | 77 | return nil, fmt.Errorf("failed to parse response body %q: %w", string(body), err)
|
73 | 78 | }
|
74 | 79 |
|
75 |
| - return &stats, nil |
| 80 | + return stats, nil |
76 | 81 | }
|
77 | 82 |
|
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 |
144 | 96 | }
|
0 commit comments