diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-08-26 08:15:20 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-08-26 08:15:20 +0000 |
commit | 87d772a7d708fec12f48cd8adc0dedff6e1025da (patch) | |
tree | 1fee344c64cc3f43074a01981e21126c8482a522 /src/go/plugin/go.d/modules/monit | |
parent | Adding upstream version 1.46.3. (diff) | |
download | netdata-87d772a7d708fec12f48cd8adc0dedff6e1025da.tar.xz netdata-87d772a7d708fec12f48cd8adc0dedff6e1025da.zip |
Adding upstream version 1.47.0.upstream/1.47.0
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/go/plugin/go.d/modules/monit')
l--------- | src/go/plugin/go.d/modules/monit/README.md | 1 | ||||
-rw-r--r-- | src/go/plugin/go.d/modules/monit/charts.go | 91 | ||||
-rw-r--r-- | src/go/plugin/go.d/modules/monit/collect.go | 117 | ||||
-rw-r--r-- | src/go/plugin/go.d/modules/monit/config_schema.json | 185 | ||||
-rw-r--r-- | src/go/plugin/go.d/modules/monit/integrations/monit.md | 255 | ||||
-rw-r--r-- | src/go/plugin/go.d/modules/monit/metadata.yaml | 193 | ||||
-rw-r--r-- | src/go/plugin/go.d/modules/monit/monit.go | 117 | ||||
-rw-r--r-- | src/go/plugin/go.d/modules/monit/monit_test.go | 371 | ||||
-rw-r--r-- | src/go/plugin/go.d/modules/monit/status.go | 153 | ||||
-rw-r--r-- | src/go/plugin/go.d/modules/monit/testdata/config.json | 20 | ||||
-rw-r--r-- | src/go/plugin/go.d/modules/monit/testdata/config.yaml | 17 | ||||
-rw-r--r-- | src/go/plugin/go.d/modules/monit/testdata/v5.33.0/status.xml | 688 |
12 files changed, 2208 insertions, 0 deletions
diff --git a/src/go/plugin/go.d/modules/monit/README.md b/src/go/plugin/go.d/modules/monit/README.md new file mode 120000 index 000000000..ac69496f4 --- /dev/null +++ b/src/go/plugin/go.d/modules/monit/README.md @@ -0,0 +1 @@ +integrations/monit.md
\ No newline at end of file diff --git a/src/go/plugin/go.d/modules/monit/charts.go b/src/go/plugin/go.d/modules/monit/charts.go new file mode 100644 index 000000000..58fcf6c78 --- /dev/null +++ b/src/go/plugin/go.d/modules/monit/charts.go @@ -0,0 +1,91 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +package monit + +import ( + "fmt" + "strings" + + "github.com/netdata/netdata/go/plugins/plugin/go.d/agent/module" +) + +const ( + prioServiceCheckStatus = module.Priority + iota + prioUptime +) + +var baseCharts = module.Charts{ + uptimeChart.Copy(), +} + +var ( + uptimeChart = module.Chart{ + ID: "uptime", + Title: "Uptime", + Units: "seconds", + Fam: "uptime", + Ctx: "monit.uptime", + Priority: prioUptime, + Dims: module.Dims{ + {ID: "uptime"}, + }, + } +) + +var serviceCheckChartsTmpl = module.Charts{ + serviceCheckStatusChartTmpl.Copy(), +} + +var ( + serviceCheckStatusChartTmpl = module.Chart{ + ID: "service_check_type_%s_name_%s_status", + Title: "Service Check Status", + Units: "status", + Fam: "service status", + Ctx: "monit.service_check_status", + Priority: prioServiceCheckStatus, + Dims: module.Dims{ + {ID: "service_check_type_%s_name_%s_status_ok", Name: "ok"}, + {ID: "service_check_type_%s_name_%s_status_error", Name: "error"}, + {ID: "service_check_type_%s_name_%s_status_initializing", Name: "initializing"}, + {ID: "service_check_type_%s_name_%s_status_not_monitored", Name: "not_monitored"}, + }, + } +) + +func (m *Monit) addServiceCheckCharts(svc statusServiceCheck, srv *statusServer) { + charts := serviceCheckChartsTmpl.Copy() + + for _, chart := range *charts { + chart.ID = cleanChartId(fmt.Sprintf(chart.ID, svc.svcType(), svc.Name)) + chart.Labels = []module.Label{ + {Key: "server_hostname", Value: srv.LocalHostname}, + {Key: "service_check_name", Value: svc.Name}, + {Key: "service_check_type", Value: svc.svcType()}, + } + for _, dim := range chart.Dims { + dim.ID = fmt.Sprintf(dim.ID, svc.svcType(), svc.Name) + } + } + + if err := m.Charts().Add(*charts...); err != nil { + m.Warning(err) + } +} + +func (m *Monit) removeServiceCharts(svc statusServiceCheck) { + px := fmt.Sprintf("service_check_type_%s_name_%s_", svc.svcType(), svc.Name) + px = cleanChartId(px) + + for _, chart := range *m.Charts() { + if strings.HasPrefix(chart.ID, px) { + chart.MarkRemove() + chart.MarkNotCreated() + } + } +} + +func cleanChartId(s string) string { + r := strings.NewReplacer(" ", "_", ".", "_", ",", "_") + return r.Replace(s) +} 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() + } +} diff --git a/src/go/plugin/go.d/modules/monit/config_schema.json b/src/go/plugin/go.d/modules/monit/config_schema.json new file mode 100644 index 000000000..4d23760b3 --- /dev/null +++ b/src/go/plugin/go.d/modules/monit/config_schema.json @@ -0,0 +1,185 @@ +{ + "jsonSchema": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "Monit collector configuration.", + "type": "object", + "properties": { + "update_every": { + "title": "Update every", + "description": "Data collection interval, measured in seconds.", + "type": "integer", + "minimum": 1, + "default": 1 + }, + "url": { + "title": "URL", + "description": "The base URL of the Monit server.", + "type": "string", + "default": "http://127.0.0.1:2812", + "format": "uri" + }, + "timeout": { + "title": "Timeout", + "description": "The timeout in seconds for the HTTP request.", + "type": "number", + "minimum": 0.5, + "default": 1 + }, + "not_follow_redirects": { + "title": "Not follow redirects", + "description": "If set, the client will not follow HTTP redirects automatically.", + "type": "boolean" + }, + "username": { + "title": "Username", + "description": "The username for basic authentication.", + "type": "string", + "sensitive": true, + "default": "admin" + }, + "password": { + "title": "Password", + "description": "The password for basic authentication.", + "type": "string", + "sensitive": true, + "default": "monit" + }, + "proxy_url": { + "title": "Proxy URL", + "description": "The URL of the proxy server.", + "type": "string" + }, + "proxy_username": { + "title": "Proxy username", + "description": "The username for proxy authentication.", + "type": "string", + "sensitive": true + }, + "proxy_password": { + "title": "Proxy password", + "description": "The password for proxy authentication.", + "type": "string", + "sensitive": true + }, + "headers": { + "title": "Headers", + "description": "Additional HTTP headers to include in the request.", + "type": [ + "object", + "null" + ], + "additionalProperties": { + "type": "string" + } + }, + "tls_skip_verify": { + "title": "Skip TLS verification", + "description": "If set, TLS certificate verification will be skipped.", + "type": "boolean" + }, + "tls_ca": { + "title": "TLS CA", + "description": "The path to the CA certificate file for TLS verification.", + "type": "string", + "pattern": "^$|^/" + }, + "tls_cert": { + "title": "TLS certificate", + "description": "The path to the client certificate file for TLS authentication.", + "type": "string", + "pattern": "^$|^/" + }, + "tls_key": { + "title": "TLS key", + "description": "The path to the client key file for TLS authentication.", + "type": "string", + "pattern": "^$|^/" + }, + "body": { + "title": "Body", + "type": "string" + }, + "method": { + "title": "Method", + "type": "string" + } + }, + "required": [ + "url" + ], + "additionalProperties": false, + "patternProperties": { + "^name$": {} + } + }, + "uiSchema": { + "uiOptions": { + "fullPage": true + }, + "body": { + "ui:widget": "hidden" + }, + "method": { + "ui:widget": "hidden" + }, + "timeout": { + "ui:help": "Accepts decimals for precise control (e.g., type 1.5 for 1.5 seconds)." + }, + "username": { + "ui:widget": "password" + }, + "proxy_username": { + "ui:widget": "password" + }, + "password": { + "ui:widget": "password" + }, + "proxy_password": { + "ui:widget": "password" + }, + "ui:flavour": "tabs", + "ui:options": { + "tabs": [ + { + "title": "Base", + "fields": [ + "update_every", + "url", + "timeout", + "not_follow_redirects" + ] + }, + { + "title": "Auth", + "fields": [ + "username", + "password" + ] + }, + { + "title": "TLS", + "fields": [ + "tls_skip_verify", + "tls_ca", + "tls_cert", + "tls_key" + ] + }, + { + "title": "Proxy", + "fields": [ + "proxy_url", + "proxy_username", + "proxy_password" + ] + }, + { + "title": "Headers", + "fields": [ + "headers" + ] + } + ] + } + } +} diff --git a/src/go/plugin/go.d/modules/monit/integrations/monit.md b/src/go/plugin/go.d/modules/monit/integrations/monit.md new file mode 100644 index 000000000..8d3739ac4 --- /dev/null +++ b/src/go/plugin/go.d/modules/monit/integrations/monit.md @@ -0,0 +1,255 @@ +<!--startmeta +custom_edit_url: "https://github.com/netdata/netdata/edit/master/src/go/plugin/go.d/modules/monit/README.md" +meta_yaml: "https://github.com/netdata/netdata/edit/master/src/go/plugin/go.d/modules/monit/metadata.yaml" +sidebar_label: "Monit" +learn_status: "Published" +learn_rel_path: "Collecting Metrics/Synthetic Checks" +most_popular: False +message: "DO NOT EDIT THIS FILE DIRECTLY, IT IS GENERATED BY THE COLLECTOR'S metadata.yaml FILE" +endmeta--> + +# Monit + + +<img src="https://netdata.cloud/img/monit.png" width="150"/> + + +Plugin: go.d.plugin +Module: monit + +<img src="https://img.shields.io/badge/maintained%20by-Netdata-%2300ab44" /> + +## Overview + +This collector monitors status of Monit's service checks. + + +It sends HTTP requests to the Monit `/_status?format=xml&level=full` endpoint. + + +This collector is supported on all platforms. + +This collector supports collecting metrics from multiple instances of this integration, including remote instances. + + +### Default Behavior + +#### Auto-Detection + +By default, it detects Monit instances running on localhost that are listening on port 2812. +On startup, it tries to collect metrics from: + +- http://127.0.0.1:2812 + + +#### Limits + +The default configuration for this integration does not impose any limits on data collection. + +#### Performance Impact + +The default configuration for this integration is not expected to impose a significant performance impact on the system. + + +## Metrics + +Metrics grouped by *scope*. + +The scope defines the instance that the metric belongs to. An instance is uniquely identified by a set of labels. + + + +### Per service + +These metrics refer to the monitored Service. + +Labels: + +| Label | Description | +|:-----------|:----------------| +| server_hostname | Hostname of the Monit server. | +| service_check_name | Service check name. | +| service_check_type | Service check type. | + +Metrics: + +| Metric | Dimensions | Unit | +|:------|:----------|:----| +| monit.service_check_status | ok, error, initializing, not_monitored | status | + + + +## Alerts + +There are no alerts configured by default for this integration. + + +## Setup + +### Prerequisites + +#### Enable TCP PORT + +See [Syntax for TCP port](https://mmonit.com/monit/documentation/monit.html#TCP-PORT) for details. + + +### Configuration + +#### File + +The configuration file name for this integration is `go.d/monit.conf`. + + +You can edit the configuration file using the `edit-config` script from the +Netdata [config directory](/docs/netdata-agent/configuration/README.md#the-netdata-config-directory). + +```bash +cd /etc/netdata 2>/dev/null || cd /opt/netdata/etc/netdata +sudo ./edit-config go.d/monit.conf +``` +#### Options + +The following options can be defined globally: update_every, autodetection_retry. + + +<details open><summary>Config options</summary> + +| Name | Description | Default | Required | +|:----|:-----------|:-------|:--------:| +| update_every | Data collection frequency. | 1 | no | +| autodetection_retry | Recheck interval in seconds. Zero means no recheck will be scheduled. | 0 | no | +| url | Server URL. | http://127.0.0.1:2812 | yes | +| timeout | HTTP request timeout. | 1 | no | +| username | Username for basic HTTP authentication. | admin | no | +| password | Password for basic HTTP authentication. | monit | no | +| proxy_url | Proxy URL. | | no | +| proxy_username | Username for proxy basic HTTP authentication. | | no | +| proxy_password | Password for proxy basic HTTP authentication. | | no | +| method | HTTP request method. | GET | no | +| body | HTTP request body. | | no | +| headers | HTTP request headers. | | no | +| not_follow_redirects | Redirect handling policy. Controls whether the client follows redirects. | no | no | +| tls_skip_verify | Server certificate chain and hostname validation policy. Controls whether the client performs this check. | no | no | +| tls_ca | Certification authority that the client uses when verifying the server's certificates. | | no | +| tls_cert | Client TLS certificate. | | no | +| tls_key | Client TLS key. | | no | + +</details> + +#### Examples + +##### HTTP authentication + +Basic HTTP authentication. + +<details open><summary>Config</summary> + +```yaml +jobs: + - name: local + url: http://127.0.0.1:2812 + username: admin + password: monit + +``` +</details> + +##### HTTPS with self-signed certificate + +With enabled HTTPS and self-signed certificate. + +<details open><summary>Config</summary> + +```yaml +jobs: + - name: local + url: http://127.0.0.1:2812 + tls_skip_verify: yes + +``` +</details> + +##### Multi-instance + +> **Note**: When you define multiple jobs, their names must be unique. + +Collecting metrics from local and remote instances. + + +<details open><summary>Config</summary> + +```yaml +jobs: + - name: local + url: http://127.0.0.1:2812 + + - name: remote + url: http://192.0.2.1:2812 + +``` +</details> + + + +## Troubleshooting + +### Debug Mode + +**Important**: Debug mode is not supported for data collection jobs created via the UI using the Dyncfg feature. + +To troubleshoot issues with the `monit` collector, run the `go.d.plugin` with the debug option enabled. The output +should give you clues as to why the collector isn't working. + +- Navigate to the `plugins.d` directory, usually at `/usr/libexec/netdata/plugins.d/`. If that's not the case on + your system, open `netdata.conf` and look for the `plugins` setting under `[directories]`. + + ```bash + cd /usr/libexec/netdata/plugins.d/ + ``` + +- Switch to the `netdata` user. + + ```bash + sudo -u netdata -s + ``` + +- Run the `go.d.plugin` to debug the collector: + + ```bash + ./go.d.plugin -d -m monit + ``` + +### Getting Logs + +If you're encountering problems with the `monit` collector, follow these steps to retrieve logs and identify potential issues: + +- **Run the command** specific to your system (systemd, non-systemd, or Docker container). +- **Examine the output** for any warnings or error messages that might indicate issues. These messages should provide clues about the root cause of the problem. + +#### System with systemd + +Use the following command to view logs generated since the last Netdata service restart: + +```bash +journalctl _SYSTEMD_INVOCATION_ID="$(systemctl show --value --property=InvocationID netdata)" --namespace=netdata --grep monit +``` + +#### System without systemd + +Locate the collector log file, typically at `/var/log/netdata/collector.log`, and use `grep` to filter for collector's name: + +```bash +grep monit /var/log/netdata/collector.log +``` + +**Note**: This method shows logs from all restarts. Focus on the **latest entries** for troubleshooting current issues. + +#### Docker Container + +If your Netdata runs in a Docker container named "netdata" (replace if different), use this command: + +```bash +docker logs netdata 2>&1 | grep monit +``` + + diff --git a/src/go/plugin/go.d/modules/monit/metadata.yaml b/src/go/plugin/go.d/modules/monit/metadata.yaml new file mode 100644 index 000000000..d54793984 --- /dev/null +++ b/src/go/plugin/go.d/modules/monit/metadata.yaml @@ -0,0 +1,193 @@ +plugin_name: go.d.plugin +modules: + - meta: + id: collector-go.d.plugin-monit + plugin_name: go.d.plugin + module_name: monit + monitored_instance: + name: Monit + link: https://mmonit.com/monit/ + categories: + - data-collection.synthetic-checks + icon_filename: monit.png + related_resources: + integrations: + list: [] + alternative_monitored_instances: [] + info_provided_to_referring_integrations: + description: "" + keywords: + - monit + - mmonit + - supervision tool + - monitrc + most_popular: false + overview: + data_collection: + metrics_description: | + This collector monitors status of Monit's service checks. + method_description: | + It sends HTTP requests to the Monit `/_status?format=xml&level=full` endpoint. + default_behavior: + auto_detection: + description: | + By default, it detects Monit instances running on localhost that are listening on port 2812. + On startup, it tries to collect metrics from: + + - http://127.0.0.1:2812 + limits: + description: "" + performance_impact: + description: "" + additional_permissions: + description: "" + multi_instance: true + supported_platforms: + include: [] + exclude: [] + setup: + prerequisites: + list: + - title: Enable TCP PORT + description: + See [Syntax for TCP port](https://mmonit.com/monit/documentation/monit.html#TCP-PORT) for details. + configuration: + file: + name: go.d/monit.conf + options: + description: | + The following options can be defined globally: update_every, autodetection_retry. + folding: + title: Config options + enabled: true + list: + - name: update_every + description: Data collection frequency. + default_value: 1 + required: false + - name: autodetection_retry + description: Recheck interval in seconds. Zero means no recheck will be scheduled. + default_value: 0 + required: false + - name: url + description: Server URL. + default_value: http://127.0.0.1:2812 + required: true + - name: timeout + description: HTTP request timeout. + default_value: 1 + required: false + - name: username + description: Username for basic HTTP authentication. + default_value: "admin" + required: false + - name: password + description: Password for basic HTTP authentication. + default_value: "monit" + required: false + - name: proxy_url + description: Proxy URL. + default_value: "" + required: false + - name: proxy_username + description: Username for proxy basic HTTP authentication. + default_value: "" + required: false + - name: proxy_password + description: Password for proxy basic HTTP authentication. + default_value: "" + required: false + - name: method + description: HTTP request method. + default_value: GET + required: false + - name: body + description: HTTP request body. + default_value: "" + required: false + - name: headers + description: HTTP request headers. + default_value: "" + required: false + - name: not_follow_redirects + description: Redirect handling policy. Controls whether the client follows redirects. + default_value: false + required: false + - name: tls_skip_verify + description: Server certificate chain and hostname validation policy. Controls whether the client performs this check. + default_value: false + required: false + - name: tls_ca + description: Certification authority that the client uses when verifying the server's certificates. + default_value: "" + required: false + - name: tls_cert + description: Client TLS certificate. + default_value: "" + required: false + - name: tls_key + description: Client TLS key. + default_value: "" + required: false + examples: + folding: + title: Config + enabled: true + list: + - name: HTTP authentication + description: Basic HTTP authentication. + config: | + jobs: + - name: local + url: http://127.0.0.1:2812 + username: admin + password: monit + - name: HTTPS with self-signed certificate + description: With enabled HTTPS and self-signed certificate. + config: | + jobs: + - name: local + url: http://127.0.0.1:2812 + tls_skip_verify: yes + - name: Multi-instance + description: | + > **Note**: When you define multiple jobs, their names must be unique. + + Collecting metrics from local and remote instances. + config: | + jobs: + - name: local + url: http://127.0.0.1:2812 + + - name: remote + url: http://192.0.2.1:2812 + troubleshooting: + problems: + list: [] + alerts: [] + metrics: + folding: + title: Metrics + enabled: false + description: "" + availability: [] + scopes: + - name: service + description: These metrics refer to the monitored Service. + labels: + - name: server_hostname + description: Hostname of the Monit server. + - name: service_check_name + description: Service check name. + - name: service_check_type + description: Service check type. + metrics: + - name: monit.service_check_status + description: Service Check Status + unit: status + chart_type: line + dimensions: + - name: ok + - name: error + - name: initializing + - name: not_monitored diff --git a/src/go/plugin/go.d/modules/monit/monit.go b/src/go/plugin/go.d/modules/monit/monit.go new file mode 100644 index 000000000..d0fe90b14 --- /dev/null +++ b/src/go/plugin/go.d/modules/monit/monit.go @@ -0,0 +1,117 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +package monit + +import ( + _ "embed" + "errors" + "net/http" + "time" + + "github.com/netdata/netdata/go/plugins/plugin/go.d/agent/module" + "github.com/netdata/netdata/go/plugins/plugin/go.d/pkg/web" +) + +//go:embed "config_schema.json" +var configSchema string + +func init() { + module.Register("monit", module.Creator{ + Create: func() module.Module { return New() }, + JobConfigSchema: configSchema, + Config: func() any { return &Config{} }, + }) +} + +func New() *Monit { + return &Monit{ + Config: Config{ + HTTP: web.HTTP{ + Request: web.Request{ + URL: "http://127.0.0.1:2812", + Username: "admin", + Password: "monit", + }, + Client: web.Client{ + Timeout: web.Duration(time.Second), + }, + }, + }, + charts: baseCharts.Copy(), + seenServices: make(map[string]statusServiceCheck), + } +} + +type Config struct { + UpdateEvery int `yaml:"update_every,omitempty" json:"update_every"` + web.HTTP `yaml:",inline" json:""` +} + +type Monit struct { + module.Base + Config `yaml:",inline" json:""` + + charts *module.Charts + + httpClient *http.Client + + seenServices map[string]statusServiceCheck +} + +func (m *Monit) Configuration() any { + return m.Config +} + +func (m *Monit) Init() error { + if m.URL == "" { + m.Error("config: monit url is required but not set") + return errors.New("config: missing URL") + } + + httpClient, err := web.NewHTTPClient(m.Client) + if err != nil { + m.Errorf("init HTTP client: %v", err) + return err + } + m.httpClient = httpClient + + m.Debugf("using URL %s", m.URL) + m.Debugf("using timeout: %s", m.Timeout) + + return nil +} + +func (m *Monit) Check() error { + mx, err := m.collect() + if err != nil { + m.Error(err) + return err + } + if len(mx) == 0 { + return errors.New("no metrics collected") + + } + return nil +} + +func (m *Monit) Charts() *module.Charts { + return m.charts +} + +func (m *Monit) Collect() map[string]int64 { + mx, err := m.collect() + if err != nil { + m.Error(err) + } + + if len(mx) == 0 { + return nil + } + return mx +} + +func (m *Monit) Cleanup() { + if m.httpClient != nil { + m.httpClient.CloseIdleConnections() + } +} diff --git a/src/go/plugin/go.d/modules/monit/monit_test.go b/src/go/plugin/go.d/modules/monit/monit_test.go new file mode 100644 index 000000000..7735dcdc2 --- /dev/null +++ b/src/go/plugin/go.d/modules/monit/monit_test.go @@ -0,0 +1,371 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +package monit + +import ( + "net/http" + "net/http/httptest" + "os" + "testing" + + "github.com/netdata/netdata/go/plugins/plugin/go.d/agent/module" + "github.com/netdata/netdata/go/plugins/plugin/go.d/pkg/web" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +var ( + dataConfigJSON, _ = os.ReadFile("testdata/config.json") + dataConfigYAML, _ = os.ReadFile("testdata/config.yaml") + + dataStatus, _ = os.ReadFile("testdata/v5.33.0/status.xml") +) + +func Test_testDataIsValid(t *testing.T) { + for name, data := range map[string][]byte{ + "dataConfigJSON": dataConfigJSON, + "dataConfigYAML": dataConfigYAML, + "dataStatus": dataStatus, + } { + require.NotNil(t, data, name) + + } +} + +func TestMonit_ConfigurationSerialize(t *testing.T) { + module.TestConfigurationSerialize(t, &Monit{}, dataConfigJSON, dataConfigYAML) +} + +func TestMonit_Init(t *testing.T) { + tests := map[string]struct { + wantFail bool + config Config + }{ + "success with default": { + wantFail: false, + config: New().Config, + }, + "fail when URL not set": { + wantFail: true, + config: Config{ + HTTP: web.HTTP{ + Request: web.Request{URL: ""}, + }, + }, + }, + } + + for name, test := range tests { + t.Run(name, func(t *testing.T) { + monit := New() + monit.Config = test.config + + if test.wantFail { + assert.Error(t, monit.Init()) + } else { + assert.NoError(t, monit.Init()) + } + }) + } +} + +func TestMonit_Check(t *testing.T) { + tests := map[string]struct { + wantFail bool + prepare func(t *testing.T) (monit *Monit, cleanup func()) + }{ + "success on valid response": { + wantFail: false, + prepare: caseOk, + }, + "fail on unexpected XML response": { + wantFail: true, + prepare: caseUnexpectedXMLResponse, + }, + "fail on invalid data response": { + wantFail: true, + prepare: caseInvalidDataResponse, + }, + "fail on connection refused": { + wantFail: true, + prepare: caseConnectionRefused, + }, + "fail on 404 response": { + wantFail: true, + prepare: case404, + }, + } + + for name, test := range tests { + t.Run(name, func(t *testing.T) { + monit, cleanup := test.prepare(t) + defer cleanup() + + if test.wantFail { + assert.Error(t, monit.Check()) + } else { + assert.NoError(t, monit.Check()) + } + }) + } +} + +func TestMonit_Charts(t *testing.T) { + assert.NotNil(t, New().Charts()) +} + +func TestMonit_Collect(t *testing.T) { + tests := map[string]struct { + prepare func(t *testing.T) (monit *Monit, cleanup func()) + wantNumOfCharts int + wantMetrics map[string]int64 + }{ + "success on valid response": { + prepare: caseOk, + wantNumOfCharts: len(baseCharts) + len(serviceCheckChartsTmpl)*25, + wantMetrics: map[string]int64{ + "service_check_type_directory_name_directoryAlert_status_error": 1, + "service_check_type_directory_name_directoryAlert_status_initializing": 0, + "service_check_type_directory_name_directoryAlert_status_not_monitored": 0, + "service_check_type_directory_name_directoryAlert_status_ok": 0, + "service_check_type_directory_name_directoryDisabled_status_error": 0, + "service_check_type_directory_name_directoryDisabled_status_initializing": 0, + "service_check_type_directory_name_directoryDisabled_status_not_monitored": 1, + "service_check_type_directory_name_directoryDisabled_status_ok": 0, + "service_check_type_directory_name_directoryNotExists_status_error": 1, + "service_check_type_directory_name_directoryNotExists_status_initializing": 0, + "service_check_type_directory_name_directoryNotExists_status_not_monitored": 0, + "service_check_type_directory_name_directoryNotExists_status_ok": 0, + "service_check_type_directory_name_directoryOk_status_error": 0, + "service_check_type_directory_name_directoryOk_status_initializing": 0, + "service_check_type_directory_name_directoryOk_status_not_monitored": 0, + "service_check_type_directory_name_directoryOk_status_ok": 1, + "service_check_type_file_name_fileAlert_status_error": 1, + "service_check_type_file_name_fileAlert_status_initializing": 0, + "service_check_type_file_name_fileAlert_status_not_monitored": 0, + "service_check_type_file_name_fileAlert_status_ok": 0, + "service_check_type_file_name_fileDisabled_status_error": 0, + "service_check_type_file_name_fileDisabled_status_initializing": 0, + "service_check_type_file_name_fileDisabled_status_not_monitored": 1, + "service_check_type_file_name_fileDisabled_status_ok": 0, + "service_check_type_file_name_fileNotExists_status_error": 1, + "service_check_type_file_name_fileNotExists_status_initializing": 0, + "service_check_type_file_name_fileNotExists_status_not_monitored": 0, + "service_check_type_file_name_fileNotExists_status_ok": 0, + "service_check_type_file_name_fileOk_status_error": 0, + "service_check_type_file_name_fileOk_status_initializing": 0, + "service_check_type_file_name_fileOk_status_not_monitored": 0, + "service_check_type_file_name_fileOk_status_ok": 1, + "service_check_type_filesystem_name_filesystemAlert_status_error": 1, + "service_check_type_filesystem_name_filesystemAlert_status_initializing": 0, + "service_check_type_filesystem_name_filesystemAlert_status_not_monitored": 0, + "service_check_type_filesystem_name_filesystemAlert_status_ok": 0, + "service_check_type_filesystem_name_filesystemDisabled_status_error": 0, + "service_check_type_filesystem_name_filesystemDisabled_status_initializing": 0, + "service_check_type_filesystem_name_filesystemDisabled_status_not_monitored": 1, + "service_check_type_filesystem_name_filesystemDisabled_status_ok": 0, + "service_check_type_filesystem_name_filesystemNotExists_status_error": 1, + "service_check_type_filesystem_name_filesystemNotExists_status_initializing": 0, + "service_check_type_filesystem_name_filesystemNotExists_status_not_monitored": 0, + "service_check_type_filesystem_name_filesystemNotExists_status_ok": 0, + "service_check_type_filesystem_name_filsystemOk_status_error": 0, + "service_check_type_filesystem_name_filsystemOk_status_initializing": 0, + "service_check_type_filesystem_name_filsystemOk_status_not_monitored": 0, + "service_check_type_filesystem_name_filsystemOk_status_ok": 1, + "service_check_type_host_name_hostAlert_status_error": 1, + "service_check_type_host_name_hostAlert_status_initializing": 0, + "service_check_type_host_name_hostAlert_status_not_monitored": 0, + "service_check_type_host_name_hostAlert_status_ok": 0, + "service_check_type_host_name_hostDisabled_status_error": 0, + "service_check_type_host_name_hostDisabled_status_initializing": 0, + "service_check_type_host_name_hostDisabled_status_not_monitored": 1, + "service_check_type_host_name_hostDisabled_status_ok": 0, + "service_check_type_host_name_hostNotExists_status_error": 1, + "service_check_type_host_name_hostNotExists_status_initializing": 0, + "service_check_type_host_name_hostNotExists_status_not_monitored": 0, + "service_check_type_host_name_hostNotExists_status_ok": 0, + "service_check_type_host_name_hostOk_status_error": 0, + "service_check_type_host_name_hostOk_status_initializing": 0, + "service_check_type_host_name_hostOk_status_not_monitored": 0, + "service_check_type_host_name_hostOk_status_ok": 1, + "service_check_type_network_name_networkAlert_status_error": 1, + "service_check_type_network_name_networkAlert_status_initializing": 0, + "service_check_type_network_name_networkAlert_status_not_monitored": 0, + "service_check_type_network_name_networkAlert_status_ok": 0, + "service_check_type_network_name_networkDisabled_status_error": 0, + "service_check_type_network_name_networkDisabled_status_initializing": 0, + "service_check_type_network_name_networkDisabled_status_not_monitored": 1, + "service_check_type_network_name_networkDisabled_status_ok": 0, + "service_check_type_network_name_networkNotExists_status_error": 1, + "service_check_type_network_name_networkNotExists_status_initializing": 0, + "service_check_type_network_name_networkNotExists_status_not_monitored": 0, + "service_check_type_network_name_networkNotExists_status_ok": 0, + "service_check_type_network_name_networkOk_status_error": 0, + "service_check_type_network_name_networkOk_status_initializing": 0, + "service_check_type_network_name_networkOk_status_not_monitored": 0, + "service_check_type_network_name_networkOk_status_ok": 1, + "service_check_type_process_name_processAlert_status_error": 1, + "service_check_type_process_name_processAlert_status_initializing": 0, + "service_check_type_process_name_processAlert_status_not_monitored": 0, + "service_check_type_process_name_processAlert_status_ok": 0, + "service_check_type_process_name_processDisabled_status_error": 0, + "service_check_type_process_name_processDisabled_status_initializing": 0, + "service_check_type_process_name_processDisabled_status_not_monitored": 1, + "service_check_type_process_name_processDisabled_status_ok": 0, + "service_check_type_process_name_processNotExists_status_error": 1, + "service_check_type_process_name_processNotExists_status_initializing": 0, + "service_check_type_process_name_processNotExists_status_not_monitored": 0, + "service_check_type_process_name_processNotExists_status_ok": 0, + "service_check_type_process_name_processOk_status_error": 0, + "service_check_type_process_name_processOk_status_initializing": 0, + "service_check_type_process_name_processOk_status_not_monitored": 0, + "service_check_type_process_name_processOk_status_ok": 1, + "service_check_type_system_name_pve-deb-work_status_error": 0, + "service_check_type_system_name_pve-deb-work_status_initializing": 0, + "service_check_type_system_name_pve-deb-work_status_not_monitored": 0, + "service_check_type_system_name_pve-deb-work_status_ok": 1, + "uptime": 33, + }, + }, + "fail on unexpected XML response": { + prepare: caseUnexpectedXMLResponse, + wantNumOfCharts: len(baseCharts), + wantMetrics: nil, + }, + "fail on invalid data response": { + prepare: caseInvalidDataResponse, + wantNumOfCharts: len(baseCharts), + wantMetrics: nil, + }, + "fail on connection refused": { + prepare: caseConnectionRefused, + wantNumOfCharts: len(baseCharts), + wantMetrics: nil, + }, + "fail on 404 response": { + prepare: case404, + wantNumOfCharts: len(baseCharts), + wantMetrics: nil, + }, + } + + for name, test := range tests { + t.Run(name, func(t *testing.T) { + monit, cleanup := test.prepare(t) + defer cleanup() + + _ = monit.Check() + + mx := monit.Collect() + + require.Equal(t, test.wantMetrics, mx) + + if len(test.wantMetrics) > 0 { + module.TestMetricsHasAllChartsDims(t, monit.Charts(), mx) + assert.Equal(t, test.wantNumOfCharts, len(*monit.Charts()), "want number of charts") + } + }) + } +} + +func caseOk(t *testing.T) (*Monit, func()) { + t.Helper() + srv := httptest.NewServer(http.HandlerFunc( + func(w http.ResponseWriter, r *http.Request) { + if r.URL.Path != urlPathStatus || r.URL.RawQuery != urlQueryStatus { + w.WriteHeader(http.StatusNotFound) + return + } + _, _ = w.Write(dataStatus) + })) + monit := New() + monit.URL = srv.URL + require.NoError(t, monit.Init()) + + return monit, srv.Close +} + +func caseUnexpectedXMLResponse(t *testing.T) (*Monit, func()) { + t.Helper() + data := `<?xml version="1.0" encoding="UTF-8"?> +<Response> + <Status> + <Code>200</Code> + <Message>Success</Message> + </Status> + <Data> + <User> + <ID>12345</ID> + <Name>John Doe</Name> + <Email>johndoe@example.com</Email> + <Roles> + <Role>Admin</Role> + <Role>User</Role> + </Roles> + </User> + <Order> + <OrderID>98765</OrderID> + <Date>2024-08-15</Date> + <Items> + <Item> + <Name>Widget A</Name> + <Quantity>2</Quantity> + <Price>19.99</Price> + </Item> + <Item> + <Name>Gadget B</Name> + <Quantity>1</Quantity> + <Price>99.99</Price> + </Item> + </Items> + <Total>139.97</Total> + </Order> + </Data> +</Response> +` + srv := httptest.NewServer(http.HandlerFunc( + func(w http.ResponseWriter, r *http.Request) { + _, _ = w.Write([]byte(data)) + })) + monit := New() + monit.URL = srv.URL + require.NoError(t, monit.Init()) + + return monit, srv.Close +} + +func caseInvalidDataResponse(t *testing.T) (*Monit, func()) { + t.Helper() + srv := httptest.NewServer(http.HandlerFunc( + func(w http.ResponseWriter, r *http.Request) { + _, _ = w.Write([]byte("hello and\n goodbye")) + })) + monit := New() + monit.URL = srv.URL + require.NoError(t, monit.Init()) + + return monit, srv.Close +} + +func caseConnectionRefused(t *testing.T) (*Monit, func()) { + t.Helper() + monit := New() + monit.URL = "http://127.0.0.1:65001" + require.NoError(t, monit.Init()) + + return monit, func() {} +} + +func case404(t *testing.T) (*Monit, func()) { + t.Helper() + srv := httptest.NewServer(http.HandlerFunc( + func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusNotFound) + })) + monit := New() + monit.URL = srv.URL + require.NoError(t, monit.Init()) + + return monit, srv.Close +} diff --git a/src/go/plugin/go.d/modules/monit/status.go b/src/go/plugin/go.d/modules/monit/status.go new file mode 100644 index 000000000..4a87e8c90 --- /dev/null +++ b/src/go/plugin/go.d/modules/monit/status.go @@ -0,0 +1,153 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +package monit + +// status_xml(): https://bitbucket.org/tildeslash/monit/src/5467d37d70c3c63c5760cddb93831bde4e17c14b/src/http/xml.c#lines-631 +type monitStatus struct { + Server *statusServer `xml:"server"` + Services []statusServiceCheck `xml:"service"` +} + +type statusServer struct { + ID string `xml:"id"` + Version string `xml:"version"` + Uptime int64 `xml:"uptime"` + LocalHostname string `xml:"localhostname"` +} + +// status_service(): https://bitbucket.org/tildeslash/monit/src/5467d37d70c3c63c5760cddb93831bde4e17c14b/src/http/xml.c#lines-196 +// struct Service_T: https://bitbucket.org/tildeslash/monit/src/5467d37d70c3c63c5760cddb93831bde4e17c14b/src/monit.h#lines-1212 +type statusServiceCheck struct { + Type string `xml:"type,attr"` + Name string `xml:"name"` + + Status int `xml:"status"` // Error flags bitmap + + // https://bitbucket.org/tildeslash/monit/src/5467d37d70c3c63c5760cddb93831bde4e17c14b/src/monit.h#lines-269 + MonitoringStatus int `xml:"monitor"` + + // https://bitbucket.org/tildeslash/monit/src/5467d37d70c3c63c5760cddb93831bde4e17c14b/src/monit.h#lines-254 + MonitorMode int `xml:"monitormode"` + + // https://bitbucket.org/tildeslash/monit/src/5467d37d70c3c63c5760cddb93831bde4e17c14b/src/monit.h#lines-261 + OnReboot int `xml:"onreboot"` + + // https://bitbucket.org/tildeslash/monit/src/5467d37d70c3c63c5760cddb93831bde4e17c14b/src/monit.h#lines-248 + PendingAction int `xml:"pendingaction"` +} + +func (s *statusServiceCheck) id() string { + return s.svcType() + ":" + s.Name +} + +func (s *statusServiceCheck) svcType() string { + // See enum Service_Type https://bitbucket.org/tildeslash/monit/src/master/src/monit.h + + switch s.Type { + case "0": + return "filesystem" + case "1": + return "directory" + case "2": + return "file" + case "3": + return "process" + case "4": + return "host" + case "5": + return "system" + case "6": + return "fifo" + case "7": + return "program" + case "8": + return "network" + default: + return "unknown" + } +} + +func (s *statusServiceCheck) status() string { + // https://bitbucket.org/tildeslash/monit/src/5467d37d70c3c63c5760cddb93831bde4e17c14b/src/http/cervlet.c#lines-2866 + + switch st := s.monitoringStatus(); st { + case "not_monitored", "initializing": + return st + default: + if s.Status != 0 { + return "error" + } + return "ok" + } +} + +func (s *statusServiceCheck) monitoringStatus() string { + switch s.MonitoringStatus { + case 0: + return "not_monitored" + case 1: + return "monitored" + case 2: + return "initializing" + case 4: + return "waiting" + default: + return "unknown" + } +} + +func (s *statusServiceCheck) monitorMode() string { + switch s.MonitorMode { + case 0: + return "active" + case 1: + return "passive" + default: + return "unknown" + } +} + +func (s *statusServiceCheck) onReboot() string { + switch s.OnReboot { + case 0: + return "start" + case 1: + return "no_start" + default: + return "unknown" + } +} + +func (s *statusServiceCheck) pendingAction() string { + switch s.PendingAction { + case 0: + return "ignored" + case 1: + return "alert" + case 2: + return "restart" + case 3: + return "stop" + case 4: + return "exec" + case 5: + return "unmonitor" + case 6: + return "start" + case 7: + return "monitor" + default: + return "unknown" + } +} + +func (s *statusServiceCheck) hasServiceStatus() bool { + // https://bitbucket.org/tildeslash/monit/src/5467d37d70c3c63c5760cddb93831bde4e17c14b/src/util.c#lines-1721 + + const eventNonExist = 512 + const eventData = 2048 + + return s.monitoringStatus() == "monitored" && + !(s.Status&eventNonExist != 0) && + !(s.Status&eventData != 0) +} diff --git a/src/go/plugin/go.d/modules/monit/testdata/config.json b/src/go/plugin/go.d/modules/monit/testdata/config.json new file mode 100644 index 000000000..984c3ed6e --- /dev/null +++ b/src/go/plugin/go.d/modules/monit/testdata/config.json @@ -0,0 +1,20 @@ +{ + "update_every": 123, + "url": "ok", + "body": "ok", + "method": "ok", + "headers": { + "ok": "ok" + }, + "username": "ok", + "password": "ok", + "proxy_url": "ok", + "proxy_username": "ok", + "proxy_password": "ok", + "timeout": 123.123, + "not_follow_redirects": true, + "tls_ca": "ok", + "tls_cert": "ok", + "tls_key": "ok", + "tls_skip_verify": true +} diff --git a/src/go/plugin/go.d/modules/monit/testdata/config.yaml b/src/go/plugin/go.d/modules/monit/testdata/config.yaml new file mode 100644 index 000000000..8558b61cc --- /dev/null +++ b/src/go/plugin/go.d/modules/monit/testdata/config.yaml @@ -0,0 +1,17 @@ +update_every: 123 +url: "ok" +body: "ok" +method: "ok" +headers: + ok: "ok" +username: "ok" +password: "ok" +proxy_url: "ok" +proxy_username: "ok" +proxy_password: "ok" +timeout: 123.123 +not_follow_redirects: yes +tls_ca: "ok" +tls_cert: "ok" +tls_key: "ok" +tls_skip_verify: yes diff --git a/src/go/plugin/go.d/modules/monit/testdata/v5.33.0/status.xml b/src/go/plugin/go.d/modules/monit/testdata/v5.33.0/status.xml new file mode 100644 index 000000000..ca4178c6c --- /dev/null +++ b/src/go/plugin/go.d/modules/monit/testdata/v5.33.0/status.xml @@ -0,0 +1,688 @@ +<?xml version="1.0" encoding="ISO-8859-1"?> +<monit> + <server> + <id>309dc5d56ccd5964cef9b42d1d8305e7</id> + <incarnation>1723810534</incarnation> + <version>5.33.0</version> + <uptime>33</uptime> + <poll>120</poll> + <startdelay>0</startdelay> + <localhostname>pve-deb-work</localhostname> + <controlfile>/etc/monit/monitrc</controlfile> + <httpd> + <address>127.0.0.1</address> + <port>2812</port> + <ssl>0</ssl> + </httpd> + </server> + <platform> + <name>Linux</name> + <release>6.1.0-23-amd64</release> + <version>#1 SMP PREEMPT_DYNAMIC Debian 6.1.99-1 (2024-07-15)</version> + <machine>x86_64</machine> + <cpu>16</cpu> + <memory>32864100</memory> + <swap>262140</swap> + </platform> + <service type="3"> + <name>processOk</name> + <collected_sec>1723810534</collected_sec> + <collected_usec>86510</collected_usec> + <status>0</status> + <status_hint>0</status_hint> + <monitor>1</monitor> + <monitormode>0</monitormode> + <onreboot>0</onreboot> + <pendingaction>0</pendingaction> + <pid>843</pid> + <ppid>1</ppid> + <uid>0</uid> + <euid>0</euid> + <gid>0</gid> + <uptime>66112</uptime> + <threads>1</threads> + <children>2</children> + <memory> + <percent>0.0</percent> + <percenttotal>0.1</percenttotal> + <kilobyte>5036</kilobyte> + <kilobytetotal>34156</kilobytetotal> + </memory> + <cpu> + <percent>-1.0</percent> + <percenttotal>-1.0</percenttotal> + </cpu> + <filedescriptors> + <open>9</open> + <opentotal>34</opentotal> + <limit> + <soft>8192</soft> + <hard>8192</hard> + </limit> + </filedescriptors> + <read> + <bytesgeneric> + <count>0</count> + <total>1733465</total> + </bytesgeneric> + <bytes> + <count>0</count> + <total>135168</total> + </bytes> + <operations> + <count>0</count> + <total>23145</total> + </operations> + </read> + <write> + <bytesgeneric> + <count>0</count> + <total>8842272</total> + </bytesgeneric> + <bytes> + <count>0</count> + <total>9150464</total> + </bytes> + <operations> + <count>0</count> + <total>22890</total> + </operations> + </write> + </service> + <service type="3"> + <name>processDisabled</name> + <collected_sec>1723810534</collected_sec> + <collected_usec>68402</collected_usec> + <status>0</status> + <status_hint>0</status_hint> + <monitor>0</monitor> + <monitormode>0</monitormode> + <onreboot>0</onreboot> + <pendingaction>0</pendingaction> + </service> + <service type="3"> + <name>processAlert</name> + <collected_sec>1723810534</collected_sec> + <collected_usec>86548</collected_usec> + <status>2</status> + <status_hint>0</status_hint> + <monitor>1</monitor> + <monitormode>0</monitormode> + <onreboot>0</onreboot> + <pendingaction>0</pendingaction> + <pid>843</pid> + <ppid>1</ppid> + <uid>0</uid> + <euid>0</euid> + <gid>0</gid> + <uptime>66112</uptime> + <threads>1</threads> + <children>2</children> + <memory> + <percent>0.0</percent> + <percenttotal>0.1</percenttotal> + <kilobyte>5036</kilobyte> + <kilobytetotal>34156</kilobytetotal> + </memory> + <cpu> + <percent>-1.0</percent> + <percenttotal>-1.0</percenttotal> + </cpu> + <filedescriptors> + <open>9</open> + <opentotal>34</opentotal> + <limit> + <soft>8192</soft> + <hard>8192</hard> + </limit> + </filedescriptors> + <read> + <bytesgeneric> + <count>0</count> + <total>1733465</total> + </bytesgeneric> + <bytes> + <count>0</count> + <total>135168</total> + </bytes> + <operations> + <count>0</count> + <total>23145</total> + </operations> + </read> + <write> + <bytesgeneric> + <count>0</count> + <total>8842272</total> + </bytesgeneric> + <bytes> + <count>0</count> + <total>9150464</total> + </bytes> + <operations> + <count>0</count> + <total>22890</total> + </operations> + </write> + </service> + <service type="3"> + <name>processNotExists</name> + <collected_sec>1723810534</collected_sec> + <collected_usec>86595</collected_usec> + <status>4608</status> + <status_hint>0</status_hint> + <monitor>1</monitor> + <monitormode>0</monitormode> + <onreboot>0</onreboot> + <pendingaction>0</pendingaction> + </service> + <service type="0"> + <name>filsystemOk</name> + <collected_sec>1723810534</collected_sec> + <collected_usec>86891</collected_usec> + <status>0</status> + <status_hint>0</status_hint> + <monitor>1</monitor> + <monitormode>0</monitormode> + <onreboot>0</onreboot> + <pendingaction>0</pendingaction> + <fstype>ext2</fstype> + <fsflags>rw,relatime</fsflags> + <mode>660</mode> + <uid>0</uid> + <gid>6</gid> + <block> + <percent>19.6</percent> + <usage>92.0</usage> + <total>469.4</total> + </block> + <inode> + <percent>0.3</percent> + <usage>356</usage> + <total>124928</total> + </inode> + <read> + <bytes> + <count>0</count> + <total>5706752</total> + </bytes> + <operations> + <count>0</count> + <total>210</total> + </operations> + </read> + <write> + <bytes> + <count>0</count> + <total>1024</total> + </bytes> + <operations> + <count>0</count> + <total>1</total> + </operations> + </write> + <servicetime> + <read>0.000</read> + <write>0.000</write> + </servicetime> + </service> + <service type="0"> + <name>filesystemDisabled</name> + <collected_sec>1723810534</collected_sec> + <collected_usec>68613</collected_usec> + <status>0</status> + <status_hint>0</status_hint> + <monitor>0</monitor> + <monitormode>0</monitormode> + <onreboot>0</onreboot> + <pendingaction>0</pendingaction> + </service> + <service type="0"> + <name>filesystemAlert</name> + <collected_sec>1723810534</collected_sec> + <collected_usec>87124</collected_usec> + <status>384</status> + <status_hint>0</status_hint> + <monitor>1</monitor> + <monitormode>0</monitormode> + <onreboot>0</onreboot> + <pendingaction>0</pendingaction> + <fstype>ext2</fstype> + <fsflags>rw,relatime</fsflags> + <mode>660</mode> + <uid>0</uid> + <gid>6</gid> + <block> + <percent>19.6</percent> + <usage>92.0</usage> + <total>469.4</total> + </block> + <inode> + <percent>0.3</percent> + <usage>356</usage> + <total>124928</total> + </inode> + <read> + <bytes> + <count>0</count> + <total>5706752</total> + </bytes> + <operations> + <count>0</count> + <total>210</total> + </operations> + </read> + <write> + <bytes> + <count>0</count> + <total>1024</total> + </bytes> + <operations> + <count>0</count> + <total>1</total> + </operations> + </write> + <servicetime> + <read>0.000</read> + <write>0.000</write> + </servicetime> + </service> + <service type="0"> + <name>filesystemNotExists</name> + <collected_sec>1723810534</collected_sec> + <collected_usec>87334</collected_usec> + <status>512</status> + <status_hint>0</status_hint> + <monitor>1</monitor> + <monitormode>0</monitormode> + <onreboot>0</onreboot> + <pendingaction>0</pendingaction> + </service> + <service type="2"> + <name>fileOk</name> + <collected_sec>1723810534</collected_sec> + <collected_usec>87339</collected_usec> + <status>0</status> + <status_hint>0</status_hint> + <monitor>1</monitor> + <monitormode>0</monitormode> + <onreboot>0</onreboot> + <pendingaction>0</pendingaction> + <mode>755</mode> + <uid>0</uid> + <gid>0</gid> + <timestamps> + <access>1723744256</access> + <change>1723744256</change> + <modify>1723744256</modify> + </timestamps> + <size>84820392</size> + </service> + <service type="2"> + <name>fileDisabled</name> + <collected_sec>1723810534</collected_sec> + <collected_usec>68835</collected_usec> + <status>0</status> + <status_hint>0</status_hint> + <monitor>0</monitor> + <monitormode>0</monitormode> + <onreboot>0</onreboot> + <pendingaction>0</pendingaction> + </service> + <service type="2"> + <name>fileAlert</name> + <collected_sec>1723810534</collected_sec> + <collected_usec>87356</collected_usec> + <status>384</status> + <status_hint>0</status_hint> + <monitor>1</monitor> + <monitormode>0</monitormode> + <onreboot>0</onreboot> + <pendingaction>0</pendingaction> + <mode>755</mode> + <uid>0</uid> + <gid>0</gid> + <timestamps> + <access>1723744256</access> + <change>1723744256</change> + <modify>1723744256</modify> + </timestamps> + <size>84820392</size> + </service> + <service type="2"> + <name>fileNotExists</name> + <collected_sec>1723810534</collected_sec> + <collected_usec>87371</collected_usec> + <status>512</status> + <status_hint>0</status_hint> + <monitor>1</monitor> + <monitormode>0</monitormode> + <onreboot>0</onreboot> + <pendingaction>0</pendingaction> + </service> + <service type="1"> + <name>directoryOk</name> + <collected_sec>1723810534</collected_sec> + <collected_usec>87375</collected_usec> + <status>0</status> + <status_hint>0</status_hint> + <monitor>1</monitor> + <monitormode>0</monitormode> + <onreboot>0</onreboot> + <pendingaction>0</pendingaction> + <mode>775</mode> + <uid>0</uid> + <gid>0</gid> + <timestamps> + <access>1723740545</access> + <change>1720694060</change> + <modify>1720694060</modify> + </timestamps> + </service> + <service type="1"> + <name>directoryDisabled</name> + <collected_sec>1723810534</collected_sec> + <collected_usec>68957</collected_usec> + <status>0</status> + <status_hint>0</status_hint> + <monitor>0</monitor> + <monitormode>0</monitormode> + <onreboot>0</onreboot> + <pendingaction>0</pendingaction> + </service> + <service type="1"> + <name>directoryAlert</name> + <collected_sec>1723810534</collected_sec> + <collected_usec>87385</collected_usec> + <status>64</status> + <status_hint>0</status_hint> + <monitor>1</monitor> + <monitormode>0</monitormode> + <onreboot>0</onreboot> + <pendingaction>0</pendingaction> + <mode>775</mode> + <uid>0</uid> + <gid>0</gid> + <timestamps> + <access>1723740545</access> + <change>1720694060</change> + <modify>1720694060</modify> + </timestamps> + </service> + <service type="1"> + <name>directoryNotExists</name> + <collected_sec>1723810534</collected_sec> + <collected_usec>87400</collected_usec> + <status>512</status> + <status_hint>0</status_hint> + <monitor>1</monitor> + <monitormode>0</monitormode> + <onreboot>0</onreboot> + <pendingaction>0</pendingaction> + </service> + <service type="4"> + <name>hostOk</name> + <collected_sec>1723810534</collected_sec> + <collected_usec>89652</collected_usec> + <status>0</status> + <status_hint>0</status_hint> + <monitor>1</monitor> + <monitormode>0</monitormode> + <onreboot>0</onreboot> + <pendingaction>0</pendingaction> + <icmp> + <type>Ping</type> + <responsetime>0.000144</responsetime> + </icmp> + <port> + <hostname>10.20.4.200</hostname> + <portnumber>19999</portnumber> + <request><![CDATA[/api/v1/info]]></request> + <protocol>HTTP</protocol> + <type>TCP</type> + <responsetime>0.002077</responsetime> + </port> + </service> + <service type="4"> + <name>hostDisabled</name> + <collected_sec>1723810534</collected_sec> + <collected_usec>69066</collected_usec> + <status>0</status> + <status_hint>0</status_hint> + <monitor>0</monitor> + <monitormode>0</monitormode> + <onreboot>0</onreboot> + <pendingaction>0</pendingaction> + </service> + <service type="4"> + <name>hostAlert</name> + <collected_sec>1723810534</collected_sec> + <collected_usec>89857</collected_usec> + <status>32</status> + <status_hint>0</status_hint> + <monitor>1</monitor> + <monitormode>0</monitormode> + <onreboot>0</onreboot> + <pendingaction>0</pendingaction> + <icmp> + <type>Ping</type> + <responsetime>0.000069</responsetime> + </icmp> + <port> + <hostname>10.20.4.200</hostname> + <portnumber>19991</portnumber> + <request><![CDATA[/api/v1/info]]></request> + <protocol>HTTP</protocol> + <type>TCP</type> + <responsetime>-1.000000</responsetime> + </port> + </service> + <service type="4"> + <name>hostNotExists</name> + <collected_sec>1723810549</collected_sec> + <collected_usec>94459</collected_usec> + <status>16384</status> + <status_hint>0</status_hint> + <monitor>1</monitor> + <monitormode>0</monitormode> + <onreboot>0</onreboot> + <pendingaction>0</pendingaction> + <icmp> + <type>Ping</type> + <responsetime>-1.000000</responsetime> + </icmp> + <port> + <hostname>10.20.4.233</hostname> + <portnumber>19999</portnumber> + <request><![CDATA[/api/v1/info]]></request> + <protocol>HTTP</protocol> + <type>TCP</type> + <responsetime>-1.000000</responsetime> + </port> + </service> + <service type="8"> + <name>networkOk</name> + <collected_sec>1723810549</collected_sec> + <collected_usec>94801</collected_usec> + <status>0</status> + <status_hint>0</status_hint> + <monitor>1</monitor> + <monitormode>0</monitormode> + <onreboot>0</onreboot> + <pendingaction>0</pendingaction> + <link> + <state>1</state> + <speed>-1000000</speed> + <duplex>-1</duplex> + <download> + <packets> + <now>0</now> + <total>319258</total> + </packets> + <bytes> + <now>0</now> + <total>714558077</total> + </bytes> + <errors> + <now>0</now> + <total>0</total> + </errors> + </download> + <upload> + <packets> + <now>0</now> + <total>172909</total> + </packets> + <bytes> + <now>0</now> + <total>25128489</total> + </bytes> + <errors> + <now>0</now> + <total>0</total> + </errors> + </upload> + </link> + </service> + <service type="8"> + <name>networkDisabled</name> + <collected_sec>1723810534</collected_sec> + <collected_usec>69103</collected_usec> + <status>0</status> + <status_hint>0</status_hint> + <monitor>0</monitor> + <monitormode>0</monitormode> + <onreboot>0</onreboot> + <pendingaction>0</pendingaction> + </service> + <service type="8"> + <name>networkAlert</name> + <collected_sec>1723810549</collected_sec> + <collected_usec>94969</collected_usec> + <status>8388608</status> + <status_hint>0</status_hint> + <monitor>1</monitor> + <monitormode>0</monitormode> + <onreboot>0</onreboot> + <pendingaction>0</pendingaction> + <link> + <state>0</state> + <speed>-1</speed> + <duplex>-1</duplex> + <download> + <packets> + <now>-1</now> + <total>-1</total> + </packets> + <bytes> + <now>-1</now> + <total>-1</total> + </bytes> + <errors> + <now>-1</now> + <total>-1</total> + </errors> + </download> + <upload> + <packets> + <now>-1</now> + <total>-1</total> + </packets> + <bytes> + <now>-1</now> + <total>-1</total> + </bytes> + <errors> + <now>-1</now> + <total>-1</total> + </errors> + </upload> + </link> + </service> + <service type="8"> + <name>networkNotExists</name> + <collected_sec>1723810549</collected_sec> + <collected_usec>94992</collected_usec> + <status>8388608</status> + <status_hint>0</status_hint> + <monitor>1</monitor> + <monitormode>0</monitormode> + <onreboot>0</onreboot> + <pendingaction>0</pendingaction> + <link> + <state>-1</state> + <speed>-1</speed> + <duplex>-1</duplex> + <download> + <packets> + <now>-1</now> + <total>-1</total> + </packets> + <bytes> + <now>-1</now> + <total>-1</total> + </bytes> + <errors> + <now>-1</now> + <total>-1</total> + </errors> + </download> + <upload> + <packets> + <now>-1</now> + <total>-1</total> + </packets> + <bytes> + <now>-1</now> + <total>-1</total> + </bytes> + <errors> + <now>-1</now> + <total>-1</total> + </errors> + </upload> + </link> + </service> + <service type="5"> + <name>pve-deb-work</name> + <collected_sec>1723810549</collected_sec> + <collected_usec>94992</collected_usec> + <status>0</status> + <status_hint>0</status_hint> + <monitor>1</monitor> + <monitormode>0</monitormode> + <onreboot>0</onreboot> + <pendingaction>0</pendingaction> + <filedescriptors> + <allocated>1664</allocated> + <unused>0</unused> + <maximum>9223372036854775807</maximum> + </filedescriptors> + <system> + <load> + <avg01>0.00</avg01> + <avg05>0.04</avg05> + <avg15>0.03</avg15> + </load> + <cpu> + <user>0.0</user> + <system>0.0</system> + <nice>0.0</nice> + <wait>0.0</wait> + <hardirq>0.0</hardirq> + <softirq>0.0</softirq> + <steal>0.0</steal> + <guest>0.0</guest> + <guestnice>0.0</guestnice> + </cpu> + <memory> + <percent>3.1</percent> + <kilobyte>1020120</kilobyte> + </memory> + <swap> + <percent>0.0</percent> + <kilobyte>0</kilobyte> + </swap> + </system> + </service> +</monit> |