diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-05 11:19:16 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-07-24 09:53:24 +0000 |
commit | b5f8ee61a7f7e9bd291dd26b0585d03eb686c941 (patch) | |
tree | d4d31289c39fc00da064a825df13a0b98ce95b10 /src/go/collectors/go.d.plugin/modules/zookeeper | |
parent | Adding upstream version 1.44.3. (diff) | |
download | netdata-b5f8ee61a7f7e9bd291dd26b0585d03eb686c941.tar.xz netdata-b5f8ee61a7f7e9bd291dd26b0585d03eb686c941.zip |
Adding upstream version 1.46.3.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
15 files changed, 1579 insertions, 0 deletions
diff --git a/src/go/collectors/go.d.plugin/modules/zookeeper/README.md b/src/go/collectors/go.d.plugin/modules/zookeeper/README.md new file mode 120000 index 000000000..ae81b3714 --- /dev/null +++ b/src/go/collectors/go.d.plugin/modules/zookeeper/README.md @@ -0,0 +1 @@ +integrations/zookeeper.md
\ No newline at end of file diff --git a/src/go/collectors/go.d.plugin/modules/zookeeper/charts.go b/src/go/collectors/go.d.plugin/modules/zookeeper/charts.go new file mode 100644 index 000000000..2c2cf6a05 --- /dev/null +++ b/src/go/collectors/go.d.plugin/modules/zookeeper/charts.go @@ -0,0 +1,111 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +package zookeeper + +import "github.com/netdata/netdata/go/go.d.plugin/agent/module" + +type ( + Charts = module.Charts + Dims = module.Dims + Vars = module.Vars +) + +var charts = Charts{ + { + ID: "requests", + Title: "Outstanding Requests", + Units: "requests", + Fam: "requests", + Ctx: "zookeeper.requests", + Dims: Dims{ + {ID: "outstanding_requests", Name: "outstanding"}, + }, + }, + { + ID: "requests_latency", + Title: "Requests Latency", + Units: "ms", + Fam: "requests", + Ctx: "zookeeper.requests_latency", + Dims: Dims{ + {ID: "min_latency", Name: "min", Div: 1000}, + {ID: "avg_latency", Name: "avg", Div: 1000}, + {ID: "max_latency", Name: "max", Div: 1000}, + }, + }, + { + ID: "connections", + Title: "Alive Connections", + Units: "connections", + Fam: "connections", + Ctx: "zookeeper.connections", + Dims: Dims{ + {ID: "num_alive_connections", Name: "alive"}, + }, + }, + { + ID: "packets", + Title: "Packets", + Units: "pps", + Fam: "net", + Ctx: "zookeeper.packets", + Dims: Dims{ + {ID: "packets_received", Name: "received", Algo: module.Incremental}, + {ID: "packets_sent", Name: "sent", Algo: module.Incremental, Mul: -1}, + }, + }, + { + ID: "file_descriptor", + Title: "Open File Descriptors", + Units: "file descriptors", + Fam: "file descriptors", + Ctx: "zookeeper.file_descriptor", + Dims: Dims{ + {ID: "open_file_descriptor_count", Name: "open"}, + }, + Vars: Vars{ + {ID: "max_file_descriptor_count"}, + }, + }, + { + ID: "nodes", + Title: "Number of Nodes", + Units: "nodes", + Fam: "data tree", + Ctx: "zookeeper.nodes", + Dims: Dims{ + {ID: "znode_count", Name: "znode"}, + {ID: "ephemerals_count", Name: "ephemerals"}, + }, + }, + { + ID: "watches", + Title: "Number of Watches", + Units: "watches", + Fam: "data tree", + Ctx: "zookeeper.watches", + Dims: Dims{ + {ID: "watch_count", Name: "watches"}, + }, + }, + { + ID: "approximate_data_size", + Title: "Approximate Data Tree Size", + Units: "KiB", + Fam: "data tree", + Ctx: "zookeeper.approximate_data_size", + Dims: Dims{ + {ID: "approximate_data_size", Name: "size", Div: 1024}, + }, + }, + { + ID: "server_state", + Title: "Server State", + Units: "state", + Fam: "server state", + Ctx: "zookeeper.server_state", + Dims: Dims{ + {ID: "server_state", Name: "state"}, + }, + }, +} diff --git a/src/go/collectors/go.d.plugin/modules/zookeeper/collect.go b/src/go/collectors/go.d.plugin/modules/zookeeper/collect.go new file mode 100644 index 000000000..86491e1b1 --- /dev/null +++ b/src/go/collectors/go.d.plugin/modules/zookeeper/collect.go @@ -0,0 +1,79 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +package zookeeper + +import ( + "fmt" + "strconv" + "strings" +) + +func (z *Zookeeper) collect() (map[string]int64, error) { + return z.collectMntr() +} + +func (z *Zookeeper) collectMntr() (map[string]int64, error) { + const command = "mntr" + + lines, err := z.fetch("mntr") + if err != nil { + return nil, err + } + + switch len(lines) { + case 0: + return nil, fmt.Errorf("'%s' command returned empty response", command) + case 1: + // mntr is not executed because it is not in the whitelist. + return nil, fmt.Errorf("'%s' command returned bad response: %s", command, lines[0]) + } + + mx := make(map[string]int64) + + for _, line := range lines { + parts := strings.Fields(line) + if len(parts) != 2 || !strings.HasPrefix(parts[0], "zk_") { + continue + } + + key, value := strings.TrimPrefix(parts[0], "zk_"), parts[1] + switch key { + case "version": + case "server_state": + mx[key] = convertServerState(value) + case "min_latency", "avg_latency", "max_latency": + v, err := strconv.ParseFloat(value, 64) + if err != nil { + continue + } + mx[key] = int64(v * 1000) + default: + v, err := strconv.ParseFloat(value, 64) + if err != nil { + continue + } + mx[key] = int64(v) + } + } + + if len(mx) == 0 { + return nil, fmt.Errorf("'%s' command: failed to parse response", command) + } + + return mx, nil +} + +func convertServerState(state string) int64 { + switch state { + default: + return 0 + case "leader": + return 1 + case "follower": + return 2 + case "observer": + return 3 + case "standalone": + return 4 + } +} diff --git a/src/go/collectors/go.d.plugin/modules/zookeeper/config_schema.json b/src/go/collectors/go.d.plugin/modules/zookeeper/config_schema.json new file mode 100644 index 000000000..e07a27c29 --- /dev/null +++ b/src/go/collectors/go.d.plugin/modules/zookeeper/config_schema.json @@ -0,0 +1,95 @@ +{ + "jsonSchema": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "Zookeeper collector configuration.", + "type": "object", + "properties": { + "update_every": { + "title": "Update every", + "description": "Data collection interval, measured in seconds.", + "type": "integer", + "minimum": 1, + "default": 1 + }, + "address": { + "title": "Address", + "description": "The IP address and port where the Zookeeper server listens for connections.", + "type": "string", + "default": "127.0.0.1:2181" + }, + "timeout": { + "title": "Timeout", + "description": "The timeout, in seconds, for connection, read, write, and SSL handshake operations.", + "type": "number", + "minimum": 0.5, + "default": 1 + }, + "use_tls": { + "title": "Use TLS", + "description": "Indicates whether TLS should be used for secure communication.", + "type": "boolean" + }, + "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": "^$|^/" + } + }, + "required": [ + "address" + ], + "additionalProperties": false, + "patternProperties": { + "^name$": {} + } + }, + "uiSchema": { + "uiOptions": { + "fullPage": true + }, + "timeout": { + "ui:help": "Accepts decimals for precise control (e.g., type 1.5 for 1.5 seconds)." + }, + "ui:flavour": "tabs", + "ui:options": { + "tabs": [ + { + "title": "Base", + "fields": [ + "update_every", + "address", + "timeout" + ] + }, + { + "title": "TLS", + "fields": [ + "use_tls", + "tls_skip_verify", + "tls_ca", + "tls_cert", + "tls_key" + ] + } + ] + } + } +} diff --git a/src/go/collectors/go.d.plugin/modules/zookeeper/fetcher.go b/src/go/collectors/go.d.plugin/modules/zookeeper/fetcher.go new file mode 100644 index 000000000..be821e622 --- /dev/null +++ b/src/go/collectors/go.d.plugin/modules/zookeeper/fetcher.go @@ -0,0 +1,74 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +package zookeeper + +import ( + "bytes" + "fmt" + "unsafe" + + "github.com/netdata/netdata/go/go.d.plugin/pkg/socket" +) + +const limitReadLines = 2000 + +type zookeeperFetcher struct { + socket.Client +} + +func (c *zookeeperFetcher) fetch(command string) (rows []string, err error) { + if err = c.Connect(); err != nil { + return nil, err + } + defer func() { _ = c.Disconnect() }() + + var num int + clientErr := c.Command(command, func(b []byte) bool { + if !isZKLine(b) || isMntrLineOK(b) { + rows = append(rows, string(b)) + } + if num += 1; num >= limitReadLines { + err = fmt.Errorf("read line limit exceeded (%d)", limitReadLines) + return false + } + return true + }) + if clientErr != nil { + return nil, clientErr + } + if err != nil { + return nil, err + } + + return rows, nil +} + +func isZKLine(line []byte) bool { + return bytes.HasPrefix(line, []byte("zk_")) +} + +func isMntrLineOK(line []byte) bool { + idx := bytes.LastIndexByte(line, '\t') + return idx > 0 && collectedZKKeys[unsafeString(line)[:idx]] +} + +func unsafeString(b []byte) string { + return *((*string)(unsafe.Pointer(&b))) +} + +var collectedZKKeys = map[string]bool{ + "zk_num_alive_connections": true, + "zk_outstanding_requests": true, + "zk_min_latency": true, + "zk_avg_latency": true, + "zk_max_latency": true, + "zk_packets_received": true, + "zk_packets_sent": true, + "zk_open_file_descriptor_count": true, + "zk_max_file_descriptor_count": true, + "zk_znode_count": true, + "zk_ephemerals_count": true, + "zk_watch_count": true, + "zk_approximate_data_size": true, + "zk_server_state": true, +} diff --git a/src/go/collectors/go.d.plugin/modules/zookeeper/fetcher_test.go b/src/go/collectors/go.d.plugin/modules/zookeeper/fetcher_test.go new file mode 100644 index 000000000..dbc5174b9 --- /dev/null +++ b/src/go/collectors/go.d.plugin/modules/zookeeper/fetcher_test.go @@ -0,0 +1,49 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +package zookeeper + +import ( + "testing" + + "github.com/netdata/netdata/go/go.d.plugin/pkg/socket" + "github.com/stretchr/testify/assert" +) + +func Test_clientFetch(t *testing.T) { + c := &zookeeperFetcher{Client: &mockSocket{rowsNumResp: 10}} + + rows, err := c.fetch("whatever\n") + assert.NoError(t, err) + assert.Len(t, rows, 10) + + rows, err = c.fetch("whatever\n") + assert.NoError(t, err) + assert.Len(t, rows, 10) +} + +func Test_clientFetchReadLineLimitExceeded(t *testing.T) { + c := &zookeeperFetcher{Client: &mockSocket{rowsNumResp: limitReadLines + 1}} + + rows, err := c.fetch("whatever\n") + assert.Error(t, err) + assert.Len(t, rows, 0) +} + +type mockSocket struct { + rowsNumResp int +} + +func (m *mockSocket) Connect() error { + return nil +} + +func (m *mockSocket) Disconnect() error { + return nil +} + +func (m *mockSocket) Command(command string, process socket.Processor) error { + for i := 0; i < m.rowsNumResp; i++ { + process([]byte(command)) + } + return nil +} diff --git a/src/go/collectors/go.d.plugin/modules/zookeeper/init.go b/src/go/collectors/go.d.plugin/modules/zookeeper/init.go new file mode 100644 index 000000000..1910e9a0b --- /dev/null +++ b/src/go/collectors/go.d.plugin/modules/zookeeper/init.go @@ -0,0 +1,41 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +package zookeeper + +import ( + "crypto/tls" + "errors" + "fmt" + + "github.com/netdata/netdata/go/go.d.plugin/pkg/socket" + "github.com/netdata/netdata/go/go.d.plugin/pkg/tlscfg" +) + +func (z *Zookeeper) verifyConfig() error { + if z.Address == "" { + return errors.New("address not set") + } + return nil +} + +func (z *Zookeeper) initZookeeperFetcher() (fetcher, error) { + var tlsConf *tls.Config + var err error + + if z.UseTLS { + tlsConf, err = tlscfg.NewTLSConfig(z.TLSConfig) + if err != nil { + return nil, fmt.Errorf("creating tls config : %v", err) + } + } + + sock := socket.New(socket.Config{ + Address: z.Address, + ConnectTimeout: z.Timeout.Duration(), + ReadTimeout: z.Timeout.Duration(), + WriteTimeout: z.Timeout.Duration(), + TLSConf: tlsConf, + }) + + return &zookeeperFetcher{Client: sock}, nil +} diff --git a/src/go/collectors/go.d.plugin/modules/zookeeper/integrations/zookeeper.md b/src/go/collectors/go.d.plugin/modules/zookeeper/integrations/zookeeper.md new file mode 100644 index 000000000..45eeb0fc9 --- /dev/null +++ b/src/go/collectors/go.d.plugin/modules/zookeeper/integrations/zookeeper.md @@ -0,0 +1,215 @@ +<!--startmeta +custom_edit_url: "https://github.com/netdata/netdata/edit/master/src/go/collectors/go.d.plugin/modules/zookeeper/README.md" +meta_yaml: "https://github.com/netdata/netdata/edit/master/src/go/collectors/go.d.plugin/modules/zookeeper/metadata.yaml" +sidebar_label: "ZooKeeper" +learn_status: "Published" +learn_rel_path: "Collecting Metrics/Service Discovery / Registry" +most_popular: False +message: "DO NOT EDIT THIS FILE DIRECTLY, IT IS GENERATED BY THE COLLECTOR'S metadata.yaml FILE" +endmeta--> + +# ZooKeeper + + +<img src="https://netdata.cloud/img/zookeeper.svg" width="150"/> + + +Plugin: go.d.plugin +Module: zookeeper + +<img src="https://img.shields.io/badge/maintained%20by-Netdata-%2300ab44" /> + +## Overview + + + +It connects to the Zookeeper instance via a TCP and executes the following commands: + +- [mntr](https://zookeeper.apache.org/doc/r3.4.8/zookeeperAdmin.html#sc_zkCommands). + + +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 instances running on localhost by attempting to connect using known ZooKeeper TCP sockets: + +- 127.0.0.1:2181 +- 127.0.0.1:2182 + + +#### 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 ZooKeeper instance + +These metrics refer to the entire monitored application. + +This scope has no labels. + +Metrics: + +| Metric | Dimensions | Unit | +|:------|:----------|:----| +| zookeeper.requests | outstanding | requests | +| zookeeper.requests_latency | min, avg, max | ms | +| zookeeper.connections | alive | connections | +| zookeeper.packets | received, sent | pps | +| zookeeper.file_descriptor | open | file descriptors | +| zookeeper.nodes | znode, ephemerals | nodes | +| zookeeper.watches | watches | watches | +| zookeeper.approximate_data_size | size | KiB | +| zookeeper.server_state | state | state | + + + +## Alerts + +There are no alerts configured by default for this integration. + + +## Setup + +### Prerequisites + +#### Whitelist `mntr` command + +Add `mntr` to Zookeeper's [4lw.commands.whitelist](https://zookeeper.apache.org/doc/current/zookeeperAdmin.html#sc_4lw). + + + +### Configuration + +#### File + +The configuration file name for this integration is `go.d/zookeeper.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/zookeeper.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 | +| address | Server address. The format is IP:PORT. | 127.0.0.1:2181 | yes | +| timeout | Connection/read/write/ssl handshake timeout. | 1 | no | +| use_tls | Whether to use TLS or not. | 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 + +##### Basic + +Local server. + +<details open><summary>Config</summary> + +```yaml +jobs: + - name: local + address: 127.0.0.1:2181 + +``` +</details> + +##### TLS with self-signed certificate + +Zookeeper with TLS and self-signed certificate. + +<details open><summary>Config</summary> + +```yaml +jobs: + - name: local + address: 127.0.0.1:2181 + use_tls: yes + 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 + address: 127.0.0.1:2181 + + - name: remote + address: 192.0.2.1:2181 + +``` +</details> + + + +## Troubleshooting + +### Debug Mode + +To troubleshoot issues with the `zookeeper` 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 zookeeper + ``` + + diff --git a/src/go/collectors/go.d.plugin/modules/zookeeper/metadata.yaml b/src/go/collectors/go.d.plugin/modules/zookeeper/metadata.yaml new file mode 100644 index 000000000..527a55fb4 --- /dev/null +++ b/src/go/collectors/go.d.plugin/modules/zookeeper/metadata.yaml @@ -0,0 +1,202 @@ +plugin_name: go.d.plugin +modules: + - meta: + id: collector-go.d.plugin-zookeeper + plugin_name: go.d.plugin + module_name: zookeeper + monitored_instance: + name: ZooKeeper + link: https://zookeeper.apache.org/ + categories: + - data-collection.service-discovery-registry + icon_filename: zookeeper.svg + keywords: + - zookeeper + most_popular: false + info_provided_to_referring_integrations: + description: "" + related_resources: + integrations: + list: + - plugin_name: apps.plugin + module_name: apps + overview: + data_collection: + metrics_description: "" + method_description: | + It connects to the Zookeeper instance via a TCP and executes the following commands: + + - [mntr](https://zookeeper.apache.org/doc/r3.4.8/zookeeperAdmin.html#sc_zkCommands). + default_behavior: + auto_detection: + description: | + By default, it detects instances running on localhost by attempting to connect using known ZooKeeper TCP sockets: + + - 127.0.0.1:2181 + - 127.0.0.1:2182 + limits: + description: "" + performance_impact: + description: "" + additional_permissions: + description: "" + multi_instance: true + supported_platforms: + include: [] + exclude: [] + setup: + prerequisites: + list: + - title: Whitelist `mntr` command + description: | + Add `mntr` to Zookeeper's [4lw.commands.whitelist](https://zookeeper.apache.org/doc/current/zookeeperAdmin.html#sc_4lw). + configuration: + file: + name: "go.d/zookeeper.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: address + description: Server address. The format is IP:PORT. + default_value: 127.0.0.1:2181 + required: true + - name: timeout + description: Connection/read/write/ssl handshake timeout. + default_value: 1 + required: false + - name: use_tls + description: Whether to use TLS or not. + 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: Basic + description: Local server. + config: | + jobs: + - name: local + address: 127.0.0.1:2181 + - name: TLS with self-signed certificate + description: Zookeeper with TLS and self-signed certificate. + config: | + jobs: + - name: local + address: 127.0.0.1:2181 + use_tls: yes + 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 + address: 127.0.0.1:2181 + + - name: remote + address: 192.0.2.1:2181 + troubleshooting: + problems: + list: [] + alerts: [] + metrics: + folding: + title: Metrics + enabled: false + description: "" + availability: [] + scopes: + - name: global + description: These metrics refer to the entire monitored application. + labels: [] + metrics: + - name: zookeeper.requests + description: Outstanding Requests + unit: requests + chart_type: line + dimensions: + - name: outstanding + - name: zookeeper.requests_latency + description: Requests Latency + unit: ms + chart_type: line + dimensions: + - name: min + - name: avg + - name: max + - name: zookeeper.connections + description: Alive Connections + unit: connections + chart_type: line + dimensions: + - name: alive + - name: zookeeper.packets + description: Packets + unit: pps + chart_type: line + dimensions: + - name: received + - name: sent + - name: zookeeper.file_descriptor + description: Open File Descriptors + unit: file descriptors + chart_type: line + dimensions: + - name: open + - name: zookeeper.nodes + description: Number of Nodes + unit: nodes + chart_type: line + dimensions: + - name: znode + - name: ephemerals + - name: zookeeper.watches + description: Number of Watches + unit: watches + chart_type: line + dimensions: + - name: watches + - name: zookeeper.approximate_data_size + description: Approximate Data Tree Size + unit: KiB + chart_type: line + dimensions: + - name: size + - name: zookeeper.server_state + description: Server State + unit: state + chart_type: line + dimensions: + - name: state diff --git a/src/go/collectors/go.d.plugin/modules/zookeeper/testdata/config.json b/src/go/collectors/go.d.plugin/modules/zookeeper/testdata/config.json new file mode 100644 index 000000000..0cf6c4727 --- /dev/null +++ b/src/go/collectors/go.d.plugin/modules/zookeeper/testdata/config.json @@ -0,0 +1,10 @@ +{ + "update_every": 123, + "address": "ok", + "timeout": 123.123, + "use_tls": true, + "tls_ca": "ok", + "tls_cert": "ok", + "tls_key": "ok", + "tls_skip_verify": true +} diff --git a/src/go/collectors/go.d.plugin/modules/zookeeper/testdata/config.yaml b/src/go/collectors/go.d.plugin/modules/zookeeper/testdata/config.yaml new file mode 100644 index 000000000..54456cc80 --- /dev/null +++ b/src/go/collectors/go.d.plugin/modules/zookeeper/testdata/config.yaml @@ -0,0 +1,8 @@ +update_every: 123 +address: "ok" +timeout: 123.123 +use_tls: yes +tls_ca: "ok" +tls_cert: "ok" +tls_key: "ok" +tls_skip_verify: yes diff --git a/src/go/collectors/go.d.plugin/modules/zookeeper/testdata/mntr.txt b/src/go/collectors/go.d.plugin/modules/zookeeper/testdata/mntr.txt new file mode 100644 index 000000000..8e10c287d --- /dev/null +++ b/src/go/collectors/go.d.plugin/modules/zookeeper/testdata/mntr.txt @@ -0,0 +1,416 @@ +zk_version 3.6.1--104dcb3e3fb464b30c5186d229e00af9f332524b, built on 04/21/2020 15:01 GMT +zk_server_state standalone +zk_ephemerals_count 0 +zk_min_latency 0.1 +zk_avg_latency 0.1 +zk_num_alive_connections 1 +zk_max_file_descriptor_count 1048576 +zk_outstanding_requests 0 +zk_approximate_data_size 44 +zk_znode_count 5 +zk_open_file_descriptor_count 63 +zk_global_sessions 0 +zk_local_sessions 0 +zk_uptime 27595191 +zk_last_client_response_size -1 +zk_max_latency 0.1 +zk_packets_sent 182 +zk_outstanding_tls_handshake 0 +zk_packets_received 92 +zk_max_client_response_size -1 +zk_connection_drop_probability 0.0 +zk_watch_count 0 +zk_min_client_response_size -1 +zk_proposal_count 0 +zk_outstanding_changes_removed 0 +zk_stale_requests_dropped 0 +zk_large_requests_rejected 0 +zk_connection_rejected 0 +zk_sessionless_connections_expired 0 +zk_looking_count 0 +zk_dead_watchers_queued 0 +zk_stale_requests 0 +zk_connection_drop_count 0 +zk_learner_proposal_received_count 0 +zk_digest_mismatches_count 0 +zk_dead_watchers_cleared 0 +zk_response_packet_cache_hits 0 +zk_bytes_received_count 368 +zk_add_dead_watcher_stall_time 0 +zk_request_throttle_wait_count 0 +zk_response_packet_cache_misses 0 +zk_ensemble_auth_success 0 +zk_prep_processor_request_queued 0 +zk_learner_commit_received_count 0 +zk_stale_replies 0 +zk_connection_request_count 0 +zk_ensemble_auth_fail 0 +zk_diff_count 0 +zk_response_packet_get_children_cache_misses 0 +zk_connection_revalidate_count 0 +zk_quit_leading_due_to_disloyal_voter 0 +zk_snap_count 0 +zk_unrecoverable_error_count 0 +zk_commit_count 0 +zk_stale_sessions_expired 0 +zk_response_packet_get_children_cache_hits 0 +zk_sync_processor_request_queued 0 +zk_outstanding_changes_queued 0 +zk_request_commit_queued 0 +zk_ensemble_auth_skip 0 +zk_tls_handshake_exceeded 0 +zk_revalidate_count 0 +zk_avg_node_created_watch_count 0.0 +zk_min_node_created_watch_count 0 +zk_max_node_created_watch_count 0 +zk_cnt_node_created_watch_count 0 +zk_sum_node_created_watch_count 0 +zk_avg_session_queues_drained 0.0 +zk_min_session_queues_drained 0 +zk_max_session_queues_drained 0 +zk_cnt_session_queues_drained 0 +zk_sum_session_queues_drained 0 +zk_avg_write_commit_proc_req_queued 0.0 +zk_min_write_commit_proc_req_queued 0 +zk_max_write_commit_proc_req_queued 0 +zk_cnt_write_commit_proc_req_queued 0 +zk_sum_write_commit_proc_req_queued 0 +zk_avg_connection_token_deficit 0.0 +zk_min_connection_token_deficit 0 +zk_max_connection_token_deficit 0 +zk_cnt_connection_token_deficit 0 +zk_sum_connection_token_deficit 0 +zk_avg_read_commit_proc_req_queued 0.0 +zk_min_read_commit_proc_req_queued 0 +zk_max_read_commit_proc_req_queued 0 +zk_cnt_read_commit_proc_req_queued 0 +zk_sum_read_commit_proc_req_queued 0 +zk_avg_node_deleted_watch_count 0.0 +zk_min_node_deleted_watch_count 0 +zk_max_node_deleted_watch_count 0 +zk_cnt_node_deleted_watch_count 0 +zk_sum_node_deleted_watch_count 0 +zk_avg_startup_txns_load_time 0.0 +zk_min_startup_txns_load_time 0 +zk_max_startup_txns_load_time 0 +zk_cnt_startup_txns_load_time 0 +zk_sum_startup_txns_load_time 0 +zk_avg_sync_processor_queue_size 0.0 +zk_min_sync_processor_queue_size 0 +zk_max_sync_processor_queue_size 0 +zk_cnt_sync_processor_queue_size 1 +zk_sum_sync_processor_queue_size 0 +zk_avg_follower_sync_time 0.0 +zk_min_follower_sync_time 0 +zk_max_follower_sync_time 0 +zk_cnt_follower_sync_time 0 +zk_sum_follower_sync_time 0 +zk_avg_prep_processor_queue_size 0.0 +zk_min_prep_processor_queue_size 0 +zk_max_prep_processor_queue_size 0 +zk_cnt_prep_processor_queue_size 1 +zk_sum_prep_processor_queue_size 0 +zk_avg_fsynctime 0.0 +zk_min_fsynctime 0 +zk_max_fsynctime 0 +zk_cnt_fsynctime 0 +zk_sum_fsynctime 0 +zk_avg_reads_issued_from_session_queue 0.0 +zk_min_reads_issued_from_session_queue 0 +zk_max_reads_issued_from_session_queue 0 +zk_cnt_reads_issued_from_session_queue 0 +zk_sum_reads_issued_from_session_queue 0 +zk_avg_snapshottime 0.0 +zk_min_snapshottime 0 +zk_max_snapshottime 0 +zk_cnt_snapshottime 1 +zk_sum_snapshottime 0 +zk_avg_startup_txns_loaded 0.0 +zk_min_startup_txns_loaded 0 +zk_max_startup_txns_loaded 0 +zk_cnt_startup_txns_loaded 0 +zk_sum_startup_txns_loaded 0 +zk_avg_reads_after_write_in_session_queue 0.0 +zk_min_reads_after_write_in_session_queue 0 +zk_max_reads_after_write_in_session_queue 0 +zk_cnt_reads_after_write_in_session_queue 0 +zk_sum_reads_after_write_in_session_queue 0 +zk_avg_requests_in_session_queue 0.0 +zk_min_requests_in_session_queue 0 +zk_max_requests_in_session_queue 0 +zk_cnt_requests_in_session_queue 0 +zk_sum_requests_in_session_queue 0 +zk_avg_write_commit_proc_issued 0.0 +zk_min_write_commit_proc_issued 0 +zk_max_write_commit_proc_issued 0 +zk_cnt_write_commit_proc_issued 0 +zk_sum_write_commit_proc_issued 0 +zk_avg_prep_process_time 0.0 +zk_min_prep_process_time 0 +zk_max_prep_process_time 0 +zk_cnt_prep_process_time 0 +zk_sum_prep_process_time 0 +zk_avg_pending_session_queue_size 0.0 +zk_min_pending_session_queue_size 0 +zk_max_pending_session_queue_size 0 +zk_cnt_pending_session_queue_size 0 +zk_sum_pending_session_queue_size 0 +zk_avg_time_waiting_empty_pool_in_commit_processor_read_ms 0.0 +zk_min_time_waiting_empty_pool_in_commit_processor_read_ms 0 +zk_max_time_waiting_empty_pool_in_commit_processor_read_ms 0 +zk_cnt_time_waiting_empty_pool_in_commit_processor_read_ms 0 +zk_sum_time_waiting_empty_pool_in_commit_processor_read_ms 0 +zk_avg_commit_process_time 0.0 +zk_min_commit_process_time 0 +zk_max_commit_process_time 0 +zk_cnt_commit_process_time 0 +zk_sum_commit_process_time 0 +zk_avg_dbinittime 6.0 +zk_min_dbinittime 6 +zk_max_dbinittime 6 +zk_cnt_dbinittime 1 +zk_sum_dbinittime 6 +zk_avg_netty_queued_buffer_capacity 0.0 +zk_min_netty_queued_buffer_capacity 0 +zk_max_netty_queued_buffer_capacity 0 +zk_cnt_netty_queued_buffer_capacity 0 +zk_sum_netty_queued_buffer_capacity 0 +zk_avg_election_time 0.0 +zk_min_election_time 0 +zk_max_election_time 0 +zk_cnt_election_time 0 +zk_sum_election_time 0 +zk_avg_commit_commit_proc_req_queued 0.0 +zk_min_commit_commit_proc_req_queued 0 +zk_max_commit_commit_proc_req_queued 0 +zk_cnt_commit_commit_proc_req_queued 0 +zk_sum_commit_commit_proc_req_queued 0 +zk_avg_sync_processor_batch_size 0.0 +zk_min_sync_processor_batch_size 0 +zk_max_sync_processor_batch_size 0 +zk_cnt_sync_processor_batch_size 0 +zk_sum_sync_processor_batch_size 0 +zk_avg_node_children_watch_count 0.0 +zk_min_node_children_watch_count 0 +zk_max_node_children_watch_count 0 +zk_cnt_node_children_watch_count 0 +zk_sum_node_children_watch_count 0 +zk_avg_write_batch_time_in_commit_processor 0.0 +zk_min_write_batch_time_in_commit_processor 0 +zk_max_write_batch_time_in_commit_processor 0 +zk_cnt_write_batch_time_in_commit_processor 0 +zk_sum_write_batch_time_in_commit_processor 0 +zk_avg_read_commit_proc_issued 0.0 +zk_min_read_commit_proc_issued 0 +zk_max_read_commit_proc_issued 0 +zk_cnt_read_commit_proc_issued 0 +zk_sum_read_commit_proc_issued 0 +zk_avg_concurrent_request_processing_in_commit_processor 0.0 +zk_min_concurrent_request_processing_in_commit_processor 0 +zk_max_concurrent_request_processing_in_commit_processor 0 +zk_cnt_concurrent_request_processing_in_commit_processor 0 +zk_sum_concurrent_request_processing_in_commit_processor 0 +zk_avg_node_changed_watch_count 0.0 +zk_min_node_changed_watch_count 0 +zk_max_node_changed_watch_count 0 +zk_cnt_node_changed_watch_count 0 +zk_sum_node_changed_watch_count 0 +zk_avg_sync_process_time 0.0 +zk_min_sync_process_time 0 +zk_max_sync_process_time 0 +zk_cnt_sync_process_time 0 +zk_sum_sync_process_time 0 +zk_avg_startup_snap_load_time 5.0 +zk_min_startup_snap_load_time 5 +zk_max_startup_snap_load_time 5 +zk_cnt_startup_snap_load_time 1 +zk_sum_startup_snap_load_time 5 +zk_avg_prep_processor_queue_time_ms 0.0 +zk_min_prep_processor_queue_time_ms 0 +zk_max_prep_processor_queue_time_ms 0 +zk_cnt_prep_processor_queue_time_ms 0 +zk_sum_prep_processor_queue_time_ms 0 +zk_p50_prep_processor_queue_time_ms 0 +zk_p95_prep_processor_queue_time_ms 0 +zk_p99_prep_processor_queue_time_ms 0 +zk_p999_prep_processor_queue_time_ms 0 +zk_avg_close_session_prep_time 0.0 +zk_min_close_session_prep_time 0 +zk_max_close_session_prep_time 0 +zk_cnt_close_session_prep_time 0 +zk_sum_close_session_prep_time 0 +zk_p50_close_session_prep_time 0 +zk_p95_close_session_prep_time 0 +zk_p99_close_session_prep_time 0 +zk_p999_close_session_prep_time 0 +zk_avg_read_commitproc_time_ms 0.0 +zk_min_read_commitproc_time_ms 0 +zk_max_read_commitproc_time_ms 0 +zk_cnt_read_commitproc_time_ms 0 +zk_sum_read_commitproc_time_ms 0 +zk_p50_read_commitproc_time_ms 0 +zk_p95_read_commitproc_time_ms 0 +zk_p99_read_commitproc_time_ms 0 +zk_p999_read_commitproc_time_ms 0 +zk_avg_updatelatency 0.0 +zk_min_updatelatency 0 +zk_max_updatelatency 0 +zk_cnt_updatelatency 0 +zk_sum_updatelatency 0 +zk_p50_updatelatency 0 +zk_p95_updatelatency 0 +zk_p99_updatelatency 0 +zk_p999_updatelatency 0 +zk_avg_local_write_committed_time_ms 0.0 +zk_min_local_write_committed_time_ms 0 +zk_max_local_write_committed_time_ms 0 +zk_cnt_local_write_committed_time_ms 0 +zk_sum_local_write_committed_time_ms 0 +zk_p50_local_write_committed_time_ms 0 +zk_p95_local_write_committed_time_ms 0 +zk_p99_local_write_committed_time_ms 0 +zk_p999_local_write_committed_time_ms 0 +zk_avg_readlatency 0.0 +zk_min_readlatency 0 +zk_max_readlatency 0 +zk_cnt_readlatency 0 +zk_sum_readlatency 0 +zk_p50_readlatency 0 +zk_p95_readlatency 0 +zk_p99_readlatency 0 +zk_p999_readlatency 0 +zk_avg_quorum_ack_latency 0.0 +zk_min_quorum_ack_latency 0 +zk_max_quorum_ack_latency 0 +zk_cnt_quorum_ack_latency 0 +zk_sum_quorum_ack_latency 0 +zk_p50_quorum_ack_latency 0 +zk_p95_quorum_ack_latency 0 +zk_p99_quorum_ack_latency 0 +zk_p999_quorum_ack_latency 0 +zk_avg_om_commit_process_time_ms 0.0 +zk_min_om_commit_process_time_ms 0 +zk_max_om_commit_process_time_ms 0 +zk_cnt_om_commit_process_time_ms 0 +zk_sum_om_commit_process_time_ms 0 +zk_p50_om_commit_process_time_ms 0 +zk_p95_om_commit_process_time_ms 0 +zk_p99_om_commit_process_time_ms 0 +zk_p999_om_commit_process_time_ms 0 +zk_avg_read_final_proc_time_ms 0.0 +zk_min_read_final_proc_time_ms 0 +zk_max_read_final_proc_time_ms 0 +zk_cnt_read_final_proc_time_ms 0 +zk_sum_read_final_proc_time_ms 0 +zk_p50_read_final_proc_time_ms 0 +zk_p95_read_final_proc_time_ms 0 +zk_p99_read_final_proc_time_ms 0 +zk_p999_read_final_proc_time_ms 0 +zk_avg_commit_propagation_latency 0.0 +zk_min_commit_propagation_latency 0 +zk_max_commit_propagation_latency 0 +zk_cnt_commit_propagation_latency 0 +zk_sum_commit_propagation_latency 0 +zk_p50_commit_propagation_latency 0 +zk_p95_commit_propagation_latency 0 +zk_p99_commit_propagation_latency 0 +zk_p999_commit_propagation_latency 0 +zk_avg_dead_watchers_cleaner_latency 0.0 +zk_min_dead_watchers_cleaner_latency 0 +zk_max_dead_watchers_cleaner_latency 0 +zk_cnt_dead_watchers_cleaner_latency 0 +zk_sum_dead_watchers_cleaner_latency 0 +zk_p50_dead_watchers_cleaner_latency 0 +zk_p95_dead_watchers_cleaner_latency 0 +zk_p99_dead_watchers_cleaner_latency 0 +zk_p999_dead_watchers_cleaner_latency 0 +zk_avg_write_final_proc_time_ms 0.0 +zk_min_write_final_proc_time_ms 0 +zk_max_write_final_proc_time_ms 0 +zk_cnt_write_final_proc_time_ms 0 +zk_sum_write_final_proc_time_ms 0 +zk_p50_write_final_proc_time_ms 0 +zk_p95_write_final_proc_time_ms 0 +zk_p99_write_final_proc_time_ms 0 +zk_p999_write_final_proc_time_ms 0 +zk_avg_proposal_ack_creation_latency 0.0 +zk_min_proposal_ack_creation_latency 0 +zk_max_proposal_ack_creation_latency 0 +zk_cnt_proposal_ack_creation_latency 0 +zk_sum_proposal_ack_creation_latency 0 +zk_p50_proposal_ack_creation_latency 0 +zk_p95_proposal_ack_creation_latency 0 +zk_p99_proposal_ack_creation_latency 0 +zk_p999_proposal_ack_creation_latency 0 +zk_avg_proposal_latency 0.0 +zk_min_proposal_latency 0 +zk_max_proposal_latency 0 +zk_cnt_proposal_latency 0 +zk_sum_proposal_latency 0 +zk_p50_proposal_latency 0 +zk_p95_proposal_latency 0 +zk_p99_proposal_latency 0 +zk_p999_proposal_latency 0 +zk_avg_om_proposal_process_time_ms 0.0 +zk_min_om_proposal_process_time_ms 0 +zk_max_om_proposal_process_time_ms 0 +zk_cnt_om_proposal_process_time_ms 0 +zk_sum_om_proposal_process_time_ms 0 +zk_p50_om_proposal_process_time_ms 0 +zk_p95_om_proposal_process_time_ms 0 +zk_p99_om_proposal_process_time_ms 0 +zk_p999_om_proposal_process_time_ms 0 +zk_avg_sync_processor_queue_and_flush_time_ms 0.0 +zk_min_sync_processor_queue_and_flush_time_ms 0 +zk_max_sync_processor_queue_and_flush_time_ms 0 +zk_cnt_sync_processor_queue_and_flush_time_ms 0 +zk_sum_sync_processor_queue_and_flush_time_ms 0 +zk_p50_sync_processor_queue_and_flush_time_ms 0 +zk_p95_sync_processor_queue_and_flush_time_ms 0 +zk_p99_sync_processor_queue_and_flush_time_ms 0 +zk_p999_sync_processor_queue_and_flush_time_ms 0 +zk_avg_propagation_latency 0.0 +zk_min_propagation_latency 0 +zk_max_propagation_latency 0 +zk_cnt_propagation_latency 0 +zk_sum_propagation_latency 0 +zk_p50_propagation_latency 0 +zk_p95_propagation_latency 0 +zk_p99_propagation_latency 0 +zk_p999_propagation_latency 0 +zk_avg_server_write_committed_time_ms 0.0 +zk_min_server_write_committed_time_ms 0 +zk_max_server_write_committed_time_ms 0 +zk_cnt_server_write_committed_time_ms 0 +zk_sum_server_write_committed_time_ms 0 +zk_p50_server_write_committed_time_ms 0 +zk_p95_server_write_committed_time_ms 0 +zk_p99_server_write_committed_time_ms 0 +zk_p999_server_write_committed_time_ms 0 +zk_avg_sync_processor_queue_time_ms 0.0 +zk_min_sync_processor_queue_time_ms 0 +zk_max_sync_processor_queue_time_ms 0 +zk_cnt_sync_processor_queue_time_ms 0 +zk_sum_sync_processor_queue_time_ms 0 +zk_p50_sync_processor_queue_time_ms 0 +zk_p95_sync_processor_queue_time_ms 0 +zk_p99_sync_processor_queue_time_ms 0 +zk_p999_sync_processor_queue_time_ms 0 +zk_avg_sync_processor_queue_flush_time_ms 0.0 +zk_min_sync_processor_queue_flush_time_ms 0 +zk_max_sync_processor_queue_flush_time_ms 0 +zk_cnt_sync_processor_queue_flush_time_ms 0 +zk_sum_sync_processor_queue_flush_time_ms 0 +zk_p50_sync_processor_queue_flush_time_ms 0 +zk_p95_sync_processor_queue_flush_time_ms 0 +zk_p99_sync_processor_queue_flush_time_ms 0 +zk_p999_sync_processor_queue_flush_time_ms 0 +zk_avg_write_commitproc_time_ms 0.0 +zk_min_write_commitproc_time_ms 0 +zk_max_write_commitproc_time_ms 0 +zk_cnt_write_commitproc_time_ms 0 +zk_sum_write_commitproc_time_ms 0 +zk_p50_write_commitproc_time_ms 0 +zk_p95_write_commitproc_time_ms 0 +zk_p99_write_commitproc_time_ms 0 +zk_p999_write_commitproc_time_ms 0
\ No newline at end of file diff --git a/src/go/collectors/go.d.plugin/modules/zookeeper/testdata/mntr_notinwhitelist.txt b/src/go/collectors/go.d.plugin/modules/zookeeper/testdata/mntr_notinwhitelist.txt new file mode 100644 index 000000000..1fd1983b7 --- /dev/null +++ b/src/go/collectors/go.d.plugin/modules/zookeeper/testdata/mntr_notinwhitelist.txt @@ -0,0 +1 @@ +mntr is not executed because it is not in the whitelist.
\ No newline at end of file diff --git a/src/go/collectors/go.d.plugin/modules/zookeeper/zookeeper.go b/src/go/collectors/go.d.plugin/modules/zookeeper/zookeeper.go new file mode 100644 index 000000000..bf2a43310 --- /dev/null +++ b/src/go/collectors/go.d.plugin/modules/zookeeper/zookeeper.go @@ -0,0 +1,103 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +package zookeeper + +import ( + _ "embed" + "errors" + "time" + + "github.com/netdata/netdata/go/go.d.plugin/agent/module" + "github.com/netdata/netdata/go/go.d.plugin/pkg/tlscfg" + "github.com/netdata/netdata/go/go.d.plugin/pkg/web" +) + +//go:embed "config_schema.json" +var configSchema string + +func init() { + module.Register("zookeeper", module.Creator{ + JobConfigSchema: configSchema, + Create: func() module.Module { return New() }, + Config: func() any { return &Config{} }, + }) +} + +func New() *Zookeeper { + return &Zookeeper{ + Config: Config{ + Address: "127.0.0.1:2181", + Timeout: web.Duration(time.Second), + UseTLS: false, + }} +} + +type Config struct { + UpdateEvery int `yaml:"update_every,omitempty" json:"update_every"` + Address string `yaml:"address" json:"address"` + Timeout web.Duration `yaml:"timeout,omitempty" json:"timeout"` + tlscfg.TLSConfig `yaml:",inline" json:""` + UseTLS bool `yaml:"use_tls,omitempty" json:"use_tls"` +} + +type ( + Zookeeper struct { + module.Base + Config `yaml:",inline" json:""` + + fetcher + } + fetcher interface { + fetch(command string) ([]string, error) + } +) + +func (z *Zookeeper) Configuration() any { + return z.Config +} + +func (z *Zookeeper) Init() error { + if err := z.verifyConfig(); err != nil { + z.Error(err) + return err + } + + f, err := z.initZookeeperFetcher() + if err != nil { + z.Error(err) + return err + } + z.fetcher = f + + return nil +} + +func (z *Zookeeper) Check() error { + mx, err := z.collect() + if err != nil { + z.Error(err) + return err + } + if len(mx) == 0 { + return errors.New("no metrics collected") + } + return nil +} + +func (z *Zookeeper) Charts() *Charts { + return charts.Copy() +} + +func (z *Zookeeper) Collect() map[string]int64 { + mx, err := z.collect() + if err != nil { + z.Error(err) + } + + if len(mx) == 0 { + return nil + } + return mx +} + +func (z *Zookeeper) Cleanup() {} diff --git a/src/go/collectors/go.d.plugin/modules/zookeeper/zookeeper_test.go b/src/go/collectors/go.d.plugin/modules/zookeeper/zookeeper_test.go new file mode 100644 index 000000000..d33673fc3 --- /dev/null +++ b/src/go/collectors/go.d.plugin/modules/zookeeper/zookeeper_test.go @@ -0,0 +1,174 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +package zookeeper + +import ( + "bufio" + "bytes" + "errors" + "os" + "testing" + + "github.com/netdata/netdata/go/go.d.plugin/agent/module" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +var ( + dataConfigJSON, _ = os.ReadFile("testdata/config.json") + dataConfigYAML, _ = os.ReadFile("testdata/config.yaml") + + dataMntrMetrics, _ = os.ReadFile("testdata/mntr.txt") + dataMntrNotInWhiteListResponse, _ = os.ReadFile("testdata/mntr_notinwhitelist.txt") +) + +func Test_testDataIsValid(t *testing.T) { + for name, data := range map[string][]byte{ + "dataConfigJSON": dataConfigJSON, + "dataConfigYAML": dataConfigYAML, + "dataMntrMetrics": dataMntrMetrics, + "dataMntrNotInWhiteListResponse": dataMntrNotInWhiteListResponse, + } { + assert.NotNil(t, data, name) + } +} + +func TestZookeeper_ConfigurationSerialize(t *testing.T) { + module.TestConfigurationSerialize(t, &Zookeeper{}, dataConfigJSON, dataConfigYAML) +} + +func TestZookeeper_Init(t *testing.T) { + job := New() + + assert.NoError(t, job.Init()) + assert.NotNil(t, job.fetcher) +} + +func TestZookeeper_InitErrorOnCreatingTLSConfig(t *testing.T) { + job := New() + job.UseTLS = true + job.TLSConfig.TLSCA = "testdata/tls" + + assert.Error(t, job.Init()) +} + +func TestZookeeper_Check(t *testing.T) { + job := New() + require.NoError(t, job.Init()) + job.fetcher = &mockZookeeperFetcher{data: dataMntrMetrics} + + assert.NoError(t, job.Check()) +} + +func TestZookeeper_CheckErrorOnFetch(t *testing.T) { + job := New() + require.NoError(t, job.Init()) + job.fetcher = &mockZookeeperFetcher{err: true} + + assert.Error(t, job.Check()) +} + +func TestZookeeper_Charts(t *testing.T) { + assert.NotNil(t, New().Charts()) +} + +func TestZookeeper_Cleanup(t *testing.T) { + New().Cleanup() +} + +func TestZookeeper_Collect(t *testing.T) { + job := New() + require.NoError(t, job.Init()) + job.fetcher = &mockZookeeperFetcher{data: dataMntrMetrics} + + expected := map[string]int64{ + "approximate_data_size": 44, + "avg_latency": 100, + "ephemerals_count": 0, + "max_file_descriptor_count": 1048576, + "max_latency": 100, + "min_latency": 100, + "num_alive_connections": 1, + "open_file_descriptor_count": 63, + "outstanding_requests": 0, + "packets_received": 92, + "packets_sent": 182, + "server_state": 4, + "watch_count": 0, + "znode_count": 5, + } + + collected := job.Collect() + + assert.Equal(t, expected, collected) + ensureCollectedHasAllChartsDimsVarsIDs(t, job, collected) +} + +func TestZookeeper_CollectMntrNotInWhiteList(t *testing.T) { + job := New() + require.NoError(t, job.Init()) + job.fetcher = &mockZookeeperFetcher{data: dataMntrNotInWhiteListResponse} + + assert.Nil(t, job.Collect()) +} + +func TestZookeeper_CollectMntrEmptyResponse(t *testing.T) { + job := New() + require.NoError(t, job.Init()) + job.fetcher = &mockZookeeperFetcher{} + + assert.Nil(t, job.Collect()) +} + +func TestZookeeper_CollectMntrInvalidData(t *testing.T) { + job := New() + require.NoError(t, job.Init()) + job.fetcher = &mockZookeeperFetcher{data: []byte("hello \nand good buy\n")} + + assert.Nil(t, job.Collect()) +} + +func TestZookeeper_CollectMntrReceiveError(t *testing.T) { + job := New() + require.NoError(t, job.Init()) + job.fetcher = &mockZookeeperFetcher{err: true} + + assert.Nil(t, job.Collect()) +} + +func ensureCollectedHasAllChartsDimsVarsIDs(t *testing.T, zk *Zookeeper, collected map[string]int64) { + for _, chart := range *zk.Charts() { + if chart.Obsolete { + continue + } + for _, dim := range chart.Dims { + _, ok := collected[dim.ID] + assert.Truef(t, ok, "collected metrics has no data for dim '%s' chart '%s'", dim.ID, chart.ID) + } + for _, v := range chart.Vars { + _, ok := collected[v.ID] + assert.Truef(t, ok, "collected metrics has no data for var '%s' chart '%s'", v.ID, chart.ID) + } + } +} + +type mockZookeeperFetcher struct { + data []byte + err bool +} + +func (m mockZookeeperFetcher) fetch(_ string) ([]string, error) { + if m.err { + return nil, errors.New("mock fetch error") + } + + var lines []string + s := bufio.NewScanner(bytes.NewReader(m.data)) + for s.Scan() { + if !isZKLine(s.Bytes()) || isMntrLineOK(s.Bytes()) { + lines = append(lines, s.Text()) + } + } + return lines, nil +} |