diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-05 12:08:03 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-05 12:08:18 +0000 |
commit | 5da14042f70711ea5cf66e034699730335462f66 (patch) | |
tree | 0f6354ccac934ed87a2d555f45be4c831cf92f4a /src/go/collectors/go.d.plugin/modules/nginx/apiclient.go | |
parent | Releasing debian version 1.44.3-2. (diff) | |
download | netdata-5da14042f70711ea5cf66e034699730335462f66.tar.xz netdata-5da14042f70711ea5cf66e034699730335462f66.zip |
Merging upstream version 1.45.3+dfsg.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r-- | src/go/collectors/go.d.plugin/modules/nginx/apiclient.go | 168 |
1 files changed, 168 insertions, 0 deletions
diff --git a/src/go/collectors/go.d.plugin/modules/nginx/apiclient.go b/src/go/collectors/go.d.plugin/modules/nginx/apiclient.go new file mode 100644 index 000000000..8e1003b44 --- /dev/null +++ b/src/go/collectors/go.d.plugin/modules/nginx/apiclient.go @@ -0,0 +1,168 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +package nginx + +import ( + "bufio" + "fmt" + "io" + "net/http" + "regexp" + "strconv" + "strings" + + "github.com/netdata/netdata/go/go.d.plugin/pkg/web" +) + +const ( + connActive = "connActive" + connAccepts = "connAccepts" + connHandled = "connHandled" + requests = "requests" + requestTime = "requestTime" + connReading = "connReading" + connWriting = "connWriting" + connWaiting = "connWaiting" +) + +var ( + nginxSeq = []string{ + connActive, + connAccepts, + connHandled, + requests, + connReading, + connWriting, + connWaiting, + } + tengineSeq = []string{ + connActive, + connAccepts, + connHandled, + requests, + requestTime, + connReading, + connWriting, + connWaiting, + } + + reStatus = regexp.MustCompile(`^Active connections: ([0-9]+)\n[^\d]+([0-9]+) ([0-9]+) ([0-9]+) ?([0-9]+)?\nReading: ([0-9]+) Writing: ([0-9]+) Waiting: ([0-9]+)`) +) + +func newAPIClient(client *http.Client, request web.Request) *apiClient { + return &apiClient{httpClient: client, request: request} +} + +type apiClient struct { + httpClient *http.Client + request web.Request +} + +func (a apiClient) getStubStatus() (*stubStatus, error) { + req, err := web.NewHTTPRequest(a.request) + if err != nil { + return nil, fmt.Errorf("error on creating request : %v", err) + } + + resp, err := a.doRequestOK(req) + defer closeBody(resp) + if err != nil { + return nil, err + } + + status, err := parseStubStatus(resp.Body) + if err != nil { + return nil, fmt.Errorf("error on parsing response : %v", err) + } + + return status, nil +} + +func (a apiClient) doRequestOK(req *http.Request) (*http.Response, error) { + resp, err := a.httpClient.Do(req) + if err != nil { + return resp, fmt.Errorf("error on request : %v", err) + } + + if resp.StatusCode != http.StatusOK { + return resp, fmt.Errorf("%s returned HTTP status %d", req.URL, resp.StatusCode) + } + + return resp, err +} + +func closeBody(resp *http.Response) { + if resp != nil && resp.Body != nil { + _, _ = io.Copy(io.Discard, resp.Body) + _ = resp.Body.Close() + } +} + +func parseStubStatus(r io.Reader) (*stubStatus, error) { + sc := bufio.NewScanner(r) + var lines []string + + for sc.Scan() { + lines = append(lines, strings.Trim(sc.Text(), "\r\n ")) + } + + parsed := reStatus.FindStringSubmatch(strings.Join(lines, "\n")) + + if len(parsed) == 0 { + return nil, fmt.Errorf("can't parse '%v'", lines) + } + + parsed = parsed[1:] + + var ( + seq []string + status stubStatus + ) + + switch len(parsed) { + default: + return nil, fmt.Errorf("invalid number of fields, got %d, expect %d or %d", len(parsed), len(nginxSeq), len(tengineSeq)) + case len(nginxSeq): + seq = nginxSeq + case len(tengineSeq): + seq = tengineSeq + } + + for i, key := range seq { + strValue := parsed[i] + if strValue == "" { + continue + } + value := mustParseInt(strValue) + switch key { + default: + return nil, fmt.Errorf("unknown key in seq : %s", key) + case connActive: + status.Connections.Active = value + case connAccepts: + status.Connections.Accepts = value + case connHandled: + status.Connections.Handled = value + case requests: + status.Requests.Total = value + case connReading: + status.Connections.Reading = value + case connWriting: + status.Connections.Writing = value + case connWaiting: + status.Connections.Waiting = value + case requestTime: + status.Requests.Time = &value + } + } + + return &status, nil +} + +func mustParseInt(value string) int64 { + v, err := strconv.ParseInt(value, 10, 64) + if err != nil { + panic(err) + } + return v +} |