summaryrefslogtreecommitdiffstats
path: root/src/go/plugin/go.d/modules/monit/collect.go
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/go/plugin/go.d/modules/monit/collect.go117
1 files changed, 117 insertions, 0 deletions
diff --git a/src/go/plugin/go.d/modules/monit/collect.go b/src/go/plugin/go.d/modules/monit/collect.go
new file mode 100644
index 000000000..580aa6d99
--- /dev/null
+++ b/src/go/plugin/go.d/modules/monit/collect.go
@@ -0,0 +1,117 @@
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+package monit
+
+import (
+ "encoding/xml"
+ "errors"
+ "fmt"
+ "io"
+ "net/http"
+ "net/url"
+
+ "github.com/netdata/netdata/go/plugins/plugin/go.d/pkg/web"
+
+ "golang.org/x/net/html/charset"
+)
+
+var (
+ urlPathStatus = "/_status"
+ urlQueryStatus = url.Values{"format": {"xml"}, "level": {"full"}}.Encode()
+)
+
+func (m *Monit) collect() (map[string]int64, error) {
+ mx := make(map[string]int64)
+
+ if err := m.collectStatus(mx); err != nil {
+ return nil, err
+ }
+
+ return mx, nil
+}
+
+func (m *Monit) collectStatus(mx map[string]int64) error {
+ status, err := m.fetchStatus()
+ if err != nil {
+ return err
+ }
+
+ if status.Server == nil {
+ // not Monit
+ return errors.New("invalid Monit status response: missing server data")
+ }
+
+ mx["uptime"] = status.Server.Uptime
+
+ seen := make(map[string]bool)
+
+ for _, svc := range status.Services {
+ seen[svc.id()] = true
+
+ if _, ok := m.seenServices[svc.id()]; !ok {
+ m.seenServices[svc.id()] = svc
+ m.addServiceCheckCharts(svc, status.Server)
+ }
+
+ px := fmt.Sprintf("service_check_type_%s_name_%s_status_", svc.svcType(), svc.Name)
+
+ for _, v := range []string{"not_monitored", "ok", "initializing", "error"} {
+ mx[px+v] = 0
+ if svc.status() == v {
+ mx[px+v] = 1
+ }
+ }
+ }
+
+ for id, svc := range m.seenServices {
+ if !seen[id] {
+ delete(m.seenServices, id)
+ m.removeServiceCharts(svc)
+ }
+ }
+
+ return nil
+}
+
+func (m *Monit) fetchStatus() (*monitStatus, error) {
+ req, err := web.NewHTTPRequestWithPath(m.Request, urlPathStatus)
+ if err != nil {
+ return nil, err
+ }
+ req.URL.RawQuery = urlQueryStatus
+
+ var status monitStatus
+ if err := m.doOKDecode(req, &status); err != nil {
+ return nil, err
+ }
+
+ return &status, nil
+}
+
+func (m *Monit) doOKDecode(req *http.Request, in interface{}) error {
+ resp, err := m.httpClient.Do(req)
+ if err != nil {
+ return fmt.Errorf("error on HTTP request '%s': %v", req.URL, err)
+ }
+ defer closeBody(resp)
+
+ if resp.StatusCode != http.StatusOK {
+ return fmt.Errorf("'%s' returned HTTP status code: %d", req.URL, resp.StatusCode)
+ }
+
+ dec := xml.NewDecoder(resp.Body)
+ dec.CharsetReader = charset.NewReaderLabel
+
+ if err := dec.Decode(in); err != nil {
+ return fmt.Errorf("error on decoding XML response from '%s': %v", req.URL, err)
+ }
+
+ return nil
+}
+
+func closeBody(resp *http.Response) {
+ if resp != nil && resp.Body != nil {
+ _, _ = io.Copy(io.Discard, resp.Body)
+ _ = resp.Body.Close()
+ }
+}