@cryptotaxi247 / netdata-1 / commits / fa0a549fb

add go.d/monit (#18344)

Ilya Mashchenko committed Aug 16, 2024 at 17:20 UTC fa0a549fbeda71c82412d4dc198284220ccfa365
16 files changed +1971 -1
src/collectors/python.d.plugin/python.d.conf
+1 -1
@@ -34,7 +34,6 @@ gc_interval: 300
34 example: no
35 go_expvar: no
36 # haproxy: yes
37 -# monit: yes
37 # openldap: yes
38 # oracledb: yes
39 # pandas: yes
@@ -67,6 +66,7 @@ litespeed: no # Removed (replaced with go.d/litespeed).
66 megacli: no # Removed (replaced with go.d/megacli).
67 memcached: no # Removed (replaced with go.d/memcached).
68 mongodb: no # Removed (replaced with go.d/mongodb).
69 +monit: no # Removed (replaced with go.d/monit).
70 mysql: no # Removed (replaced with go.d/mysql).
71 nginx: no # Removed (replaced with go.d/nginx).
72 nsd: no # Removed (replaced with go.d/nsd).
src/go/plugin/go.d/README.md
+1
@@ -101,6 +101,7 @@ see the appropriate collector readme.
101 | [megacli](https://github.com/netdata/netdata/tree/master/src/go/plugin/go.d/modules/megacli) | MegaCli Hardware Raid |
102 | [memcached](https://github.com/netdata/netdata/tree/master/src/go/plugin/go.d/modules/memcached) | Memcached |
103 | [mongoDB](https://github.com/netdata/netdata/tree/master/src/go/plugin/go.d/modules/mongodb) | MongoDB |
104 +| [monit](https://github.com/netdata/netdata/tree/master/src/go/plugin/go.d/modules/monit) | Monit |
105 | [mysql](https://github.com/netdata/netdata/tree/master/src/go/plugin/go.d/modules/mysql) | MySQL |
106 | [nginx](https://github.com/netdata/netdata/tree/master/src/go/plugin/go.d/modules/nginx) | NGINX |
107 | [nginxplus](https://github.com/netdata/netdata/tree/master/src/go/plugin/go.d/modules/nginxplus) | NGINX Plus |
src/go/plugin/go.d/config/go.d.conf
+1
@@ -65,6 +65,7 @@ modules:
65 # megacli: yes
66 # memcached: yes
67 # mongodb: yes
68 +# monit: yes
69 # mysql: yes
70 # nginx: yes
71 # nginxplus: yes
src/go/plugin/go.d/config/go.d/monit.conf new
+6
@@ -0,0 +1,6 @@
1 +## All available configuration options, their descriptions and default values:
2 +## https://github.com/netdata/netdata/tree/master/src/go/plugin/go.d/modules/monit#readme
3 +
4 +#jobs:
5 +# - name: local
6 +# url: http://127.0.0.1:2812
src/go/plugin/go.d/config/go.d/sd/net_listeners.conf
+9
@@ -80,6 +80,8 @@ classify:
80 expr: '{{ or (eq .Port "11211") (eq .Comm "memcached") }}'
81 - tags: "mongodb"
82 expr: '{{ or (eq .Port "27017") (eq .Comm "mongod") }}'
83 + - tags: "monit"
84 + expr: '{{ or (eq .Port "2812") (eq .Comm "monit") }}'
85 - tags: "mysql"
86 expr: '{{ or (eq .Port "3306") (eq .Comm "mysqld" "mariadbd") }}'
87 - tags: "nginx"
@@ -336,6 +338,13 @@ compose:
338 module: mongodb
339 name: local
340 uri: mongodb://{{.Address}}
341 + - selector: "monit"
342 + template: |
343 + module: monit
344 + name: local
345 + url: http://{{.Address}}
346 + username: admin
347 + password: monit
348 - selector: "mysql"
349 template: |
350 - module: mysql
src/go/plugin/go.d/modules/init.go
+1
@@ -56,6 +56,7 @@ import (
56 _ "github.com/netdata/netdata/go/plugins/plugin/go.d/modules/megacli"
57 _ "github.com/netdata/netdata/go/plugins/plugin/go.d/modules/memcached"
58 _ "github.com/netdata/netdata/go/plugins/plugin/go.d/modules/mongodb"
59 + _ "github.com/netdata/netdata/go/plugins/plugin/go.d/modules/monit"
60 _ "github.com/netdata/netdata/go/plugins/plugin/go.d/modules/mysql"
61 _ "github.com/netdata/netdata/go/plugins/plugin/go.d/modules/nginx"
62 _ "github.com/netdata/netdata/go/plugins/plugin/go.d/modules/nginxplus"
src/go/plugin/go.d/modules/monit/charts.go new
+91
@@ -0,0 +1,91 @@
1 +// SPDX-License-Identifier: GPL-3.0-or-later
2 +
3 +package monit
4 +
5 +import (
6 + "fmt"
7 + "strings"
8 +
9 + "github.com/netdata/netdata/go/plugins/plugin/go.d/agent/module"
10 +)
11 +
12 +const (
13 + prioServiceCheckStatus = module.Priority + iota
14 + prioUptime
15 +)
16 +
17 +var baseCharts = module.Charts{
18 + uptimeChart.Copy(),
19 +}
20 +
21 +var (
22 + uptimeChart = module.Chart{
23 + ID: "uptime",
24 + Title: "Uptime",
25 + Units: "seconds",
26 + Fam: "uptime",
27 + Ctx: "monit.uptime",
28 + Priority: prioUptime,
29 + Dims: module.Dims{
30 + {ID: "uptime"},
31 + },
32 + }
33 +)
34 +
35 +var serviceCheckChartsTmpl = module.Charts{
36 + serviceCheckStatusChartTmpl.Copy(),
37 +}
38 +
39 +var (
40 + serviceCheckStatusChartTmpl = module.Chart{
41 + ID: "service_check_type_%s_name_%s_status",
42 + Title: "Service Check Status",
43 + Units: "status",
44 + Fam: "service status",
45 + Ctx: "monit.service_check_status",
46 + Priority: prioServiceCheckStatus,
47 + Dims: module.Dims{
48 + {ID: "service_check_type_%s_name_%s_status_ok", Name: "ok"},
49 + {ID: "service_check_type_%s_name_%s_status_error", Name: "error"},
50 + {ID: "service_check_type_%s_name_%s_status_initializing", Name: "initializing"},
51 + {ID: "service_check_type_%s_name_%s_status_not_monitored", Name: "not_monitored"},
52 + },
53 + }
54 +)
55 +
56 +func (m *Monit) addServiceCheckCharts(svc statusServiceCheck, srv *statusServer) {
57 + charts := serviceCheckChartsTmpl.Copy()
58 +
59 + for _, chart := range *charts {
60 + chart.ID = cleanChartId(fmt.Sprintf(chart.ID, svc.svcType(), svc.Name))
61 + chart.Labels = []module.Label{
62 + {Key: "server_hostname", Value: srv.LocalHostname},
63 + {Key: "service_check_name", Value: svc.Name},
64 + {Key: "service_check_type", Value: svc.svcType()},
65 + }
66 + for _, dim := range chart.Dims {
67 + dim.ID = fmt.Sprintf(dim.ID, svc.svcType(), svc.Name)
68 + }
69 + }
70 +
71 + if err := m.Charts().Add(*charts...); err != nil {
72 + m.Warning(err)
73 + }
74 +}
75 +
76 +func (m *Monit) removeServiceCharts(svc statusServiceCheck) {
77 + px := fmt.Sprintf("service_check_type_%s_name_%s_", svc.svcType(), svc.Name)
78 + px = cleanChartId(px)
79 +
80 + for _, chart := range *m.Charts() {
81 + if strings.HasPrefix(chart.ID, px) {
82 + chart.MarkRemove()
83 + chart.MarkNotCreated()
84 + }
85 + }
86 +}
87 +
88 +func cleanChartId(s string) string {
89 + r := strings.NewReplacer(" ", "_", ".", "_", ",", "_")
90 + return r.Replace(s)
91 +}
src/go/plugin/go.d/modules/monit/collect.go new
+117
@@ -0,0 +1,117 @@
1 +// SPDX-License-Identifier: GPL-3.0-or-later
2 +
3 +package monit
4 +
5 +import (
6 + "encoding/xml"
7 + "errors"
8 + "fmt"
9 + "io"
10 + "net/http"
11 + "net/url"
12 +
13 + "github.com/netdata/netdata/go/plugins/plugin/go.d/pkg/web"
14 +
15 + "golang.org/x/net/html/charset"
16 +)
17 +
18 +var (
19 + urlPathStatus = "/_status"
20 + urlQueryStatus = url.Values{"format": {"xml"}, "level": {"full"}}.Encode()
21 +)
22 +
23 +func (m *Monit) collect() (map[string]int64, error) {
24 + mx := make(map[string]int64)
25 +
26 + if err := m.collectStatus(mx); err != nil {
27 + return nil, err
28 + }
29 +
30 + return mx, nil
31 +}
32 +
33 +func (m *Monit) collectStatus(mx map[string]int64) error {
34 + status, err := m.fetchStatus()
35 + if err != nil {
36 + return err
37 + }
38 +
39 + if status.Server == nil {
40 + // not Monit
41 + return errors.New("invalid Monit status response: missing server data")
42 + }
43 +
44 + mx["uptime"] = status.Server.Uptime
45 +
46 + seen := make(map[string]bool)
47 +
48 + for _, svc := range status.Services {
49 + seen[svc.id()] = true
50 +
51 + if _, ok := m.seenServices[svc.id()]; !ok {
52 + m.seenServices[svc.id()] = svc
53 + m.addServiceCheckCharts(svc, status.Server)
54 + }
55 +
56 + px := fmt.Sprintf("service_check_type_%s_name_%s_status_", svc.svcType(), svc.Name)
57 +
58 + for _, v := range []string{"not_monitored", "ok", "initializing", "error"} {
59 + mx[px+v] = 0
60 + if svc.status() == v {
61 + mx[px+v] = 1
62 + }
63 + }
64 + }
65 +
66 + for id, svc := range m.seenServices {
67 + if !seen[id] {
68 + delete(m.seenServices, id)
69 + m.removeServiceCharts(svc)
70 + }
71 + }
72 +
73 + return nil
74 +}
75 +
76 +func (m *Monit) fetchStatus() (*monitStatus, error) {
77 + req, err := web.NewHTTPRequestWithPath(m.Request, urlPathStatus)
78 + if err != nil {
79 + return nil, err
80 + }
81 + req.URL.RawQuery = urlQueryStatus
82 +
83 + var status monitStatus
84 + if err := m.doOKDecode(req, &status); err != nil {
85 + return nil, err
86 + }
87 +
88 + return &status, nil
89 +}
90 +
91 +func (m *Monit) doOKDecode(req *http.Request, in interface{}) error {
92 + resp, err := m.httpClient.Do(req)
93 + if err != nil {
94 + return fmt.Errorf("error on HTTP request '%s': %v", req.URL, err)
95 + }
96 + defer closeBody(resp)
97 +
98 + if resp.StatusCode != http.StatusOK {
99 + return fmt.Errorf("'%s' returned HTTP status code: %d", req.URL, resp.StatusCode)
100 + }
101 +
102 + dec := xml.NewDecoder(resp.Body)
103 + dec.CharsetReader = charset.NewReaderLabel
104 +
105 + if err := dec.Decode(in); err != nil {
106 + return fmt.Errorf("error on decoding XML response from '%s': %v", req.URL, err)
107 + }
108 +
109 + return nil
110 +}
111 +
112 +func closeBody(resp *http.Response) {
113 + if resp != nil && resp.Body != nil {
114 + _, _ = io.Copy(io.Discard, resp.Body)
115 + _ = resp.Body.Close()
116 + }
117 +}
src/go/plugin/go.d/modules/monit/config_schema.json new
+185
@@ -0,0 +1,185 @@
1 +{
2 + "jsonSchema": {
3 + "$schema": "http://json-schema.org/draft-07/schema#",
4 + "title": "Monit collector configuration.",
5 + "type": "object",
6 + "properties": {
7 + "update_every": {
8 + "title": "Update every",
9 + "description": "Data collection interval, measured in seconds.",
10 + "type": "integer",
11 + "minimum": 1,
12 + "default": 1
13 + },
14 + "url": {
15 + "title": "URL",
16 + "description": "The base URL of the Monit server.",
17 + "type": "string",
18 + "default": "http://127.0.0.1:2812",
19 + "format": "uri"
20 + },
21 + "timeout": {
22 + "title": "Timeout",
23 + "description": "The timeout in seconds for the HTTP request.",
24 + "type": "number",
25 + "minimum": 0.5,
26 + "default": 1
27 + },
28 + "not_follow_redirects": {
29 + "title": "Not follow redirects",
30 + "description": "If set, the client will not follow HTTP redirects automatically.",
31 + "type": "boolean"
32 + },
33 + "username": {
34 + "title": "Username",
35 + "description": "The username for basic authentication.",
36 + "type": "string",
37 + "sensitive": true,
38 + "default": "admin"
39 + },
40 + "password": {
41 + "title": "Password",
42 + "description": "The password for basic authentication.",
43 + "type": "string",
44 + "sensitive": true,
45 + "default": "monit"
46 + },
47 + "proxy_url": {
48 + "title": "Proxy URL",
49 + "description": "The URL of the proxy server.",
50 + "type": "string"
51 + },
52 + "proxy_username": {
53 + "title": "Proxy username",
54 + "description": "The username for proxy authentication.",
55 + "type": "string",
56 + "sensitive": true
57 + },
58 + "proxy_password": {
59 + "title": "Proxy password",
60 + "description": "The password for proxy authentication.",
61 + "type": "string",
62 + "sensitive": true
63 + },
64 + "headers": {
65 + "title": "Headers",
66 + "description": "Additional HTTP headers to include in the request.",
67 + "type": [
68 + "object",
69 + "null"
70 + ],
71 + "additionalProperties": {
72 + "type": "string"
73 + }
74 + },
75 + "tls_skip_verify": {
76 + "title": "Skip TLS verification",
77 + "description": "If set, TLS certificate verification will be skipped.",
78 + "type": "boolean"
79 + },
80 + "tls_ca": {
81 + "title": "TLS CA",
82 + "description": "The path to the CA certificate file for TLS verification.",
83 + "type": "string",
84 + "pattern": "^$|^/"
85 + },
86 + "tls_cert": {
87 + "title": "TLS certificate",
88 + "description": "The path to the client certificate file for TLS authentication.",
89 + "type": "string",
90 + "pattern": "^$|^/"
91 + },
92 + "tls_key": {
93 + "title": "TLS key",
94 + "description": "The path to the client key file for TLS authentication.",
95 + "type": "string",
96 + "pattern": "^$|^/"
97 + },
98 + "body": {
99 + "title": "Body",
100 + "type": "string"
101 + },
102 + "method": {
103 + "title": "Method",
104 + "type": "string"
105 + }
106 + },
107 + "required": [
108 + "url"
109 + ],
110 + "additionalProperties": false,
111 + "patternProperties": {
112 + "^name$": {}
113 + }
114 + },
115 + "uiSchema": {
116 + "uiOptions": {
117 + "fullPage": true
118 + },
119 + "body": {
120 + "ui:widget": "hidden"
121 + },
122 + "method": {
123 + "ui:widget": "hidden"
124 + },
125 + "timeout": {
126 + "ui:help": "Accepts decimals for precise control (e.g., type 1.5 for 1.5 seconds)."
127 + },
128 + "username": {
129 + "ui:widget": "password"
130 + },
131 + "proxy_username": {
132 + "ui:widget": "password"
133 + },
134 + "password": {
135 + "ui:widget": "password"
136 + },
137 + "proxy_password": {
138 + "ui:widget": "password"
139 + },
140 + "ui:flavour": "tabs",
141 + "ui:options": {
142 + "tabs": [
143 + {
144 + "title": "Base",
145 + "fields": [
146 + "update_every",
147 + "url",
148 + "timeout",
149 + "not_follow_redirects"
150 + ]
151 + },
152 + {
153 + "title": "Auth",
154 + "fields": [
155 + "username",
156 + "password"
157 + ]
158 + },
159 + {
160 + "title": "TLS",
161 + "fields": [
162 + "tls_skip_verify",
163 + "tls_ca",
164 + "tls_cert",
165 + "tls_key"
166 + ]
167 + },
168 + {
169 + "title": "Proxy",
170 + "fields": [
171 + "proxy_url",
172 + "proxy_username",
173 + "proxy_password"
174 + ]
175 + },
176 + {
177 + "title": "Headers",
178 + "fields": [
179 + "headers"
180 + ]
181 + }
182 + ]
183 + }
184 + }
185 +}
src/go/plugin/go.d/modules/monit/metadata.yaml new
+193
@@ -0,0 +1,193 @@
1 +plugin_name: go.d.plugin
2 +modules:
3 + - meta:
4 + id: collector-go.d.plugin-monit
5 + plugin_name: go.d.plugin
6 + module_name: monit
7 + monitored_instance:
8 + name: Monit
9 + link: https://mmonit.com/monit/
10 + categories:
11 + - data-collection.synthetic-checks
12 + icon_filename: monit.png
13 + related_resources:
14 + integrations:
15 + list: []
16 + alternative_monitored_instances: []
17 + info_provided_to_referring_integrations:
18 + description: ""
19 + keywords:
20 + - monit
21 + - mmonit
22 + - supervision tool
23 + - monitrc
24 + most_popular: false
25 + overview:
26 + data_collection:
27 + metrics_description: |
28 + This collector monitors status of Monit's service checks.
29 + method_description: |
30 + It sends HTTP requests to the Monit `/_status?format=xml&level=full` endpoint.
31 + default_behavior:
32 + auto_detection:
33 + description: |
34 + By default, it detects Monit instances running on localhost that are listening on port 2812.
35 + On startup, it tries to collect metrics from:
36 +
37 + - http://127.0.0.1:2812
38 + limits:
39 + description: ""
40 + performance_impact:
41 + description: ""
42 + additional_permissions:
43 + description: ""
44 + multi_instance: true
45 + supported_platforms:
46 + include: []
47 + exclude: []
48 + setup:
49 + prerequisites:
50 + list:
51 + - title: Enable TCP PORT
52 + description:
53 + See [Syntax for TCP port](https://mmonit.com/monit/documentation/monit.html#TCP-PORT) for details.
54 + configuration:
55 + file:
56 + name: go.d/monit.conf
57 + options:
58 + description: |
59 + The following options can be defined globally: update_every, autodetection_retry.
60 + folding:
61 + title: Config options
62 + enabled: true
63 + list:
64 + - name: update_every
65 + description: Data collection frequency.
66 + default_value: 1
67 + required: false
68 + - name: autodetection_retry
69 + description: Recheck interval in seconds. Zero means no recheck will be scheduled.
70 + default_value: 0
71 + required: false
72 + - name: url
73 + description: Server URL.
74 + default_value: http://127.0.0.1:2812
75 + required: true
76 + - name: timeout
77 + description: HTTP request timeout.
78 + default_value: 1
79 + required: false
80 + - name: username
81 + description: Username for basic HTTP authentication.
82 + default_value: "admin"
83 + required: false
84 + - name: password
85 + description: Password for basic HTTP authentication.
86 + default_value: "monit"
87 + required: false
88 + - name: proxy_url
89 + description: Proxy URL.
90 + default_value: ""
91 + required: false
92 + - name: proxy_username
93 + description: Username for proxy basic HTTP authentication.
94 + default_value: ""
95 + required: false
96 + - name: proxy_password
97 + description: Password for proxy basic HTTP authentication.
98 + default_value: ""
99 + required: false
100 + - name: method
101 + description: HTTP request method.
102 + default_value: GET
103 + required: false
104 + - name: body
105 + description: HTTP request body.
106 + default_value: ""
107 + required: false
108 + - name: headers
109 + description: HTTP request headers.
110 + default_value: ""
111 + required: false
112 + - name: not_follow_redirects
113 + description: Redirect handling policy. Controls whether the client follows redirects.
114 + default_value: false
115 + required: false
116 + - name: tls_skip_verify
117 + description: Server certificate chain and hostname validation policy. Controls whether the client performs this check.
118 + default_value: false
119 + required: false
120 + - name: tls_ca
121 + description: Certification authority that the client uses when verifying the server's certificates.
122 + default_value: ""
123 + required: false
124 + - name: tls_cert
125 + description: Client TLS certificate.
126 + default_value: ""
127 + required: false
128 + - name: tls_key
129 + description: Client TLS key.
130 + default_value: ""
131 + required: false
132 + examples:
133 + folding:
134 + title: Config
135 + enabled: true
136 + list:
137 + - name: HTTP authentication
138 + description: Basic HTTP authentication.
139 + config: |
140 + jobs:
141 + - name: local
142 + url: http://127.0.0.1:2812
143 + username: admin
144 + password: monit
145 + - name: HTTPS with self-signed certificate
146 + description: With enabled HTTPS and self-signed certificate.
147 + config: |
148 + jobs:
149 + - name: local
150 + url: http://127.0.0.1:2812
151 + tls_skip_verify: yes
152 + - name: Multi-instance
153 + description: |
154 + > **Note**: When you define multiple jobs, their names must be unique.
155 +
156 + Collecting metrics from local and remote instances.
157 + config: |
158 + jobs:
159 + - name: local
160 + url: http://127.0.0.1:2812
161 +
162 + - name: remote
163 + url: http://192.0.2.1:2812
164 + troubleshooting:
165 + problems:
166 + list: []
167 + alerts: []
168 + metrics:
169 + folding:
170 + title: Metrics
171 + enabled: false
172 + description: ""
173 + availability: []
174 + scopes:
175 + - name: service
176 + description: These metrics refer to the monitored Service.
177 + labels:
178 + - name: server_hostname
179 + description: Hostname of the Monit server.
180 + - name: service_check_name
181 + description: Service check name.
182 + - name: service_check_type
183 + description: Service check type.
184 + metrics:
185 + - name: monit.service_check_status
186 + description: Service Check Status
187 + unit: status
188 + chart_type: line
189 + dimensions:
190 + - name: ok
191 + - name: error
192 + - name: initializing
193 + - name: not_monitored
src/go/plugin/go.d/modules/monit/monit.go new
+117
@@ -0,0 +1,117 @@
1 +// SPDX-License-Identifier: GPL-3.0-or-later
2 +
3 +package monit
4 +
5 +import (
6 + _ "embed"
7 + "errors"
8 + "net/http"
9 + "time"
10 +
11 + "github.com/netdata/netdata/go/plugins/plugin/go.d/agent/module"
12 + "github.com/netdata/netdata/go/plugins/plugin/go.d/pkg/web"
13 +)
14 +
15 +//go:embed "config_schema.json"
16 +var configSchema string
17 +
18 +func init() {
19 + module.Register("monit", module.Creator{
20 + Create: func() module.Module { return New() },
21 + JobConfigSchema: configSchema,
22 + Config: func() any { return &Config{} },
23 + })
24 +}
25 +
26 +func New() *Monit {
27 + return &Monit{
28 + Config: Config{
29 + HTTP: web.HTTP{
30 + Request: web.Request{
31 + URL: "http://127.0.0.1:2812",
32 + Username: "admin",
33 + Password: "monit",
34 + },
35 + Client: web.Client{
36 + Timeout: web.Duration(time.Second),
37 + },
38 + },
39 + },
40 + charts: baseCharts.Copy(),
41 + seenServices: make(map[string]statusServiceCheck),
42 + }
43 +}
44 +
45 +type Config struct {
46 + UpdateEvery int `yaml:"update_every,omitempty" json:"update_every"`
47 + web.HTTP `yaml:",inline" json:""`
48 +}
49 +
50 +type Monit struct {
51 + module.Base
52 + Config `yaml:",inline" json:""`
53 +
54 + charts *module.Charts
55 +
56 + httpClient *http.Client
57 +
58 + seenServices map[string]statusServiceCheck
59 +}
60 +
61 +func (m *Monit) Configuration() any {
62 + return m.Config
63 +}
64 +
65 +func (m *Monit) Init() error {
66 + if m.URL == "" {
67 + m.Error("config: monit url is required but not set")
68 + return errors.New("config: missing URL")
69 + }
70 +
71 + httpClient, err := web.NewHTTPClient(m.Client)
72 + if err != nil {
73 + m.Errorf("init HTTP client: %v", err)
74 + return err
75 + }
76 + m.httpClient = httpClient
77 +
78 + m.Debugf("using URL %s", m.URL)
79 + m.Debugf("using timeout: %s", m.Timeout)
80 +
81 + return nil
82 +}
83 +
84 +func (m *Monit) Check() error {
85 + mx, err := m.collect()
86 + if err != nil {
87 + m.Error(err)
88 + return err
89 + }
90 + if len(mx) == 0 {
91 + return errors.New("no metrics collected")
92 +
93 + }
94 + return nil
95 +}
96 +
97 +func (m *Monit) Charts() *module.Charts {
98 + return m.charts
99 +}
100 +
101 +func (m *Monit) Collect() map[string]int64 {
102 + mx, err := m.collect()
103 + if err != nil {
104 + m.Error(err)
105 + }
106 +
107 + if len(mx) == 0 {
108 + return nil
109 + }
110 + return mx
111 +}
112 +
113 +func (m *Monit) Cleanup() {
114 + if m.httpClient != nil {
115 + m.httpClient.CloseIdleConnections()
116 + }
117 +}
src/go/plugin/go.d/modules/monit/monit_test.go new
+371
@@ -0,0 +1,371 @@
1 +// SPDX-License-Identifier: GPL-3.0-or-later
2 +
3 +package monit
4 +
5 +import (
6 + "net/http"
7 + "net/http/httptest"
8 + "os"
9 + "testing"
10 +
11 + "github.com/netdata/netdata/go/plugins/plugin/go.d/agent/module"
12 + "github.com/netdata/netdata/go/plugins/plugin/go.d/pkg/web"
13 +
14 + "github.com/stretchr/testify/assert"
15 + "github.com/stretchr/testify/require"
16 +)
17 +
18 +var (
19 + dataConfigJSON, _ = os.ReadFile("testdata/config.json")
20 + dataConfigYAML, _ = os.ReadFile("testdata/config.yaml")
21 +
22 + dataStatus, _ = os.ReadFile("testdata/v5.33.0/status.xml")
23 +)
24 +
25 +func Test_testDataIsValid(t *testing.T) {
26 + for name, data := range map[string][]byte{
27 + "dataConfigJSON": dataConfigJSON,
28 + "dataConfigYAML": dataConfigYAML,
29 + "dataStatus": dataStatus,
30 + } {
31 + require.NotNil(t, data, name)
32 +
33 + }
34 +}
35 +
36 +func TestMonit_ConfigurationSerialize(t *testing.T) {
37 + module.TestConfigurationSerialize(t, &Monit{}, dataConfigJSON, dataConfigYAML)
38 +}
39 +
40 +func TestMonit_Init(t *testing.T) {
41 + tests := map[string]struct {
42 + wantFail bool
43 + config Config
44 + }{
45 + "success with default": {
46 + wantFail: false,
47 + config: New().Config,
48 + },
49 + "fail when URL not set": {
50 + wantFail: true,
51 + config: Config{
52 + HTTP: web.HTTP{
53 + Request: web.Request{URL: ""},
54 + },
55 + },
56 + },
57 + }
58 +
59 + for name, test := range tests {
60 + t.Run(name, func(t *testing.T) {
61 + monit := New()
62 + monit.Config = test.config
63 +
64 + if test.wantFail {
65 + assert.Error(t, monit.Init())
66 + } else {
67 + assert.NoError(t, monit.Init())
68 + }
69 + })
70 + }
71 +}
72 +
73 +func TestMonit_Check(t *testing.T) {
74 + tests := map[string]struct {
75 + wantFail bool
76 + prepare func(t *testing.T) (monit *Monit, cleanup func())
77 + }{
78 + "success on valid response": {
79 + wantFail: false,
80 + prepare: caseOk,
81 + },
82 + "fail on unexpected XML response": {
83 + wantFail: true,
84 + prepare: caseUnexpectedXMLResponse,
85 + },
86 + "fail on invalid data response": {
87 + wantFail: true,
88 + prepare: caseInvalidDataResponse,
89 + },
90 + "fail on connection refused": {
91 + wantFail: true,
92 + prepare: caseConnectionRefused,
93 + },
94 + "fail on 404 response": {
95 + wantFail: true,
96 + prepare: case404,
97 + },
98 + }
99 +
100 + for name, test := range tests {
101 + t.Run(name, func(t *testing.T) {
102 + monit, cleanup := test.prepare(t)
103 + defer cleanup()
104 +
105 + if test.wantFail {
106 + assert.Error(t, monit.Check())
107 + } else {
108 + assert.NoError(t, monit.Check())
109 + }
110 + })
111 + }
112 +}
113 +
114 +func TestMonit_Charts(t *testing.T) {
115 + assert.NotNil(t, New().Charts())
116 +}
117 +
118 +func TestMonit_Collect(t *testing.T) {
119 + tests := map[string]struct {
120 + prepare func(t *testing.T) (monit *Monit, cleanup func())
121 + wantNumOfCharts int
122 + wantMetrics map[string]int64
123 + }{
124 + "success on valid response": {
125 + prepare: caseOk,
126 + wantNumOfCharts: len(baseCharts) + len(serviceCheckChartsTmpl)*25,
127 + wantMetrics: map[string]int64{
128 + "service_check_type_directory_name_directoryAlert_status_error": 1,
129 + "service_check_type_directory_name_directoryAlert_status_initializing": 0,
130 + "service_check_type_directory_name_directoryAlert_status_not_monitored": 0,
131 + "service_check_type_directory_name_directoryAlert_status_ok": 0,
132 + "service_check_type_directory_name_directoryDisabled_status_error": 0,
133 + "service_check_type_directory_name_directoryDisabled_status_initializing": 0,
134 + "service_check_type_directory_name_directoryDisabled_status_not_monitored": 1,
135 + "service_check_type_directory_name_directoryDisabled_status_ok": 0,
136 + "service_check_type_directory_name_directoryNotExists_status_error": 1,
137 + "service_check_type_directory_name_directoryNotExists_status_initializing": 0,
138 + "service_check_type_directory_name_directoryNotExists_status_not_monitored": 0,
139 + "service_check_type_directory_name_directoryNotExists_status_ok": 0,
140 + "service_check_type_directory_name_directoryOk_status_error": 0,
141 + "service_check_type_directory_name_directoryOk_status_initializing": 0,
142 + "service_check_type_directory_name_directoryOk_status_not_monitored": 0,
143 + "service_check_type_directory_name_directoryOk_status_ok": 1,
144 + "service_check_type_file_name_fileAlert_status_error": 1,
145 + "service_check_type_file_name_fileAlert_status_initializing": 0,
146 + "service_check_type_file_name_fileAlert_status_not_monitored": 0,
147 + "service_check_type_file_name_fileAlert_status_ok": 0,
148 + "service_check_type_file_name_fileDisabled_status_error": 0,
149 + "service_check_type_file_name_fileDisabled_status_initializing": 0,
150 + "service_check_type_file_name_fileDisabled_status_not_monitored": 1,
151 + "service_check_type_file_name_fileDisabled_status_ok": 0,
152 + "service_check_type_file_name_fileNotExists_status_error": 1,
153 + "service_check_type_file_name_fileNotExists_status_initializing": 0,
154 + "service_check_type_file_name_fileNotExists_status_not_monitored": 0,
155 + "service_check_type_file_name_fileNotExists_status_ok": 0,
156 + "service_check_type_file_name_fileOk_status_error": 0,
157 + "service_check_type_file_name_fileOk_status_initializing": 0,
158 + "service_check_type_file_name_fileOk_status_not_monitored": 0,
159 + "service_check_type_file_name_fileOk_status_ok": 1,
160 + "service_check_type_filesystem_name_filesystemAlert_status_error": 1,
161 + "service_check_type_filesystem_name_filesystemAlert_status_initializing": 0,
162 + "service_check_type_filesystem_name_filesystemAlert_status_not_monitored": 0,
163 + "service_check_type_filesystem_name_filesystemAlert_status_ok": 0,
164 + "service_check_type_filesystem_name_filesystemDisabled_status_error": 0,
165 + "service_check_type_filesystem_name_filesystemDisabled_status_initializing": 0,
166 + "service_check_type_filesystem_name_filesystemDisabled_status_not_monitored": 1,
167 + "service_check_type_filesystem_name_filesystemDisabled_status_ok": 0,
168 + "service_check_type_filesystem_name_filesystemNotExists_status_error": 1,
169 + "service_check_type_filesystem_name_filesystemNotExists_status_initializing": 0,
170 + "service_check_type_filesystem_name_filesystemNotExists_status_not_monitored": 0,
171 + "service_check_type_filesystem_name_filesystemNotExists_status_ok": 0,
172 + "service_check_type_filesystem_name_filsystemOk_status_error": 0,
173 + "service_check_type_filesystem_name_filsystemOk_status_initializing": 0,
174 + "service_check_type_filesystem_name_filsystemOk_status_not_monitored": 0,
175 + "service_check_type_filesystem_name_filsystemOk_status_ok": 1,
176 + "service_check_type_host_name_hostAlert_status_error": 1,
177 + "service_check_type_host_name_hostAlert_status_initializing": 0,
178 + "service_check_type_host_name_hostAlert_status_not_monitored": 0,
179 + "service_check_type_host_name_hostAlert_status_ok": 0,
180 + "service_check_type_host_name_hostDisabled_status_error": 0,
181 + "service_check_type_host_name_hostDisabled_status_initializing": 0,
182 + "service_check_type_host_name_hostDisabled_status_not_monitored": 1,
183 + "service_check_type_host_name_hostDisabled_status_ok": 0,
184 + "service_check_type_host_name_hostNotExists_status_error": 1,
185 + "service_check_type_host_name_hostNotExists_status_initializing": 0,
186 + "service_check_type_host_name_hostNotExists_status_not_monitored": 0,
187 + "service_check_type_host_name_hostNotExists_status_ok": 0,
188 + "service_check_type_host_name_hostOk_status_error": 0,
189 + "service_check_type_host_name_hostOk_status_initializing": 0,
190 + "service_check_type_host_name_hostOk_status_not_monitored": 0,
191 + "service_check_type_host_name_hostOk_status_ok": 1,
192 + "service_check_type_network_name_networkAlert_status_error": 1,
193 + "service_check_type_network_name_networkAlert_status_initializing": 0,
194 + "service_check_type_network_name_networkAlert_status_not_monitored": 0,
195 + "service_check_type_network_name_networkAlert_status_ok": 0,
196 + "service_check_type_network_name_networkDisabled_status_error": 0,
197 + "service_check_type_network_name_networkDisabled_status_initializing": 0,
198 + "service_check_type_network_name_networkDisabled_status_not_monitored": 1,
199 + "service_check_type_network_name_networkDisabled_status_ok": 0,
200 + "service_check_type_network_name_networkNotExists_status_error": 1,
201 + "service_check_type_network_name_networkNotExists_status_initializing": 0,
202 + "service_check_type_network_name_networkNotExists_status_not_monitored": 0,
203 + "service_check_type_network_name_networkNotExists_status_ok": 0,
204 + "service_check_type_network_name_networkOk_status_error": 0,
205 + "service_check_type_network_name_networkOk_status_initializing": 0,
206 + "service_check_type_network_name_networkOk_status_not_monitored": 0,
207 + "service_check_type_network_name_networkOk_status_ok": 1,
208 + "service_check_type_process_name_processAlert_status_error": 1,
209 + "service_check_type_process_name_processAlert_status_initializing": 0,
210 + "service_check_type_process_name_processAlert_status_not_monitored": 0,
211 + "service_check_type_process_name_processAlert_status_ok": 0,
212 + "service_check_type_process_name_processDisabled_status_error": 0,
213 + "service_check_type_process_name_processDisabled_status_initializing": 0,
214 + "service_check_type_process_name_processDisabled_status_not_monitored": 1,
215 + "service_check_type_process_name_processDisabled_status_ok": 0,
216 + "service_check_type_process_name_processNotExists_status_error": 1,
217 + "service_check_type_process_name_processNotExists_status_initializing": 0,
218 + "service_check_type_process_name_processNotExists_status_not_monitored": 0,
219 + "service_check_type_process_name_processNotExists_status_ok": 0,
220 + "service_check_type_process_name_processOk_status_error": 0,
221 + "service_check_type_process_name_processOk_status_initializing": 0,
222 + "service_check_type_process_name_processOk_status_not_monitored": 0,
223 + "service_check_type_process_name_processOk_status_ok": 1,
224 + "service_check_type_system_name_pve-deb-work_status_error": 0,
225 + "service_check_type_system_name_pve-deb-work_status_initializing": 0,
226 + "service_check_type_system_name_pve-deb-work_status_not_monitored": 0,
227 + "service_check_type_system_name_pve-deb-work_status_ok": 1,
228 + "uptime": 33,
229 + },
230 + },
231 + "fail on unexpected XML response": {
232 + prepare: caseUnexpectedXMLResponse,
233 + wantNumOfCharts: len(baseCharts),
234 + wantMetrics: nil,
235 + },
236 + "fail on invalid data response": {
237 + prepare: caseInvalidDataResponse,
238 + wantNumOfCharts: len(baseCharts),
239 + wantMetrics: nil,
240 + },
241 + "fail on connection refused": {
242 + prepare: caseConnectionRefused,
243 + wantNumOfCharts: len(baseCharts),
244 + wantMetrics: nil,
245 + },
246 + "fail on 404 response": {
247 + prepare: case404,
248 + wantNumOfCharts: len(baseCharts),
249 + wantMetrics: nil,
250 + },
251 + }
252 +
253 + for name, test := range tests {
254 + t.Run(name, func(t *testing.T) {
255 + monit, cleanup := test.prepare(t)
256 + defer cleanup()
257 +
258 + _ = monit.Check()
259 +
260 + mx := monit.Collect()
261 +
262 + require.Equal(t, test.wantMetrics, mx)
263 +
264 + if len(test.wantMetrics) > 0 {
265 + module.TestMetricsHasAllChartsDims(t, monit.Charts(), mx)
266 + assert.Equal(t, test.wantNumOfCharts, len(*monit.Charts()), "want number of charts")
267 + }
268 + })
269 + }
270 +}
271 +
272 +func caseOk(t *testing.T) (*Monit, func()) {
273 + t.Helper()
274 + srv := httptest.NewServer(http.HandlerFunc(
275 + func(w http.ResponseWriter, r *http.Request) {
276 + if r.URL.Path != urlPathStatus || r.URL.RawQuery != urlQueryStatus {
277 + w.WriteHeader(http.StatusNotFound)
278 + return
279 + }
280 + _, _ = w.Write(dataStatus)
281 + }))
282 + monit := New()
283 + monit.URL = srv.URL
284 + require.NoError(t, monit.Init())
285 +
286 + return monit, srv.Close
287 +}
288 +
289 +func caseUnexpectedXMLResponse(t *testing.T) (*Monit, func()) {
290 + t.Helper()
291 + data := `<?xml version="1.0" encoding="UTF-8"?>
292 +<Response>
293 + <Status>
294 + <Code>200</Code>
295 + <Message>Success</Message>
296 + </Status>
297 + <Data>
298 + <User>
299 + <ID>12345</ID>
300 + <Name>John Doe</Name>
301 + <Email>johndoe@example.com</Email>
302 + <Roles>
303 + <Role>Admin</Role>
304 + <Role>User</Role>
305 + </Roles>
306 + </User>
307 + <Order>
308 + <OrderID>98765</OrderID>
309 + <Date>2024-08-15</Date>
310 + <Items>
311 + <Item>
312 + <Name>Widget A</Name>
313 + <Quantity>2</Quantity>
314 + <Price>19.99</Price>
315 + </Item>
316 + <Item>
317 + <Name>Gadget B</Name>
318 + <Quantity>1</Quantity>
319 + <Price>99.99</Price>
320 + </Item>
321 + </Items>
322 + <Total>139.97</Total>
323 + </Order>
324 + </Data>
325 +</Response>
326 +`
327 + srv := httptest.NewServer(http.HandlerFunc(
328 + func(w http.ResponseWriter, r *http.Request) {
329 + _, _ = w.Write([]byte(data))
330 + }))
331 + monit := New()
332 + monit.URL = srv.URL
333 + require.NoError(t, monit.Init())
334 +
335 + return monit, srv.Close
336 +}
337 +
338 +func caseInvalidDataResponse(t *testing.T) (*Monit, func()) {
339 + t.Helper()
340 + srv := httptest.NewServer(http.HandlerFunc(
341 + func(w http.ResponseWriter, r *http.Request) {
342 + _, _ = w.Write([]byte("hello and\n goodbye"))
343 + }))
344 + monit := New()
345 + monit.URL = srv.URL
346 + require.NoError(t, monit.Init())
347 +
348 + return monit, srv.Close
349 +}
350 +
351 +func caseConnectionRefused(t *testing.T) (*Monit, func()) {
352 + t.Helper()
353 + monit := New()
354 + monit.URL = "http://127.0.0.1:65001"
355 + require.NoError(t, monit.Init())
356 +
357 + return monit, func() {}
358 +}
359 +
360 +func case404(t *testing.T) (*Monit, func()) {
361 + t.Helper()
362 + srv := httptest.NewServer(http.HandlerFunc(
363 + func(w http.ResponseWriter, r *http.Request) {
364 + w.WriteHeader(http.StatusNotFound)
365 + }))
366 + monit := New()
367 + monit.URL = srv.URL
368 + require.NoError(t, monit.Init())
369 +
370 + return monit, srv.Close
371 +}
src/go/plugin/go.d/modules/monit/status.go new
+153
@@ -0,0 +1,153 @@
1 +// SPDX-License-Identifier: GPL-3.0-or-later
2 +
3 +package monit
4 +
5 +// status_xml(): https://bitbucket.org/tildeslash/monit/src/5467d37d70c3c63c5760cddb93831bde4e17c14b/src/http/xml.c#lines-631
6 +type monitStatus struct {
7 + Server *statusServer `xml:"server"`
8 + Services []statusServiceCheck `xml:"service"`
9 +}
10 +
11 +type statusServer struct {
12 + ID string `xml:"id"`
13 + Version string `xml:"version"`
14 + Uptime int64 `xml:"uptime"`
15 + LocalHostname string `xml:"localhostname"`
16 +}
17 +
18 +// status_service(): https://bitbucket.org/tildeslash/monit/src/5467d37d70c3c63c5760cddb93831bde4e17c14b/src/http/xml.c#lines-196
19 +// struct Service_T: https://bitbucket.org/tildeslash/monit/src/5467d37d70c3c63c5760cddb93831bde4e17c14b/src/monit.h#lines-1212
20 +type statusServiceCheck struct {
21 + Type string `xml:"type,attr"`
22 + Name string `xml:"name"`
23 +
24 + Status int `xml:"status"` // Error flags bitmap
25 +
26 + // https://bitbucket.org/tildeslash/monit/src/5467d37d70c3c63c5760cddb93831bde4e17c14b/src/monit.h#lines-269
27 + MonitoringStatus int `xml:"monitor"`
28 +
29 + // https://bitbucket.org/tildeslash/monit/src/5467d37d70c3c63c5760cddb93831bde4e17c14b/src/monit.h#lines-254
30 + MonitorMode int `xml:"monitormode"`
31 +
32 + // https://bitbucket.org/tildeslash/monit/src/5467d37d70c3c63c5760cddb93831bde4e17c14b/src/monit.h#lines-261
33 + OnReboot int `xml:"onreboot"`
34 +
35 + // https://bitbucket.org/tildeslash/monit/src/5467d37d70c3c63c5760cddb93831bde4e17c14b/src/monit.h#lines-248
36 + PendingAction int `xml:"pendingaction"`
37 +}
38 +
39 +func (s *statusServiceCheck) id() string {
40 + return s.svcType() + ":" + s.Name
41 +}
42 +
43 +func (s *statusServiceCheck) svcType() string {
44 + // See enum Service_Type https://bitbucket.org/tildeslash/monit/src/master/src/monit.h
45 +
46 + switch s.Type {
47 + case "0":
48 + return "filesystem"
49 + case "1":
50 + return "directory"
51 + case "2":
52 + return "file"
53 + case "3":
54 + return "process"
55 + case "4":
56 + return "host"
57 + case "5":
58 + return "system"
59 + case "6":
60 + return "fifo"
61 + case "7":
62 + return "program"
63 + case "8":
64 + return "network"
65 + default:
66 + return "unknown"
67 + }
68 +}
69 +
70 +func (s *statusServiceCheck) status() string {
71 + // https://bitbucket.org/tildeslash/monit/src/5467d37d70c3c63c5760cddb93831bde4e17c14b/src/http/cervlet.c#lines-2866
72 +
73 + switch st := s.monitoringStatus(); st {
74 + case "not_monitored", "initializing":
75 + return st
76 + default:
77 + if s.Status != 0 {
78 + return "error"
79 + }
80 + return "ok"
81 + }
82 +}
83 +
84 +func (s *statusServiceCheck) monitoringStatus() string {
85 + switch s.MonitoringStatus {
86 + case 0:
87 + return "not_monitored"
88 + case 1:
89 + return "monitored"
90 + case 2:
91 + return "initializing"
92 + case 4:
93 + return "waiting"
94 + default:
95 + return "unknown"
96 + }
97 +}
98 +
99 +func (s *statusServiceCheck) monitorMode() string {
100 + switch s.MonitorMode {
101 + case 0:
102 + return "active"
103 + case 1:
104 + return "passive"
105 + default:
106 + return "unknown"
107 + }
108 +}
109 +
110 +func (s *statusServiceCheck) onReboot() string {
111 + switch s.OnReboot {
112 + case 0:
113 + return "start"
114 + case 1:
115 + return "no_start"
116 + default:
117 + return "unknown"
118 + }
119 +}
120 +
121 +func (s *statusServiceCheck) pendingAction() string {
122 + switch s.PendingAction {
123 + case 0:
124 + return "ignored"
125 + case 1:
126 + return "alert"
127 + case 2:
128 + return "restart"
129 + case 3:
130 + return "stop"
131 + case 4:
132 + return "exec"
133 + case 5:
134 + return "unmonitor"
135 + case 6:
136 + return "start"
137 + case 7:
138 + return "monitor"
139 + default:
140 + return "unknown"
141 + }
142 +}
143 +
144 +func (s *statusServiceCheck) hasServiceStatus() bool {
145 + // https://bitbucket.org/tildeslash/monit/src/5467d37d70c3c63c5760cddb93831bde4e17c14b/src/util.c#lines-1721
146 +
147 + const eventNonExist = 512
148 + const eventData = 2048
149 +
150 + return s.monitoringStatus() == "monitored" &&
151 + !(s.Status&eventNonExist != 0) &&
152 + !(s.Status&eventData != 0)
153 +}
src/go/plugin/go.d/modules/monit/testdata/config.json new
+20
@@ -0,0 +1,20 @@
1 +{
2 + "update_every": 123,
3 + "url": "ok",
4 + "body": "ok",
5 + "method": "ok",
6 + "headers": {
7 + "ok": "ok"
8 + },
9 + "username": "ok",
10 + "password": "ok",
11 + "proxy_url": "ok",
12 + "proxy_username": "ok",
13 + "proxy_password": "ok",
14 + "timeout": 123.123,
15 + "not_follow_redirects": true,
16 + "tls_ca": "ok",
17 + "tls_cert": "ok",
18 + "tls_key": "ok",
19 + "tls_skip_verify": true
20 +}
src/go/plugin/go.d/modules/monit/testdata/config.yaml new
+17
@@ -0,0 +1,17 @@
1 +update_every: 123
2 +url: "ok"
3 +body: "ok"
4 +method: "ok"
5 +headers:
6 + ok: "ok"
7 +username: "ok"
8 +password: "ok"
9 +proxy_url: "ok"
10 +proxy_username: "ok"
11 +proxy_password: "ok"
12 +timeout: 123.123
13 +not_follow_redirects: yes
14 +tls_ca: "ok"
15 +tls_cert: "ok"
16 +tls_key: "ok"
17 +tls_skip_verify: yes
src/go/plugin/go.d/modules/monit/testdata/v5.33.0/status.xml new
+688
@@ -0,0 +1,688 @@
1 +<?xml version="1.0" encoding="ISO-8859-1"?>
2 +<monit>
3 + <server>
4 + <id>309dc5d56ccd5964cef9b42d1d8305e7</id>
5 + <incarnation>1723810534</incarnation>
6 + <version>5.33.0</version>
7 + <uptime>33</uptime>
8 + <poll>120</poll>
9 + <startdelay>0</startdelay>
10 + <localhostname>pve-deb-work</localhostname>
11 + <controlfile>/etc/monit/monitrc</controlfile>
12 + <httpd>
13 + <address>127.0.0.1</address>
14 + <port>2812</port>
15 + <ssl>0</ssl>
16 + </httpd>
17 + </server>
18 + <platform>
19 + <name>Linux</name>
20 + <release>6.1.0-23-amd64</release>
21 + <version>#1 SMP PREEMPT_DYNAMIC Debian 6.1.99-1 (2024-07-15)</version>
22 + <machine>x86_64</machine>
23 + <cpu>16</cpu>
24 + <memory>32864100</memory>
25 + <swap>262140</swap>
26 + </platform>
27 + <service type="3">
28 + <name>processOk</name>
29 + <collected_sec>1723810534</collected_sec>
30 + <collected_usec>86510</collected_usec>
31 + <status>0</status>
32 + <status_hint>0</status_hint>
33 + <monitor>1</monitor>
34 + <monitormode>0</monitormode>
35 + <onreboot>0</onreboot>
36 + <pendingaction>0</pendingaction>
37 + <pid>843</pid>
38 + <ppid>1</ppid>
39 + <uid>0</uid>
40 + <euid>0</euid>
41 + <gid>0</gid>
42 + <uptime>66112</uptime>
43 + <threads>1</threads>
44 + <children>2</children>
45 + <memory>
46 + <percent>0.0</percent>
47 + <percenttotal>0.1</percenttotal>
48 + <kilobyte>5036</kilobyte>
49 + <kilobytetotal>34156</kilobytetotal>
50 + </memory>
51 + <cpu>
52 + <percent>-1.0</percent>
53 + <percenttotal>-1.0</percenttotal>
54 + </cpu>
55 + <filedescriptors>
56 + <open>9</open>
57 + <opentotal>34</opentotal>
58 + <limit>
59 + <soft>8192</soft>
60 + <hard>8192</hard>
61 + </limit>
62 + </filedescriptors>
63 + <read>
64 + <bytesgeneric>
65 + <count>0</count>
66 + <total>1733465</total>
67 + </bytesgeneric>
68 + <bytes>
69 + <count>0</count>
70 + <total>135168</total>
71 + </bytes>
72 + <operations>
73 + <count>0</count>
74 + <total>23145</total>
75 + </operations>
76 + </read>
77 + <write>
78 + <bytesgeneric>
79 + <count>0</count>
80 + <total>8842272</total>
81 + </bytesgeneric>
82 + <bytes>
83 + <count>0</count>
84 + <total>9150464</total>
85 + </bytes>
86 + <operations>
87 + <count>0</count>
88 + <total>22890</total>
89 + </operations>
90 + </write>
91 + </service>
92 + <service type="3">
93 + <name>processDisabled</name>
94 + <collected_sec>1723810534</collected_sec>
95 + <collected_usec>68402</collected_usec>
96 + <status>0</status>
97 + <status_hint>0</status_hint>
98 + <monitor>0</monitor>
99 + <monitormode>0</monitormode>
100 + <onreboot>0</onreboot>
101 + <pendingaction>0</pendingaction>
102 + </service>
103 + <service type="3">
104 + <name>processAlert</name>
105 + <collected_sec>1723810534</collected_sec>
106 + <collected_usec>86548</collected_usec>
107 + <status>2</status>
108 + <status_hint>0</status_hint>
109 + <monitor>1</monitor>
110 + <monitormode>0</monitormode>
111 + <onreboot>0</onreboot>
112 + <pendingaction>0</pendingaction>
113 + <pid>843</pid>
114 + <ppid>1</ppid>
115 + <uid>0</uid>
116 + <euid>0</euid>
117 + <gid>0</gid>
118 + <uptime>66112</uptime>
119 + <threads>1</threads>
120 + <children>2</children>
121 + <memory>
122 + <percent>0.0</percent>
123 + <percenttotal>0.1</percenttotal>
124 + <kilobyte>5036</kilobyte>
125 + <kilobytetotal>34156</kilobytetotal>
126 + </memory>
127 + <cpu>
128 + <percent>-1.0</percent>
129 + <percenttotal>-1.0</percenttotal>
130 + </cpu>
131 + <filedescriptors>
132 + <open>9</open>
133 + <opentotal>34</opentotal>
134 + <limit>
135 + <soft>8192</soft>
136 + <hard>8192</hard>
137 + </limit>
138 + </filedescriptors>
139 + <read>
140 + <bytesgeneric>
141 + <count>0</count>
142 + <total>1733465</total>
143 + </bytesgeneric>
144 + <bytes>
145 + <count>0</count>
146 + <total>135168</total>
147 + </bytes>
148 + <operations>
149 + <count>0</count>
150 + <total>23145</total>
151 + </operations>
152 + </read>
153 + <write>
154 + <bytesgeneric>
155 + <count>0</count>
156 + <total>8842272</total>
157 + </bytesgeneric>
158 + <bytes>
159 + <count>0</count>
160 + <total>9150464</total>
161 + </bytes>
162 + <operations>
163 + <count>0</count>
164 + <total>22890</total>
165 + </operations>
166 + </write>
167 + </service>
168 + <service type="3">
169 + <name>processNotExists</name>
170 + <collected_sec>1723810534</collected_sec>
171 + <collected_usec>86595</collected_usec>
172 + <status>4608</status>
173 + <status_hint>0</status_hint>
174 + <monitor>1</monitor>
175 + <monitormode>0</monitormode>
176 + <onreboot>0</onreboot>
177 + <pendingaction>0</pendingaction>
178 + </service>
179 + <service type="0">
180 + <name>filsystemOk</name>
181 + <collected_sec>1723810534</collected_sec>
182 + <collected_usec>86891</collected_usec>
183 + <status>0</status>
184 + <status_hint>0</status_hint>
185 + <monitor>1</monitor>
186 + <monitormode>0</monitormode>
187 + <onreboot>0</onreboot>
188 + <pendingaction>0</pendingaction>
189 + <fstype>ext2</fstype>
190 + <fsflags>rw,relatime</fsflags>
191 + <mode>660</mode>
192 + <uid>0</uid>
193 + <gid>6</gid>
194 + <block>
195 + <percent>19.6</percent>
196 + <usage>92.0</usage>
197 + <total>469.4</total>
198 + </block>
199 + <inode>
200 + <percent>0.3</percent>
201 + <usage>356</usage>
202 + <total>124928</total>
203 + </inode>
204 + <read>
205 + <bytes>
206 + <count>0</count>
207 + <total>5706752</total>
208 + </bytes>
209 + <operations>
210 + <count>0</count>
211 + <total>210</total>
212 + </operations>
213 + </read>
214 + <write>
215 + <bytes>
216 + <count>0</count>
217 + <total>1024</total>
218 + </bytes>
219 + <operations>
220 + <count>0</count>
221 + <total>1</total>
222 + </operations>
223 + </write>
224 + <servicetime>
225 + <read>0.000</read>
226 + <write>0.000</write>
227 + </servicetime>
228 + </service>
229 + <service type="0">
230 + <name>filesystemDisabled</name>
231 + <collected_sec>1723810534</collected_sec>
232 + <collected_usec>68613</collected_usec>
233 + <status>0</status>
234 + <status_hint>0</status_hint>
235 + <monitor>0</monitor>
236 + <monitormode>0</monitormode>
237 + <onreboot>0</onreboot>
238 + <pendingaction>0</pendingaction>
239 + </service>
240 + <service type="0">
241 + <name>filesystemAlert</name>
242 + <collected_sec>1723810534</collected_sec>
243 + <collected_usec>87124</collected_usec>
244 + <status>384</status>
245 + <status_hint>0</status_hint>
246 + <monitor>1</monitor>
247 + <monitormode>0</monitormode>
248 + <onreboot>0</onreboot>
249 + <pendingaction>0</pendingaction>
250 + <fstype>ext2</fstype>
251 + <fsflags>rw,relatime</fsflags>
252 + <mode>660</mode>
253 + <uid>0</uid>
254 + <gid>6</gid>
255 + <block>
256 + <percent>19.6</percent>
257 + <usage>92.0</usage>
258 + <total>469.4</total>
259 + </block>
260 + <inode>
261 + <percent>0.3</percent>
262 + <usage>356</usage>
263 + <total>124928</total>
264 + </inode>
265 + <read>
266 + <bytes>
267 + <count>0</count>
268 + <total>5706752</total>
269 + </bytes>
270 + <operations>
271 + <count>0</count>
272 + <total>210</total>
273 + </operations>
274 + </read>
275 + <write>
276 + <bytes>
277 + <count>0</count>
278 + <total>1024</total>
279 + </bytes>
280 + <operations>
281 + <count>0</count>
282 + <total>1</total>
283 + </operations>
284 + </write>
285 + <servicetime>
286 + <read>0.000</read>
287 + <write>0.000</write>
288 + </servicetime>
289 + </service>
290 + <service type="0">
291 + <name>filesystemNotExists</name>
292 + <collected_sec>1723810534</collected_sec>
293 + <collected_usec>87334</collected_usec>
294 + <status>512</status>
295 + <status_hint>0</status_hint>
296 + <monitor>1</monitor>
297 + <monitormode>0</monitormode>
298 + <onreboot>0</onreboot>
299 + <pendingaction>0</pendingaction>
300 + </service>
301 + <service type="2">
302 + <name>fileOk</name>
303 + <collected_sec>1723810534</collected_sec>
304 + <collected_usec>87339</collected_usec>
305 + <status>0</status>
306 + <status_hint>0</status_hint>
307 + <monitor>1</monitor>
308 + <monitormode>0</monitormode>
309 + <onreboot>0</onreboot>
310 + <pendingaction>0</pendingaction>
311 + <mode>755</mode>
312 + <uid>0</uid>
313 + <gid>0</gid>
314 + <timestamps>
315 + <access>1723744256</access>
316 + <change>1723744256</change>
317 + <modify>1723744256</modify>
318 + </timestamps>
319 + <size>84820392</size>
320 + </service>
321 + <service type="2">
322 + <name>fileDisabled</name>
323 + <collected_sec>1723810534</collected_sec>
324 + <collected_usec>68835</collected_usec>
325 + <status>0</status>
326 + <status_hint>0</status_hint>
327 + <monitor>0</monitor>
328 + <monitormode>0</monitormode>
329 + <onreboot>0</onreboot>
330 + <pendingaction>0</pendingaction>
331 + </service>
332 + <service type="2">
333 + <name>fileAlert</name>
334 + <collected_sec>1723810534</collected_sec>
335 + <collected_usec>87356</collected_usec>
336 + <status>384</status>
337 + <status_hint>0</status_hint>
338 + <monitor>1</monitor>
339 + <monitormode>0</monitormode>
340 + <onreboot>0</onreboot>
341 + <pendingaction>0</pendingaction>
342 + <mode>755</mode>
343 + <uid>0</uid>
344 + <gid>0</gid>
345 + <timestamps>
346 + <access>1723744256</access>
347 + <change>1723744256</change>
348 + <modify>1723744256</modify>
349 + </timestamps>
350 + <size>84820392</size>
351 + </service>
352 + <service type="2">
353 + <name>fileNotExists</name>
354 + <collected_sec>1723810534</collected_sec>
355 + <collected_usec>87371</collected_usec>
356 + <status>512</status>
357 + <status_hint>0</status_hint>
358 + <monitor>1</monitor>
359 + <monitormode>0</monitormode>
360 + <onreboot>0</onreboot>
361 + <pendingaction>0</pendingaction>
362 + </service>
363 + <service type="1">
364 + <name>directoryOk</name>
365 + <collected_sec>1723810534</collected_sec>
366 + <collected_usec>87375</collected_usec>
367 + <status>0</status>
368 + <status_hint>0</status_hint>
369 + <monitor>1</monitor>
370 + <monitormode>0</monitormode>
371 + <onreboot>0</onreboot>
372 + <pendingaction>0</pendingaction>
373 + <mode>775</mode>
374 + <uid>0</uid>
375 + <gid>0</gid>
376 + <timestamps>
377 + <access>1723740545</access>
378 + <change>1720694060</change>
379 + <modify>1720694060</modify>
380 + </timestamps>
381 + </service>
382 + <service type="1">
383 + <name>directoryDisabled</name>
384 + <collected_sec>1723810534</collected_sec>
385 + <collected_usec>68957</collected_usec>
386 + <status>0</status>
387 + <status_hint>0</status_hint>
388 + <monitor>0</monitor>
389 + <monitormode>0</monitormode>
390 + <onreboot>0</onreboot>
391 + <pendingaction>0</pendingaction>
392 + </service>
393 + <service type="1">
394 + <name>directoryAlert</name>
395 + <collected_sec>1723810534</collected_sec>
396 + <collected_usec>87385</collected_usec>
397 + <status>64</status>
398 + <status_hint>0</status_hint>
399 + <monitor>1</monitor>
400 + <monitormode>0</monitormode>
401 + <onreboot>0</onreboot>
402 + <pendingaction>0</pendingaction>
403 + <mode>775</mode>
404 + <uid>0</uid>
405 + <gid>0</gid>
406 + <timestamps>
407 + <access>1723740545</access>
408 + <change>1720694060</change>
409 + <modify>1720694060</modify>
410 + </timestamps>
411 + </service>
412 + <service type="1">
413 + <name>directoryNotExists</name>
414 + <collected_sec>1723810534</collected_sec>
415 + <collected_usec>87400</collected_usec>
416 + <status>512</status>
417 + <status_hint>0</status_hint>
418 + <monitor>1</monitor>
419 + <monitormode>0</monitormode>
420 + <onreboot>0</onreboot>
421 + <pendingaction>0</pendingaction>
422 + </service>
423 + <service type="4">
424 + <name>hostOk</name>
425 + <collected_sec>1723810534</collected_sec>
426 + <collected_usec>89652</collected_usec>
427 + <status>0</status>
428 + <status_hint>0</status_hint>
429 + <monitor>1</monitor>
430 + <monitormode>0</monitormode>
431 + <onreboot>0</onreboot>
432 + <pendingaction>0</pendingaction>
433 + <icmp>
434 + <type>Ping</type>
435 + <responsetime>0.000144</responsetime>
436 + </icmp>
437 + <port>
438 + <hostname>10.20.4.200</hostname>
439 + <portnumber>19999</portnumber>
440 + <request><![CDATA[/api/v1/info]]></request>
441 + <protocol>HTTP</protocol>
442 + <type>TCP</type>
443 + <responsetime>0.002077</responsetime>
444 + </port>
445 + </service>
446 + <service type="4">
447 + <name>hostDisabled</name>
448 + <collected_sec>1723810534</collected_sec>
449 + <collected_usec>69066</collected_usec>
450 + <status>0</status>
451 + <status_hint>0</status_hint>
452 + <monitor>0</monitor>
453 + <monitormode>0</monitormode>
454 + <onreboot>0</onreboot>
455 + <pendingaction>0</pendingaction>
456 + </service>
457 + <service type="4">
458 + <name>hostAlert</name>
459 + <collected_sec>1723810534</collected_sec>
460 + <collected_usec>89857</collected_usec>
461 + <status>32</status>
462 + <status_hint>0</status_hint>
463 + <monitor>1</monitor>
464 + <monitormode>0</monitormode>
465 + <onreboot>0</onreboot>
466 + <pendingaction>0</pendingaction>
467 + <icmp>
468 + <type>Ping</type>
469 + <responsetime>0.000069</responsetime>
470 + </icmp>
471 + <port>
472 + <hostname>10.20.4.200</hostname>
473 + <portnumber>19991</portnumber>
474 + <request><![CDATA[/api/v1/info]]></request>
475 + <protocol>HTTP</protocol>
476 + <type>TCP</type>
477 + <responsetime>-1.000000</responsetime>
478 + </port>
479 + </service>
480 + <service type="4">
481 + <name>hostNotExists</name>
482 + <collected_sec>1723810549</collected_sec>
483 + <collected_usec>94459</collected_usec>
484 + <status>16384</status>
485 + <status_hint>0</status_hint>
486 + <monitor>1</monitor>
487 + <monitormode>0</monitormode>
488 + <onreboot>0</onreboot>
489 + <pendingaction>0</pendingaction>
490 + <icmp>
491 + <type>Ping</type>
492 + <responsetime>-1.000000</responsetime>
493 + </icmp>
494 + <port>
495 + <hostname>10.20.4.233</hostname>
496 + <portnumber>19999</portnumber>
497 + <request><![CDATA[/api/v1/info]]></request>
498 + <protocol>HTTP</protocol>
499 + <type>TCP</type>
500 + <responsetime>-1.000000</responsetime>
501 + </port>
502 + </service>
503 + <service type="8">
504 + <name>networkOk</name>
505 + <collected_sec>1723810549</collected_sec>
506 + <collected_usec>94801</collected_usec>
507 + <status>0</status>
508 + <status_hint>0</status_hint>
509 + <monitor>1</monitor>
510 + <monitormode>0</monitormode>
511 + <onreboot>0</onreboot>
512 + <pendingaction>0</pendingaction>
513 + <link>
514 + <state>1</state>
515 + <speed>-1000000</speed>
516 + <duplex>-1</duplex>
517 + <download>
518 + <packets>
519 + <now>0</now>
520 + <total>319258</total>
521 + </packets>
522 + <bytes>
523 + <now>0</now>
524 + <total>714558077</total>
525 + </bytes>
526 + <errors>
527 + <now>0</now>
528 + <total>0</total>
529 + </errors>
530 + </download>
531 + <upload>
532 + <packets>
533 + <now>0</now>
534 + <total>172909</total>
535 + </packets>
536 + <bytes>
537 + <now>0</now>
538 + <total>25128489</total>
539 + </bytes>
540 + <errors>
541 + <now>0</now>
542 + <total>0</total>
543 + </errors>
544 + </upload>
545 + </link>
546 + </service>
547 + <service type="8">
548 + <name>networkDisabled</name>
549 + <collected_sec>1723810534</collected_sec>
550 + <collected_usec>69103</collected_usec>
551 + <status>0</status>
552 + <status_hint>0</status_hint>
553 + <monitor>0</monitor>
554 + <monitormode>0</monitormode>
555 + <onreboot>0</onreboot>
556 + <pendingaction>0</pendingaction>
557 + </service>
558 + <service type="8">
559 + <name>networkAlert</name>
560 + <collected_sec>1723810549</collected_sec>
561 + <collected_usec>94969</collected_usec>
562 + <status>8388608</status>
563 + <status_hint>0</status_hint>
564 + <monitor>1</monitor>
565 + <monitormode>0</monitormode>
566 + <onreboot>0</onreboot>
567 + <pendingaction>0</pendingaction>
568 + <link>
569 + <state>0</state>
570 + <speed>-1</speed>
571 + <duplex>-1</duplex>
572 + <download>
573 + <packets>
574 + <now>-1</now>
575 + <total>-1</total>
576 + </packets>
577 + <bytes>
578 + <now>-1</now>
579 + <total>-1</total>
580 + </bytes>
581 + <errors>
582 + <now>-1</now>
583 + <total>-1</total>
584 + </errors>
585 + </download>
586 + <upload>
587 + <packets>
588 + <now>-1</now>
589 + <total>-1</total>
590 + </packets>
591 + <bytes>
592 + <now>-1</now>
593 + <total>-1</total>
594 + </bytes>
595 + <errors>
596 + <now>-1</now>
597 + <total>-1</total>
598 + </errors>
599 + </upload>
600 + </link>
601 + </service>
602 + <service type="8">
603 + <name>networkNotExists</name>
604 + <collected_sec>1723810549</collected_sec>
605 + <collected_usec>94992</collected_usec>
606 + <status>8388608</status>
607 + <status_hint>0</status_hint>
608 + <monitor>1</monitor>
609 + <monitormode>0</monitormode>
610 + <onreboot>0</onreboot>
611 + <pendingaction>0</pendingaction>
612 + <link>
613 + <state>-1</state>
614 + <speed>-1</speed>
615 + <duplex>-1</duplex>
616 + <download>
617 + <packets>
618 + <now>-1</now>
619 + <total>-1</total>
620 + </packets>
621 + <bytes>
622 + <now>-1</now>
623 + <total>-1</total>
624 + </bytes>
625 + <errors>
626 + <now>-1</now>
627 + <total>-1</total>
628 + </errors>
629 + </download>
630 + <upload>
631 + <packets>
632 + <now>-1</now>
633 + <total>-1</total>
634 + </packets>
635 + <bytes>
636 + <now>-1</now>
637 + <total>-1</total>
638 + </bytes>
639 + <errors>
640 + <now>-1</now>
641 + <total>-1</total>
642 + </errors>
643 + </upload>
644 + </link>
645 + </service>
646 + <service type="5">
647 + <name>pve-deb-work</name>
648 + <collected_sec>1723810549</collected_sec>
649 + <collected_usec>94992</collected_usec>
650 + <status>0</status>
651 + <status_hint>0</status_hint>
652 + <monitor>1</monitor>
653 + <monitormode>0</monitormode>
654 + <onreboot>0</onreboot>
655 + <pendingaction>0</pendingaction>
656 + <filedescriptors>
657 + <allocated>1664</allocated>
658 + <unused>0</unused>
659 + <maximum>9223372036854775807</maximum>
660 + </filedescriptors>
661 + <system>
662 + <load>
663 + <avg01>0.00</avg01>
664 + <avg05>0.04</avg05>
665 + <avg15>0.03</avg15>
666 + </load>
667 + <cpu>
668 + <user>0.0</user>
669 + <system>0.0</system>
670 + <nice>0.0</nice>
671 + <wait>0.0</wait>
672 + <hardirq>0.0</hardirq>
673 + <softirq>0.0</softirq>
674 + <steal>0.0</steal>
675 + <guest>0.0</guest>
676 + <guestnice>0.0</guestnice>
677 + </cpu>
678 + <memory>
679 + <percent>3.1</percent>
680 + <kilobyte>1020120</kilobyte>
681 + </memory>
682 + <swap>
683 + <percent>0.0</percent>
684 + <kilobyte>0</kilobyte>
685 + </swap>
686 + </system>
687 + </service>
688 +</monit>