master
go 269 lines 6.7 KB
Raw
1 // SPDX-License-Identifier: GPL-3.0-or-later
2
3 package tengine
4
5 import (
6 "bufio"
7 "fmt"
8 "io"
9 "strconv"
10 "strings"
11 )
12
13 /*
14 http://tengine.taobao.org/document/http_reqstat.html
15
16 bytes_in total number of bytes received from client
17 bytes_out total number of bytes sent to client
18 conn_total total number of accepted connections
19 req_total total number of processed requests
20 http_2xx total number of 2xx requests
21 http_3xx total number of 3xx requests
22 http_4xx total number of 4xx requests
23 http_5xx total number of 5xx requests
24 http_other_status total number of other requests
25 rt accumulation or rt
26 ups_req total number of requests calling for upstream
27 ups_rt accumulation or upstream rt
28 ups_tries total number of times calling for upstream
29 http_200 total number of 200 requests
30 http_206 total number of 206 requests
31 http_302 total number of 302 requests
32 http_304 total number of 304 requests
33 http_403 total number of 403 requests
34 http_404 total number of 404 requests
35 http_416 total number of 416 requests
36 http_499 total number of 499 requests
37 http_500 total number of 500 requests
38 http_502 total number of 502 requests
39 http_503 total number of 503 requests
40 http_504 total number of 504 requests
41 http_508 total number of 508 requests
42 http_other_detail_status total number of requests of other status codes
43 http_ups_4xx total number of requests of upstream 4xx
44 http_ups_5xx total number of requests of upstream 5xx
45 */
46
47 type (
48 tengineStatus []metric
49
50 metric struct {
51 Host string
52 ServerAddress string
53 BytesIn *int64 `stm:"bytes_in"`
54 BytesOut *int64 `stm:"bytes_out"`
55 ConnTotal *int64 `stm:"conn_total"`
56 ReqTotal *int64 `stm:"req_total"`
57 HTTP2xx *int64 `stm:"http_2xx"`
58 HTTP3xx *int64 `stm:"http_3xx"`
59 HTTP4xx *int64 `stm:"http_4xx"`
60 HTTP5xx *int64 `stm:"http_5xx"`
61 HTTPOtherStatus *int64 `stm:"http_other_status"`
62 RT *int64 `stm:"rt"`
63 UpsReq *int64 `stm:"ups_req"`
64 UpsRT *int64 `stm:"ups_rt"`
65 UpsTries *int64 `stm:"ups_tries"`
66 HTTP200 *int64 `stm:"http_200"`
67 HTTP206 *int64 `stm:"http_206"`
68 HTTP302 *int64 `stm:"http_302"`
69 HTTP304 *int64 `stm:"http_304"`
70 HTTP403 *int64 `stm:"http_403"`
71 HTTP404 *int64 `stm:"http_404"`
72 HTTP416 *int64 `stm:"http_416"`
73 HTTP499 *int64 `stm:"http_499"`
74 HTTP500 *int64 `stm:"http_500"`
75 HTTP502 *int64 `stm:"http_502"`
76 HTTP503 *int64 `stm:"http_503"`
77 HTTP504 *int64 `stm:"http_504"`
78 HTTP508 *int64 `stm:"http_508"`
79 HTTPOtherDetailStatus *int64 `stm:"http_other_detail_status"`
80 HTTPUps4xx *int64 `stm:"http_ups_4xx"`
81 HTTPUps5xx *int64 `stm:"http_ups_5xx"`
82 }
83 )
84
85 const (
86 bytesIn = "bytes_in"
87 bytesOut = "bytes_out"
88 connTotal = "conn_total"
89 reqTotal = "req_total"
90 http2xx = "http_2xx"
91 http3xx = "http_3xx"
92 http4xx = "http_4xx"
93 http5xx = "http_5xx"
94 httpOtherStatus = "http_other_status"
95 rt = "rt"
96 upsReq = "ups_req"
97 upsRT = "ups_rt"
98 upsTries = "ups_tries"
99 http200 = "http_200"
100 http206 = "http_206"
101 http302 = "http_302"
102 http304 = "http_304"
103 http403 = "http_403"
104 http404 = "http_404"
105 http416 = "http_416"
106 http499 = "http_499"
107 http500 = "http_500"
108 http502 = "http_502"
109 http503 = "http_503"
110 http504 = "http_504"
111 http508 = "http_508"
112 httpOtherDetailStatus = "http_other_detail_status"
113 httpUps4xx = "http_ups_4xx"
114 httpUps5xx = "http_ups_5xx"
115 )
116
117 var defaultLineFormat = []string{
118 bytesIn,
119 bytesOut,
120 connTotal,
121 reqTotal,
122 http2xx,
123 http3xx,
124 http4xx,
125 http5xx,
126 httpOtherStatus,
127 rt,
128 upsReq,
129 upsRT,
130 upsTries,
131 http200,
132 http206,
133 http302,
134 http304,
135 http403,
136 http404,
137 http416,
138 http499,
139 http500,
140 http502,
141 http503,
142 http504,
143 http508,
144 httpOtherDetailStatus,
145 httpUps4xx,
146 httpUps5xx,
147 }
148
149 func parseStatus(r io.Reader) (*tengineStatus, error) {
150 var status tengineStatus
151
152 s := bufio.NewScanner(r)
153 for s.Scan() {
154 m, err := parseStatusLine(s.Text(), defaultLineFormat)
155 if err != nil {
156 return nil, err
157 }
158 status = append(status, *m)
159 }
160
161 return &status, nil
162 }
163
164 func parseStatusLine(line string, lineFormat []string) (*metric, error) {
165 parts := strings.Split(line, ",")
166
167 // NOTE: only default line format is supported
168 // TODO: custom line format?
169 // www.example.com,127.0.0.1:80,162,6242,1,1,1,0,0,0,0,10,1,10,1....
170 i := findFirstInt(parts)
171 if i == -1 {
172 return nil, fmt.Errorf("invalid line : %s", line)
173 }
174 if len(parts[i:]) != len(lineFormat) {
175 return nil, fmt.Errorf("invalid line length, got %d, expected %d, line : %s",
176 len(parts[i:]), len(lineFormat), line)
177 }
178
179 // skip "$host,$server_addr:$server_port"
180 parts = parts[i:]
181
182 var m metric
183 for i, key := range lineFormat {
184 value := mustParseInt(parts[i])
185 switch key {
186 default:
187 return nil, fmt.Errorf("unknown line format key: %s", key)
188 case bytesIn:
189 m.BytesIn = value
190 case bytesOut:
191 m.BytesOut = value
192 case connTotal:
193 m.ConnTotal = value
194 case reqTotal:
195 m.ReqTotal = value
196 case http2xx:
197 m.HTTP2xx = value
198 case http3xx:
199 m.HTTP3xx = value
200 case http4xx:
201 m.HTTP4xx = value
202 case http5xx:
203 m.HTTP5xx = value
204 case httpOtherStatus:
205 m.HTTPOtherStatus = value
206 case rt:
207 m.RT = value
208 case upsReq:
209 m.UpsReq = value
210 case upsRT:
211 m.UpsRT = value
212 case upsTries:
213 m.UpsTries = value
214 case http200:
215 m.HTTP200 = value
216 case http206:
217 m.HTTP206 = value
218 case http302:
219 m.HTTP302 = value
220 case http304:
221 m.HTTP304 = value
222 case http403:
223 m.HTTP403 = value
224 case http404:
225 m.HTTP404 = value
226 case http416:
227 m.HTTP416 = value
228 case http499:
229 m.HTTP499 = value
230 case http500:
231 m.HTTP500 = value
232 case http502:
233 m.HTTP502 = value
234 case http503:
235 m.HTTP503 = value
236 case http504:
237 m.HTTP504 = value
238 case http508:
239 m.HTTP508 = value
240 case httpOtherDetailStatus:
241 m.HTTPOtherDetailStatus = value
242 case httpUps4xx:
243 m.HTTPUps4xx = value
244 case httpUps5xx:
245 m.HTTPUps5xx = value
246 }
247 }
248 return &m, nil
249 }
250
251 func findFirstInt(s []string) int {
252 for i, v := range s {
253 _, err := strconv.ParseInt(v, 10, 64)
254 if err != nil {
255 continue
256 }
257 return i
258 }
259 return -1
260 }
261
262 func mustParseInt(value string) *int64 {
263 v, err := strconv.ParseInt(value, 10, 64)
264 if err != nil {
265 panic(err)
266 }
267
268 return &v
269 }