diff --git a/.github/workflows/pika_exporter.yml b/.github/workflows/pika_exporter.yml new file mode 100644 index 0000000000..220c7ec605 --- /dev/null +++ b/.github/workflows/pika_exporter.yml @@ -0,0 +1,28 @@ +name: Pika_exporter + +on: + push: + branches: [ "unstable" ] + pull_request: + branches: [ "unstable" ] + paths: + - 'pika-tools/pika_exporter/**' + +jobs: + + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + + - name: Set up Go + uses: actions/setup-go@v3 + with: + go-version: 1.19 + + - name: Build + run: | + cd pika-tools/pika_exporter && make -j + - name: Test + run: | + cd pika-tools/pika_exporter && make -j diff --git a/pika-tools/pika_exporter/LICENSE b/pika-tools/pika_exporter/LICENSE new file mode 100644 index 0000000000..e3d824f93f --- /dev/null +++ b/pika-tools/pika_exporter/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2018 frank-ding + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/pika-tools/pika_exporter/Makefile b/pika-tools/pika_exporter/Makefile new file mode 100644 index 0000000000..a1747b5bc4 --- /dev/null +++ b/pika-tools/pika_exporter/Makefile @@ -0,0 +1,112 @@ +# ifeq "$(GOPATH)" "" +# $(error Please set the environment variable GOPATH before running `make`) +# endif + +# export PATH := $(PATH):$(GOPATH)/bin + +# for mac +BRANCH := $(shell git branch | sed 's/* \(.*\)/\1/p') +# for Linux +# BRANCH := $(shell git branch | sed --quiet 's/* \(.*\)/\1/p') +GITREV := $(shell git rev-parse --short HEAD) +BUILDTIME := $(shell date '+%F %T %Z') +COMPILERVERSION := $(subst go version ,,$(shell go version)) +PROJNAME := pika_exporter + +define GENERATE_VERSION_CODE +cat << EOF | gofmt > version.go +package main + +const ( + BuildVersion = "$(BRANCH)" + BuildCommitSha = "$(GITREV)" + BuildDate = "$(BUILDTIME)" + GoVersion = "$(COMPILERVERSION)" +) +EOF +endef +export GENERATE_VERSION_CODE + +PACKAGES := $$(go list ./...| grep -vE 'vendor') +FILES := $$(find . -name '*.go' | grep -vE 'vendor') + +define TEST_COVER +#!/bin/bash + +set -e + +which gocov >/dev/null || go get -v -u github.com/axw/gocov/gocov + +COV_FILE=coverage.txt +COV_TMP_FILE=coverage_tmp.txt + +rm -f $$COV_FILE +rm -f $$COV_TMP_FILE +touch $$COV_TMP_FILE + +echo "mode: count" > $$COV_FILE + +for pkg in $(PACKAGES); do + go test -v $$pkg -covermode=count -coverprofile=$$COV_TMP_FILE + tail -n +2 $$COV_TMP_FILE >> $$COV_FILE || (echo "Unable to append coverage for $$pkg" && exit 1) +done + +gocov convert $$COV_FILE | gocov report | grep 'Total Coverage' + +rm -f $$COV_FILE +rm -f $$COV_TMP_FILE + +endef +export TEST_COVER + +all: build + +build: deps + CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o bin/$(PROJNAME) + +deps: generateVer + @mkdir -p bin + +generateVer: + @echo "$$GENERATE_VERSION_CODE" | bash + +test: + @echo "$$TEST_COVER" | bash + +race: + go test -v -race $(PACKAGES) + +check: + which golint >/dev/null || go get -v -u github.com/golang/lint/golint + @echo "vet" + @go tool vet $(FILES) 2>&1 | awk '{print} END{if(NR>0) {exit 1}}' + @echo "vet --shadow" + @go tool vet --shadow $(FILES) 2>&1 | awk '{print} END{if(NR>0) {exit 1}}' + @echo "golint" +ifdef LINTEXCEPTION + @golint $(PACKAGES) | grep -vE'$(LINTEXCEPTION)' | awk '{print} END{if(NR>0) {exit 1}}' +else + @golint $(PACKAGES) | awk '{print} END{if(NR>0) {exit 1}}' +endif + +errcheck: + which errcheck >/dev/null || go get -v -u github.com/kisielk/errcheck + errcheck -blank $(PACKAGES) + +clean: + @rm -rf bin + @go clean -i ./... + +dev: check test race build + +update: + which glide >/dev/null || curl https://glide.sh/get | sh + which glide-vc || go get -v -u github.com/sgotti/glide-vc + rm -r vendor +ifdef PKG + glide get -v --skip-test $(PKG) +else + glide update -v -u --skip-test +endif + @echo "removing test files" + glide vc --only-code --no-tests --use-lock-file \ No newline at end of file diff --git a/pika-tools/pika_exporter/README.md b/pika-tools/pika_exporter/README.md new file mode 100644 index 0000000000..f327517147 --- /dev/null +++ b/pika-tools/pika_exporter/README.md @@ -0,0 +1,152 @@ +# Pika Metric Exporter # + +Prometheus exporter for nosql [Qihoo360/pika](https://github.com/Qihoo360/pika) metrics. + +Pika-Exporter is based on [Redis-Exporter](https://github.com/oliver006/redis_exporter) + +## Buiding ## + +**Build and run locally:** + +To start using `pika_exporter`, install `Go` and run go get +``` +$ go get github.com/OpenAtomFoundation/pika/pika-tools/pika_exporter +$ cd $GOPATH/src/github.com/OpenAtomFoundation/pika/pika-tools/pika_exporter +$ make +$ ./bin/pika_exporter +``` + + +**Prometheus Configuration:** + +Add a block to the scrape_configs of your prometheus.yml config file: +``` +scrape_configs: + +... + +- job_name: pika + scrape_interval: 15s + static_configs: + - targets: ['XXXXXX:9121'] + labels: + group: 'test' + +... +``` + +## Flags ## +| Name | Environment Variables | Default | Description | Example | +|----------------------|------------------------------------|----------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------| +| pika.host-file | PIKA_HOST_FILE | | Path to file containing one or more pika nodes, separated by newline. NOTE: mutually exclusive with pika.addr.Each line can optionally be comma-separated with the fields ``,``,``. See [here](https://github.com/OpenAtomFoundation/pika/pika-tools/pika_exporter/raw/master/contrib/sample_pika_hosts_file.txt) for an example file. | --pika.host-file ./pika_hosts_file.txt | +| pika.addr | PIKA_ADDR | | Address of one or more pika nodes, separated by comma. | --pika.addr 192.168.1.2:9221,192.168.1.3:9221 | +| pika.password | PIKA_PASSWORD | | Password for one or more pika nodes, separated by comma. | --pika.password 123.com,123.com | +| pika.alias | PIKA_ALIAS | | Pika instance alias for one or more pika nodes, separated by comma. | --pika.alias a,b | +| namespace | PIKA_EXPORTER_NAMESPACE | pika | Namespace for metrics | --namespace pika | +| keyspace-stats-clock | PIKA_EXPORTER_KEYSPACE_STATS_CLOCK | -1 | Stats the number of keys at keyspace-stats-clock o'clock every day, in the range [0, 23]. If < 0, not open this feature. | --keyspace-stats-clock 0 | +| check.key-patterns | PIKA_EXPORTER_CHECK_KEY_PARTTERNS | | Comma separated list of key-patterns to export value and length/size, searched for with SCAN. | --check.key-patterns db0=test*,db0=*abc* | +| check.keys | PIKA_EXPORTER_CHECK_KEYS | | Comma separated list of keys to export value and length/size. | --check.keys abc,test,wasd | +| check.scan-count | PIKA_EXPORTER_CHECK_SCAN_COUNT | 100 | When check keys and executing SCAN command, scan-count assigned to COUNT. | --check.scan-count 200 | +| web.listen-address | PIKA_EXPORTER_WEB_LISTEN_ADDRESS | :9121 | Address to listen on for web interface and telemetry. | --web.listen-address ":9121" | +| web.telemetry-path | PIKA_EXPORTER_WEB_TELEMETRY_PATH | /metrics | Path under which to expose metrics. | --web.telemetry-path "/metrics" | +| log.level | PIKA_EXPORTER_LOG_LEVEL | info | Log level, valid options: `panic` `fatal` `error` `warn` `warning` `info` `debug`. | --log.level "debug" | +| log.format | PIKA_EXPORTER_LOG_FORMAT | json | Log format, valid options: `txt` `json`. | --log.format "json" | +| version | | false | Show version information and exit. | --version | + + +## Pika Metrics Definition + +### Pika Server Info + +| Metrics Name | Metric Type | Labels | Metrics Value | Metric Desc | +| --------------------------- | ----------- | --------------------------------------------------------------------------------------------------------------- | -------------------------------- | ---------------------------------------------------------------------- | +| namespace_build_info | `Gauge` | {addr="", alias="", "os"="", "arch_bits"="", "pika_version"="", "pika_git_sha"="","pika_build_compile_date"=""} | 1 | pika binary file build info | +| namespace_server_info | `Gauge` | {addr="", alias="", "process_id"="", "tcp_port"="", "config_file"="", "server_id"="", "role"=""} | 1 | pika instance's info, the label `role` is the role in replication info | +| namespace_uptime_in_seconds | `Gauge` | {addr="", alias=""} | the value of `uptime_in_seconds` | pika instance's uptime in seconds | +| namespace_thread_num | `Gauge` | {addr="", alias=""} | the value of `thread_num` | pika instance's thread num | +| namespace_sync_thread_num | `Gauge` | {addr="", alias=""} | the value of `sync_thread_num` | pika instance's thread num for syncing | + +### Pika Data Info + +| Metrics Name | Metric Type | Labels | Metrics Value | Metric Desc | +| ------------------------------ | ----------- | ------------------------------------- | ----------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| namespace_db_size | `Gauge` | {addr="", alias="", "compression"=""} | the value of `db_size` | total db data size (in bytes) of the pika instance, statistics of all files under the configured `db-path` | +| namespace_log_size | `Gauge` | {addr="", alias=""} | the value of `log_size` | total log data size (in bytes) of the pika instance, statistics of all files under the configured `log-path` witch contains INFO, WARNING, ERROR logs and binlog (write2fine) files for synchronization | +| namespace_used_memory | `Gauge` | {addr="", alias=""} | the value of `used_memory` | total used memory size (in bytes) of the pika instance | +| namespace_db_memtable_usage | `Gauge` | {addr="", alias=""} | the value of `db_memtable_usage` | total memtable used memory size (in bytes) of the pika instance | +| namespace_db_tablereader_usage | `Gauge` | {addr="", alias=""} | the value of `db_tablereader_usage` | total tablereader used memory size (in bytes) of the pika instance | +| (*new*)namespace_db_fatal | `Gauge` | {addr="", alias=""} | the value of `db_fatal` | the metrics value: 1 means errors occurred, 0 means no error | + +### Pika Clients Info + +| Metrics Name | Metric Type | Labels | Metrics Value | Metric Desc | +| --------------------------- | ----------- | ------------------- | -------------------------------- | ------------------------------------------------- | +| namespace_connected_clients | `Gauge` | {addr="", alias=""} | the value of `connected_clients` | total count of connected clients in pika instance | + +### Pika Stats Info + +| Metrics Name | Metric Type | Labels | Metrics Value | Metric Desc | +| ------------------------------------ | ----------- | ------------------------------------------------------------ | ----------------------------------------- | ------------------------------------------------------------------------------------- | +| namespace_total_connections_received | `Counter` | {addr="", alias=""} | the value of `total_connections_received` | total count of received connections from clients in pika instance | +| namespace_instantaneous_ops_per_sec | `Gauge | {addr="", alias=""} | the value of `instantaneous_ops_per_sec` | the count of prcessed operations in per seconds by pika instance | +| namespace_total_commands_processed | `Counter` | {addr="", alias=""} | the value of `total_commands_processed` | total count of processed commands in pika instance | +| namespace_is_bgsaving | `Gauge` | {addr="", alias=""} | 0 or 1 | the metrics value: 1 means bgsave is in progress, 0 means bgsave is not in progress | +| namespace_is_scaning_keyspace | `Gauge` | {addr="", alias=""} | 0 or 1 | the metrics value: 1 means the keyspace is scanning, 0 means not scanning | +| namespace_compact | `Gauge` | {addr="", alias="", compact_cron"="", "compact_interval":""} | 0 or 1 | the metrics value: 1 means compact is in progress, 0 means compact is not in progress | + +### Pika Command Exec Count Info + +| Metrics Name | Metric Type | Labels | Metrics Value | Metric Desc | +| ---------------------------- | ----------- | --------------------------------- | --------------------------------------- | --------------------------------------------------- | +| namespace_command_exec_count | `Counter` | {addr="", alias="", "command"=""} | the value of the command executed count | the count of each command executed in pika instance | + +### Pika CPU Info + +| Metrics Name | Metric Type | Labels | Metrics Value | Metric Desc | +| -------------------------------- | ----------- | ------------------- | ------------------------------------- | ------------------------------------------------------------------ | +| namespace_used_cpu_user_children | `Counter` | {addr="", alias=""} | the value of `used_cpu_user_children` | total user CPU usage time (in seconds) of pika children instance | +| namespace_used_cpu_user | `Counter` | {addr="", alias=""} | the value of `used_cpu_user` | total user CPU usage time (in seconds) of pika instance | +| namespace_used_cpu_sys_children | `Counter` | {addr="", alias=""} | the value of `used_cpu_sys_children` | total system CPU usage time (in seconds) of pika children instance | +| namespace_used_cpu_sys | `Counter` | {addr="", alias=""} | the value of `used_cpu_sys` | total system CPU usage time (in seconds) of pika instance | + +### Pika Replication Info + +| Metrics Name | Metric Type | Labels | Metrics Value | Metric Desc | +| ---------------------------------- | ----------- | ---------------------------------------------------------------------------------------- | -------------------------------------------- | ------------------------------------------------------------------------------------------------------------- | +| namespace_connected_slaves | `Gauge` | {addr="", alias=""} | the value of `connected_slaves` | the count of connected slaves, when pika instance's role is master | +| (*no exists*)namespace_partition_slave_lag | `Gauge` | {addr="", alias="", "slave_conn_fd"="", slave_ip"="", "slave_port"="", "partition"=""} | parse master `slave info's lag` | the binlog lag of all slaves of the pika instance | +| namespace_master_link_status | `Gauge` | {addr="", alias="", "master_host"="", "master_port"=""} | 0 or 1 | connection state between slave and master(1 means all partitions sync ok), when pika instance's role is slave | +| namespace_slave_read_only | `Gauge` | {addr="", alias="", "master_host"="", "master_port"=""} | 0 or 1 | is slave read only, when pika instance's role is slave | +| namespace_slave_priority | `Gauge` | {addr="", alias="", "master_host"="", "master_port"=""} | the value of `slave_priority` | slave priority, when pika instance's role is slave | +| (*no exists*)namespace_partition_repl_state | `Gauge` | {addr="", alias="", "master_host"="", "master_port"="", "partition"="", "repl_state"=""} | 0 | sync connection state between slave and master for each partition, when pika instance's role is slave | +| (*no exists*)namespace_db_binlog_offset_filenum | `Gauge` | {addr="", alias="", "db"=""} | the value of `binlog_offset filenum` each db | binlog file num for each db | +| (*no exists*)namespace_db_binlog_offset | `Gauge` | {addr="", alias="", "db"="", "safety_purge"=""} | the value of `binlog_offset offset` each db | binlog offset for each db | +| (*new*)namespace_db_consensus_last_log | `Gauge` | {addr="", alias="", "db"="", "last_log"=""} | the value of `consensus last_log` each db | consensus last_log for each db when consensus-level is enabled | + +### Pika Keyspace Info + +| Metrics Name | Metric Type | Labels | Metrics Value | Metric Desc | +| ---------------------------------- | ----------- | --------------------------------------- | ---------------------------------------------------- | ------------------------------------------------------------- | +| (*new*)namespace_keyspace_last_start_time | `Gauge` | {addr="", alias=""} | the value of `Keyspace Time` convert to unix seconds | the start time(unix seconds) of the last statistical keyspace | +| namespace_keys | `Gauge` | {addr="", alias="", "db"="", "type"=""} | the value of `keys` | total count of the key-type keys for each db | +| namespace_expire_keys | `Gauge` | {addr="", alias="", "db"="", "type"=""} | the value of `expire_keys` | total count of the key-type expire keys for each db | +| namespace_invalid_keys | `Gauge` | {addr="", alias="", "db"="", "type"=""} | the value of `invalid_keys` | total count of the key-type invalid keys for each db | + +### Pika Command Execution Time + +### Rocksdb Metrics + +## Grafana Dashboard ## +See [here](./contrib/grafana_prometheus_pika_dashboard.json) + +Screenshots: +![Overview](./contrib/overview.png) +![Overview](./contrib/base_info.png) + +![BaseInfo](./contrib/base_info.png) + +![Replication](./contrib/replication.png) + +![TimeConsumingOperation](./contrib/time_consuming_operation.png) + +![KeysMetrics](./contrib/keys_metrics.png) diff --git a/pika-tools/pika_exporter/contrib/base_info.png b/pika-tools/pika_exporter/contrib/base_info.png new file mode 100644 index 0000000000..bbc0380638 Binary files /dev/null and b/pika-tools/pika_exporter/contrib/base_info.png differ diff --git a/pika-tools/pika_exporter/contrib/grafana_prometheus_pika_dashboard.json b/pika-tools/pika_exporter/contrib/grafana_prometheus_pika_dashboard.json new file mode 100644 index 0000000000..f3aedb81b6 --- /dev/null +++ b/pika-tools/pika_exporter/contrib/grafana_prometheus_pika_dashboard.json @@ -0,0 +1,3847 @@ +{ + "__inputs": [ + { + "name": "DS_PROMETHEUS", + "label": "Prometheus", + "description": "", + "type": "datasource", + "pluginId": "prometheus", + "pluginName": "Prometheus" + } + ], + "__requires": [ + { + "type": "grafana", + "id": "grafana", + "name": "Grafana", + "version": "5.3.4" + }, + { + "type": "panel", + "id": "graph", + "name": "Graph", + "version": "5.0.0" + }, + { + "type": "datasource", + "id": "prometheus", + "name": "Prometheus", + "version": "5.0.0" + }, + { + "type": "panel", + "id": "singlestat", + "name": "Singlestat", + "version": "5.0.0" + }, + { + "type": "panel", + "id": "table", + "name": "Table", + "version": "5.0.0" + }, + { + "type": "panel", + "id": "vonage-status-panel", + "name": "Status Panel", + "version": "1.0.8" + } + ], + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": true, + "gnetId": null, + "graphTooltip": 0, + "id": null, + "iteration": 1557200587542, + "links": [], + "panels": [ + { + "collapsed": true, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 12, + "panels": [ + { + "columns": [], + "datasource": "${DS_PROMETHEUS}", + "fontSize": "100%", + "gridPos": { + "h": 5, + "w": 24, + "x": 0, + "y": 1 + }, + "id": 8, + "links": [], + "pageSize": null, + "scroll": true, + "showHeader": true, + "sort": { + "col": 1, + "desc": false + }, + "styles": [ + { + "alias": "Time", + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "pattern": "Time", + "type": "date" + }, + { + "alias": "pika server addr", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "mappingType": 1, + "pattern": "addr", + "preserveFormat": false, + "sanitize": false, + "thresholds": [], + "type": "string", + "unit": "short" + }, + { + "alias": "pika server alias", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "mappingType": 1, + "pattern": "alias", + "thresholds": [], + "type": "string", + "unit": "short" + }, + { + "alias": "arch bits", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "mappingType": 1, + "pattern": "arch_bits", + "thresholds": [], + "type": "number", + "unit": "short" + }, + { + "alias": "collect instance", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "mappingType": 1, + "pattern": "instance", + "thresholds": [], + "type": "string", + "unit": "short" + }, + { + "alias": "os", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "mappingType": 1, + "pattern": "os", + "thresholds": [], + "type": "string", + "unit": "short" + }, + { + "alias": "pika version", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "mappingType": 1, + "pattern": "pika_version", + "thresholds": [], + "type": "number", + "unit": "short" + }, + { + "alias": "pika git sha", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "mappingType": 1, + "pattern": "pika_git_sha", + "thresholds": [], + "type": "number", + "unit": "short" + }, + { + "alias": "pika build date", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "mappingType": 1, + "pattern": "pika_build_compile_date", + "thresholds": [], + "type": "date", + "unit": "short" + }, + { + "alias": "", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "mappingType": 1, + "pattern": "/.*/", + "thresholds": [], + "type": "hidden", + "unit": "short" + } + ], + "targets": [ + { + "expr": "pika_build_info{job=~\"$job\", group=~\"$group\", instance=~\"$instance\"}", + "format": "table", + "instant": true, + "intervalFactor": 1, + "refId": "A" + } + ], + "title": "Pika Build Info List", + "transform": "table", + "type": "table" + }, + { + "columns": [], + "datasource": "${DS_PROMETHEUS}", + "fontSize": "100%", + "gridPos": { + "h": 5, + "w": 24, + "x": 0, + "y": 6 + }, + "id": 10, + "links": [], + "pageSize": null, + "scroll": true, + "showHeader": true, + "sort": { + "col": 0, + "desc": true + }, + "styles": [ + { + "alias": "Time", + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "pattern": "Time", + "type": "date" + }, + { + "alias": "addr", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "mappingType": 1, + "pattern": "addr", + "thresholds": [], + "type": "string", + "unit": "short" + }, + { + "alias": "alias", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "mappingType": 1, + "pattern": "alias", + "thresholds": [], + "type": "string", + "unit": "short" + }, + { + "alias": "config file", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "mappingType": 1, + "pattern": "config_file", + "thresholds": [], + "type": "number", + "unit": "short" + }, + { + "alias": "collect instance", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "mappingType": 1, + "pattern": "instance", + "thresholds": [], + "type": "number", + "unit": "short" + }, + { + "alias": "process id", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "mappingType": 1, + "pattern": "process_id", + "thresholds": [], + "type": "number", + "unit": "short" + }, + { + "alias": "role", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "mappingType": 1, + "pattern": "role", + "thresholds": [], + "type": "number", + "unit": "short" + }, + { + "alias": "server id", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "mappingType": 1, + "pattern": "server_id", + "thresholds": [], + "type": "number", + "unit": "short" + }, + { + "alias": "tcp port", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "mappingType": 1, + "pattern": "tcp_port", + "thresholds": [], + "type": "number", + "unit": "short" + }, + { + "alias": "", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "decimals": 2, + "pattern": "/.*/", + "thresholds": [], + "type": "hidden", + "unit": "short" + } + ], + "targets": [ + { + "expr": "pika_server_info{job=~\"$job\", group=~\"$group\", instance=~\"$instance\"}", + "format": "table", + "instant": true, + "intervalFactor": 2, + "refId": "A" + } + ], + "title": "Pika Server Info List", + "transform": "table", + "type": "table" + } + ], + "title": "Overview", + "type": "row" + }, + { + "collapsed": true, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 1 + }, + "id": 14, + "panels": [ + { + "columns": [], + "datasource": "${DS_PROMETHEUS}", + "fontSize": "100%", + "gridPos": { + "h": 3, + "w": 24, + "x": 0, + "y": 2 + }, + "id": 32, + "links": [], + "pageSize": null, + "scroll": true, + "showHeader": true, + "sort": { + "col": 1, + "desc": false + }, + "styles": [ + { + "alias": "Time", + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "pattern": "Time", + "type": "date" + }, + { + "alias": "pika server addr", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "mappingType": 1, + "pattern": "addr", + "preserveFormat": false, + "sanitize": false, + "thresholds": [], + "type": "string", + "unit": "short" + }, + { + "alias": "pika server alias", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "mappingType": 1, + "pattern": "alias", + "thresholds": [], + "type": "string", + "unit": "short" + }, + { + "alias": "arch bits", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "mappingType": 1, + "pattern": "arch_bits", + "thresholds": [], + "type": "number", + "unit": "short" + }, + { + "alias": "collect instance", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "mappingType": 1, + "pattern": "instance", + "thresholds": [], + "type": "string", + "unit": "short" + }, + { + "alias": "os", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "mappingType": 1, + "pattern": "os", + "thresholds": [], + "type": "string", + "unit": "short" + }, + { + "alias": "pika version", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "mappingType": 1, + "pattern": "pika_version", + "thresholds": [], + "type": "number", + "unit": "short" + }, + { + "alias": "pika git sha", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "mappingType": 1, + "pattern": "pika_git_sha", + "thresholds": [], + "type": "number", + "unit": "short" + }, + { + "alias": "pika build date", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "mappingType": 1, + "pattern": "pika_build_compile_date", + "thresholds": [], + "type": "date", + "unit": "short" + }, + { + "alias": "", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "mappingType": 1, + "pattern": "/.*/", + "thresholds": [], + "type": "hidden", + "unit": "short" + } + ], + "targets": [ + { + "expr": "pika_build_info{job=~\"$job\", group=~\"$group\", instance=~\"$instance\", addr=~\"$addr\", alias=~\"$alias\"}", + "format": "table", + "instant": true, + "intervalFactor": 1, + "refId": "A" + } + ], + "title": "Build Info", + "transform": "table", + "type": "table" + }, + { + "columns": [], + "datasource": "${DS_PROMETHEUS}", + "fontSize": "100%", + "gridPos": { + "h": 3, + "w": 24, + "x": 0, + "y": 5 + }, + "id": 31, + "links": [], + "pageSize": null, + "scroll": true, + "showHeader": true, + "sort": { + "col": 0, + "desc": true + }, + "styles": [ + { + "alias": "Time", + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "pattern": "Time", + "type": "date" + }, + { + "alias": "addr", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "mappingType": 1, + "pattern": "addr", + "thresholds": [], + "type": "string", + "unit": "short" + }, + { + "alias": "alias", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "mappingType": 1, + "pattern": "alias", + "thresholds": [], + "type": "string", + "unit": "short" + }, + { + "alias": "config file", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "mappingType": 1, + "pattern": "config_file", + "thresholds": [], + "type": "number", + "unit": "short" + }, + { + "alias": "collect instance", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "mappingType": 1, + "pattern": "instance", + "thresholds": [], + "type": "number", + "unit": "short" + }, + { + "alias": "process id", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "mappingType": 1, + "pattern": "process_id", + "thresholds": [], + "type": "number", + "unit": "short" + }, + { + "alias": "role", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "mappingType": 1, + "pattern": "role", + "thresholds": [], + "type": "number", + "unit": "short" + }, + { + "alias": "server id", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "mappingType": 1, + "pattern": "server_id", + "thresholds": [], + "type": "number", + "unit": "short" + }, + { + "alias": "tcp port", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "mappingType": 1, + "pattern": "tcp_port", + "thresholds": [], + "type": "number", + "unit": "short" + }, + { + "alias": "", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "decimals": 2, + "pattern": "/.*/", + "thresholds": [], + "type": "hidden", + "unit": "short" + } + ], + "targets": [ + { + "expr": "pika_server_info{job=~\"$job\", group=~\"$group\", instance=~\"$instance\", addr=~\"$addr\", alias=~\"$alias\"}", + "format": "table", + "instant": true, + "intervalFactor": 2, + "refId": "A" + } + ], + "title": "Server Info", + "transform": "table", + "type": "table" + }, + { + "clusterName": "$serverid", + "colorMode": "Disabled", + "colors": { + "crit": "rgba(245, 54, 54, 0.9)", + "disable": "rgba(128, 128, 128, 0.9)", + "ok": "rgba(50, 128, 45, 0.9)", + "warn": "rgba(237, 129, 40, 0.9)" + }, + "cornerRadius": 0, + "datasource": "${DS_PROMETHEUS}", + "displayName": "1", + "flipCard": false, + "flipTime": 5, + "fontFormat": "Regular", + "gridPos": { + "h": 4, + "w": 3, + "x": 0, + "y": 8 + }, + "id": 81, + "isAutoScrollOnOverflow": false, + "isGrayOnNoData": false, + "isHideAlertsOnDisable": false, + "isIgnoreOKColors": false, + "links": [], + "targets": [], + "title": "Server ID", + "type": "vonage-status-panel" + }, + { + "clusterName": "$role", + "colorMode": "Panel", + "colors": { + "crit": "rgba(245, 54, 54, 0.9)", + "disable": "rgba(128, 128, 128, 0.9)", + "ok": "rgba(50, 128, 45, 0.9)", + "warn": "rgba(237, 129, 40, 0.9)" + }, + "cornerRadius": 0, + "datasource": "${DS_PROMETHEUS}", + "displayName": "double_master", + "flipCard": false, + "flipTime": 5, + "fontFormat": "Regular", + "gridPos": { + "h": 4, + "w": 4, + "x": 3, + "y": 8 + }, + "id": 79, + "isAutoScrollOnOverflow": false, + "isGrayOnNoData": false, + "isHideAlertsOnDisable": false, + "isIgnoreOKColors": false, + "links": [], + "targets": [], + "title": "Role", + "type": "vonage-status-panel" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": true, + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "datasource": "${DS_PROMETHEUS}", + "decimals": 1, + "format": "s", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 4, + "w": 3, + "x": 7, + "y": 8 + }, + "id": 4, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "expr": "pika_uptime_in_seconds{job=~\"$job\", group=~\"$group\", instance=~\"$instance\", addr=~\"$addr\", alias=~\"$alias\"}", + "format": "time_series", + "instant": true, + "intervalFactor": 2, + "legendFormat": "", + "refId": "A" + } + ], + "thresholds": "", + "title": "Uptime", + "type": "singlestat", + "valueFontSize": "70%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "current" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": true, + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "datasource": "${DS_PROMETHEUS}", + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 4, + "w": 3, + "x": 10, + "y": 8 + }, + "id": 16, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "expr": "pika_thread_num{job=~\"$job\", group=~\"$group\", instance=~\"$instance\", addr=~\"$addr\", alias=~\"$alias\"}", + "format": "time_series", + "instant": true, + "intervalFactor": 2, + "refId": "A" + } + ], + "thresholds": "", + "title": "Tread Num", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "current" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": true, + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "datasource": "${DS_PROMETHEUS}", + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 4, + "w": 3, + "x": 13, + "y": 8 + }, + "id": 18, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "expr": "pika_sync_thread_num{job=~\"$job\", group=~\"$group\", instance=~\"$instance\", addr=~\"$addr\", alias=~\"$alias\"}", + "format": "time_series", + "instant": true, + "intervalFactor": 2, + "refId": "A" + } + ], + "thresholds": "", + "title": "Sync Thread Num", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "current" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": true, + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "datasource": "${DS_PROMETHEUS}", + "decimals": 2, + "format": "short", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 4, + "w": 4, + "x": 16, + "y": 8 + }, + "id": 45, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "expr": "pika_total_connections_received{job=~\"$job\", group=~\"$group\", instance=~\"$instance\", addr=~\"$addr\", alias=~\"$alias\"}", + "format": "time_series", + "instant": true, + "intervalFactor": 2, + "refId": "A" + } + ], + "thresholds": "", + "title": "Total Connections Received", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "current" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": true, + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "datasource": "${DS_PROMETHEUS}", + "decimals": 2, + "format": "short", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 4, + "w": 4, + "x": 20, + "y": 8 + }, + "id": 46, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "expr": "pika_total_commands_processed{job=~\"$job\", group=~\"$group\", instance=~\"$instance\", addr=~\"$addr\", alias=~\"$alias\"}", + "format": "time_series", + "instant": true, + "intervalFactor": 2, + "refId": "A" + } + ], + "thresholds": "", + "title": "Total Commands Processed", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "current" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "decimals": 0, + "fill": 1, + "gridPos": { + "h": 8, + "w": 8, + "x": 0, + "y": 12 + }, + "id": 75, + "legend": { + "alignAsTable": true, + "avg": false, + "current": true, + "max": true, + "min": true, + "show": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "pika_connected_clients{job=~\"$job\", group=~\"$group\", instance=~\"$instance\", addr=~\"$addr\", alias=~\"$alias\"}", + "format": "time_series", + "instant": false, + "intervalFactor": 2, + "legendFormat": "connected-clients", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Connected Clients", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": 0, + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "decimals": 2, + "fill": 1, + "gridPos": { + "h": 8, + "w": 8, + "x": 8, + "y": 12 + }, + "id": 76, + "legend": { + "alignAsTable": true, + "avg": false, + "current": true, + "max": true, + "min": true, + "show": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "(irate(pika_used_cpu_sys{job=~\"$job\", group=~\"$group\", instance=~\"$instance\", addr=~\"$addr\", alias=~\"$alias\"}[1m]) + irate(pika_used_cpu_user{job=~\"$job\", group=~\"$group\", instance=~\"$instance\", addr=~\"$addr\", alias=~\"$alias\"}[1m])) * 100", + "format": "time_series", + "instant": false, + "intervalFactor": 2, + "legendFormat": "cpu-usage", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "CPU Usage", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": 2, + "format": "percent", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "decimals": 2, + "fill": 1, + "gridPos": { + "h": 8, + "w": 8, + "x": 16, + "y": 12 + }, + "id": 77, + "legend": { + "alignAsTable": true, + "avg": false, + "current": true, + "max": true, + "min": true, + "show": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "(irate(pika_used_cpu_sys_children{job=~\"$job\", group=~\"$group\", instance=~\"$instance\", addr=~\"$addr\", alias=~\"$alias\"}[1m]) + irate(pika_used_cpu_user_children{job=~\"$job\", group=~\"$group\", instance=~\"$instance\", addr=~\"$addr\", alias=~\"$alias\"}[1m])) * 100", + "format": "time_series", + "instant": false, + "intervalFactor": 2, + "legendFormat": "cpu-usage-children", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "CPU Usage Children", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": 2, + "format": "percent", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "decimals": 2, + "fill": 1, + "gridPos": { + "h": 8, + "w": 8, + "x": 0, + "y": 20 + }, + "id": 20, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": true, + "min": true, + "show": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "pika_used_memory{job=~\"$job\", group=~\"$group\", instance=~\"$instance\", addr=~\"$addr\", alias=~\"$alias\"}", + "format": "time_series", + "instant": false, + "intervalFactor": 2, + "legendFormat": "used-memory", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Used Memory", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": 2, + "format": "bytes", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "decimals": 2, + "fill": 1, + "gridPos": { + "h": 8, + "w": 8, + "x": 8, + "y": 20 + }, + "id": 2, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": true, + "min": true, + "rightSide": false, + "show": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "pika_db_size{job=~\"$job\", group=~\"$group\", instance=~\"$instance\", addr=~\"$addr\", alias=~\"$alias\"}", + "format": "time_series", + "instant": false, + "intervalFactor": 2, + "legendFormat": "compression-{{compression}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "DB Size", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": 2, + "format": "bytes", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "decimals": 2, + "fill": 1, + "gridPos": { + "h": 8, + "w": 8, + "x": 16, + "y": 20 + }, + "id": 24, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": true, + "min": true, + "show": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + { + "alias": "db-tablereader-usage", + "transform": "negative-Y" + } + ], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "pika_db_memtable_usage{job=~\"$job\", group=~\"$group\", instance=~\"$instance\", addr=~\"$addr\", alias=~\"$alias\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "db-memtable-usage", + "refId": "A" + }, + { + "expr": "pika_db_tablereader_usage{job=~\"$job\", group=~\"$group\", instance=~\"$instance\", addr=~\"$addr\", alias=~\"$alias\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "db-tablereader-usage", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "DB Memtable Usage", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": 2, + "format": "bytes", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "decimals": 2, + "fill": 1, + "gridPos": { + "h": 11, + "w": 12, + "x": 0, + "y": 28 + }, + "id": 30, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": true, + "min": true, + "show": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "rate(pika_total_commands_processed{job=~\"$job\", group=~\"$group\", instance=~\"$instance\", addr=~\"$addr\", alias=~\"$alias\"}[5m])", + "format": "time_series", + "instant": false, + "intervalFactor": 2, + "legendFormat": "commands-processed/sec", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Commands Processed in per second", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": 2, + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 1, + "gridPos": { + "h": 11, + "w": 12, + "x": 12, + "y": 28 + }, + "id": 58, + "legend": { + "alignAsTable": true, + "avg": false, + "current": true, + "max": true, + "min": false, + "show": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "pika_kv_keys{job=~\"$job\", group=~\"$group\", instance=~\"$instance\", addr=~\"$addr\", alias=~\"$alias\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "kv-keys", + "refId": "A" + }, + { + "expr": "pika_hash_keys{job=~\"$job\", group=~\"$group\", instance=~\"$instance\", addr=~\"$addr\", alias=~\"$alias\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "hash-keys", + "refId": "B" + }, + { + "expr": "pika_list_keys{job=~\"$job\", group=~\"$group\", instance=~\"$instance\", addr=~\"$addr\", alias=~\"$alias\"}", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "list-keys", + "refId": "C" + }, + { + "expr": "pika_set_keys{job=~\"$job\", group=~\"$group\", instance=~\"$instance\", addr=~\"$addr\", alias=~\"$alias\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "set-keys", + "refId": "D" + }, + { + "expr": "pika_zset_keys{job=~\"$job\", group=~\"$group\", instance=~\"$instance\", addr=~\"$addr\", alias=~\"$alias\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "zset-keys", + "refId": "E" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "The number of Keys", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": null, + "format": "none", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + } + ], + "title": "Base Info", + "type": "row" + }, + { + "collapsed": true, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 2 + }, + "id": 42, + "panels": [ + { + "clusterName": "$role", + "colorMode": "Panel", + "colors": { + "crit": "rgba(245, 54, 54, 0.9)", + "disable": "rgba(128, 128, 128, 0.9)", + "ok": "rgba(50, 128, 45, 0.9)", + "warn": "rgba(237, 129, 40, 0.9)" + }, + "cornerRadius": null, + "datasource": "${DS_PROMETHEUS}", + "displayName": "double_master", + "flipCard": false, + "flipTime": 5, + "fontFormat": "Regular", + "gridPos": { + "h": 5, + "w": 4, + "x": 0, + "y": 3 + }, + "id": 71, + "isAutoScrollOnOverflow": false, + "isGrayOnNoData": false, + "isHideAlertsOnDisable": false, + "isIgnoreOKColors": false, + "links": [], + "targets": [], + "title": "Role", + "type": "vonage-status-panel" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "decimals": 0, + "fill": 1, + "gridPos": { + "h": 5, + "w": 8, + "x": 4, + "y": 3 + }, + "id": 44, + "legend": { + "alignAsTable": true, + "avg": false, + "current": true, + "max": true, + "min": true, + "show": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "pika_master_info{job=~\"$job\", group=~\"$group\", instance=~\"$instance\", addr=~\"$addr\", alias=~\"$alias\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "connected-slaves", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Connected Slaves", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": 0, + "format": "none", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "columns": [], + "datasource": "${DS_PROMETHEUS}", + "fontSize": "100%", + "gridPos": { + "h": 5, + "w": 12, + "x": 12, + "y": 3 + }, + "id": 68, + "links": [], + "pageSize": null, + "scroll": true, + "showHeader": true, + "sort": { + "col": 0, + "desc": true + }, + "styles": [ + { + "alias": "Time", + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "pattern": "Time", + "type": "date" + }, + { + "alias": "slave server id", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "mappingType": 1, + "pattern": "slave_sid", + "thresholds": [], + "type": "string", + "unit": "short" + }, + { + "alias": "slave ip", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "mappingType": 1, + "pattern": "slave_ip", + "thresholds": [], + "type": "string", + "unit": "short" + }, + { + "alias": "slave port", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": null, + "mappingType": 1, + "pattern": "slave_port", + "thresholds": [], + "type": "string", + "unit": "none" + }, + { + "alias": "slave state", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": null, + "mappingType": 1, + "pattern": "slave_state", + "thresholds": [], + "type": "string", + "unit": "none" + }, + { + "alias": "slave lag", + "colorMode": "cell", + "colors": [ + "rgba(50, 172, 45, 0.97)", + "#508642", + "rgba(245, 54, 54, 0.9)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": null, + "mappingType": 1, + "pattern": "Value", + "thresholds": [ + "0", + "1" + ], + "type": "number", + "unit": "none" + }, + { + "alias": "", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "decimals": 2, + "pattern": "/.*/", + "thresholds": [], + "type": "hidden", + "unit": "short" + } + ], + "targets": [ + { + "expr": "pika_master_slave_info{job=~\"$job\", group=~\"$group\", instance=~\"$instance\", addr=~\"$addr\", alias=~\"$alias\"}", + "format": "table", + "instant": true, + "intervalFactor": 2, + "legendFormat": "", + "refId": "A" + } + ], + "title": "Connected Slave List", + "transform": "table", + "type": "table" + }, + { + "columns": [], + "datasource": "${DS_PROMETHEUS}", + "fontSize": "100%", + "gridPos": { + "h": 5, + "w": 24, + "x": 0, + "y": 8 + }, + "id": 69, + "links": [], + "pageSize": null, + "scroll": true, + "showHeader": true, + "sort": { + "col": 0, + "desc": true + }, + "styles": [ + { + "alias": "Time", + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "pattern": "Time", + "type": "date" + }, + { + "alias": "master host", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "mappingType": 1, + "pattern": "master_host", + "thresholds": [], + "type": "string", + "unit": "short" + }, + { + "alias": "master port", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": null, + "mappingType": 1, + "pattern": "master_port", + "thresholds": [], + "type": "string", + "unit": "none" + }, + { + "alias": "slave priority", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": null, + "mappingType": 1, + "pattern": "slave_priority", + "thresholds": [ + "" + ], + "type": "string", + "unit": "short" + }, + { + "alias": "slave read only", + "colorMode": "cell", + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": null, + "mappingType": 1, + "pattern": "slave_read_only", + "thresholds": [ + "0", + "1" + ], + "type": "string", + "unit": "none" + }, + { + "alias": "repl state", + "colorMode": "cell", + "colors": [ + "#e5ac0e", + "#508642", + "rgba(245, 54, 54, 0.9)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "mappingType": 1, + "pattern": "repl_state", + "thresholds": [ + "2", + "4" + ], + "type": "string", + "unit": "short" + }, + { + "alias": "master link status", + "colorMode": "cell", + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": null, + "mappingType": 1, + "pattern": "Value", + "thresholds": [ + "0", + "1" + ], + "type": "number", + "unit": "none" + }, + { + "alias": "", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "decimals": 2, + "pattern": "/.*/", + "thresholds": [], + "type": "hidden", + "unit": "short" + } + ], + "targets": [ + { + "expr": "pika_slave_info{job=~\"$job\", group=~\"$group\", instance=~\"$instance\", addr=~\"$addr\", alias=~\"$alias\"}", + "format": "table", + "instant": true, + "intervalFactor": 2, + "legendFormat": "", + "refId": "A" + } + ], + "title": "Slave Info", + "transform": "table", + "type": "table" + }, + { + "columns": [], + "datasource": "${DS_PROMETHEUS}", + "fontSize": "100%", + "gridPos": { + "h": 3, + "w": 24, + "x": 0, + "y": 13 + }, + "id": 38, + "links": [], + "pageSize": null, + "scroll": true, + "showHeader": true, + "sort": { + "col": 0, + "desc": true + }, + "styles": [ + { + "alias": "Time", + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "pattern": "Time", + "type": "date" + }, + { + "alias": "safety purge", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "mappingType": 1, + "pattern": "safety_purge", + "thresholds": [], + "type": "string", + "unit": "short" + }, + { + "alias": "expire logs days", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "mappingType": 1, + "pattern": "expire_logs_days", + "thresholds": [], + "type": "number", + "unit": "short" + }, + { + "alias": "expire logs nums", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "mappingType": 1, + "pattern": "expire_logs_nums", + "thresholds": [], + "type": "number", + "unit": "short" + }, + { + "alias": "", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "decimals": 2, + "pattern": "/.*/", + "thresholds": [], + "type": "hidden", + "unit": "short" + } + ], + "targets": [ + { + "expr": "pika_binlog{job=~\"$job\", group=~\"$group\", instance=~\"$instance\", addr=~\"$addr\", alias=~\"$alias\"}", + "format": "table", + "instant": true, + "intervalFactor": 2, + "refId": "A" + } + ], + "title": "Binlog Setting", + "transform": "table", + "type": "table" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 1, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 16 + }, + "id": 36, + "legend": { + "alignAsTable": true, + "avg": false, + "current": true, + "max": true, + "min": true, + "show": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "pika_binlog{job=~\"$job\", group=~\"$group\", instance=~\"$instance\", addr=~\"$addr\", alias=~\"$alias\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "binlog size", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Binlog Size", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "bytes", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 1, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 16 + }, + "id": 40, + "legend": { + "alignAsTable": true, + "avg": false, + "current": true, + "max": true, + "min": true, + "show": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "pika_binlog_offset{job=~\"$job\", group=~\"$group\", instance=~\"$instance\", addr=~\"$addr\", alias=~\"$alias\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "file-num: [{{binlog_offset_filenum}}] binlog-offset", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Binlog Offset", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "bytes", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "columns": [], + "datasource": "${DS_PROMETHEUS}", + "fontSize": "100%", + "gridPos": { + "h": 5, + "w": 12, + "x": 0, + "y": 24 + }, + "id": 72, + "links": [], + "pageSize": null, + "scroll": true, + "showHeader": true, + "sort": { + "col": 0, + "desc": true + }, + "styles": [ + { + "alias": "Time", + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "pattern": "Time", + "type": "date" + }, + { + "alias": "the peer master host", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "mappingType": 1, + "pattern": "the_peer_master_host", + "thresholds": [], + "type": "string", + "unit": "short" + }, + { + "alias": "the peer master port", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": null, + "mappingType": 1, + "pattern": "the_peer_master_port", + "thresholds": [], + "type": "string", + "unit": "none" + }, + { + "alias": "the peer master server id", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "mappingType": 1, + "pattern": "the_peer_master_server_id", + "thresholds": [], + "type": "string", + "unit": "short" + }, + { + "alias": "repl state", + "colorMode": "cell", + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "mappingType": 1, + "pattern": "repl_state", + "thresholds": [ + "1", + "1" + ], + "type": "string", + "unit": "short" + }, + { + "alias": "", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "decimals": 2, + "pattern": "/.*/", + "thresholds": [], + "type": "hidden", + "unit": "short" + } + ], + "targets": [ + { + "expr": "pika_double_master_info{job=~\"$job\", group=~\"$group\", instance=~\"$instance\", addr=~\"$addr\", alias=~\"$alias\"}", + "format": "table", + "instant": true, + "intervalFactor": 2, + "legendFormat": "", + "refId": "A" + } + ], + "title": "Double Master Info", + "transform": "table", + "type": "table" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 1, + "gridPos": { + "h": 5, + "w": 12, + "x": 12, + "y": 24 + }, + "id": 74, + "legend": { + "alignAsTable": true, + "avg": false, + "current": true, + "max": true, + "min": true, + "show": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "pika_double_master_recv_info{job=~\"$job\", group=~\"$group\", instance=~\"$instance\", addr=~\"$addr\", alias=~\"$alias\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "filenum:[{{double_master_recv_info_binlog_filenum}}] binlog-offset", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Double Master Binlog Offset", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + } + ], + "title": "Replication", + "type": "row" + }, + { + "collapsed": true, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 3 + }, + "id": 48, + "panels": [ + { + "columns": [], + "datasource": "${DS_PROMETHEUS}", + "fontSize": "100%", + "gridPos": { + "h": 3, + "w": 12, + "x": 0, + "y": 4 + }, + "hideTimeOverride": false, + "id": 53, + "links": [], + "pageSize": null, + "scroll": true, + "showHeader": true, + "sort": { + "col": 8, + "desc": true + }, + "styles": [ + { + "alias": "Time", + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "link": false, + "pattern": "Time", + "type": "date" + }, + { + "alias": "latest start time", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "mappingType": 1, + "pattern": "keyspace_time", + "thresholds": [], + "type": "date", + "unit": "short" + }, + { + "alias": "is scaning keyspace", + "colorMode": "cell", + "colors": [ + "rgba(50, 172, 45, 0.97)", + "rgba(237, 129, 40, 0.89)", + "rgba(245, 54, 54, 0.9)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "mappingType": 1, + "pattern": "Value", + "thresholds": [ + "1", + "1" + ], + "type": "number", + "unit": "short" + }, + { + "alias": "", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "decimals": 2, + "pattern": "/.*/", + "thresholds": [], + "type": "hidden", + "unit": "short" + } + ], + "targets": [ + { + "expr": "pika_is_scaning_keyspace{job=~\"$job\", group=~\"$group\", instance=~\"$instance\", addr=~\"$addr\", alias=~\"$alias\"}", + "format": "table", + "instant": true, + "intervalFactor": 2, + "refId": "A" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Scan Keyspace", + "transform": "table", + "type": "table" + }, + { + "columns": [], + "datasource": "${DS_PROMETHEUS}", + "fontSize": "100%", + "gridPos": { + "h": 3, + "w": 12, + "x": 12, + "y": 4 + }, + "id": 50, + "links": [], + "pageSize": null, + "scroll": true, + "showHeader": true, + "sort": { + "col": 8, + "desc": true + }, + "styles": [ + { + "alias": "Time", + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "pattern": "Time", + "type": "date" + }, + { + "alias": "latest start time", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "mappingType": 1, + "pattern": "bgsave_start_time", + "thresholds": [], + "type": "date", + "unit": "short" + }, + { + "alias": "is bgsaving", + "colorMode": "cell", + "colors": [ + "rgba(50, 172, 45, 0.97)", + "rgba(237, 129, 40, 0.89)", + "rgba(245, 54, 54, 0.9)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "mappingType": 1, + "pattern": "Value", + "thresholds": [ + "1", + "1" + ], + "type": "number", + "unit": "short" + }, + { + "alias": "", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "decimals": 2, + "pattern": "/.*/", + "thresholds": [], + "type": "hidden", + "unit": "short" + } + ], + "targets": [ + { + "expr": "pika_is_bgsaving{job=~\"$job\", group=~\"$group\", instance=~\"$instance\", addr=~\"$addr\", alias=~\"$alias\"}", + "format": "table", + "instant": true, + "intervalFactor": 2, + "refId": "A" + } + ], + "title": "Bgsave", + "transform": "table", + "type": "table" + }, + { + "columns": [], + "datasource": "${DS_PROMETHEUS}", + "fontSize": "100%", + "gridPos": { + "h": 3, + "w": 12, + "x": 0, + "y": 7 + }, + "hideTimeOverride": false, + "id": 52, + "links": [], + "pageSize": null, + "scroll": true, + "showHeader": true, + "sort": { + "col": 8, + "desc": true + }, + "styles": [ + { + "alias": "Time", + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "link": false, + "pattern": "Time", + "type": "date" + }, + { + "alias": "latest start time", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "mappingType": 1, + "pattern": "slots_clean_start_time", + "thresholds": [], + "type": "date", + "unit": "short" + }, + { + "alias": "is slots cleaning", + "colorMode": "cell", + "colors": [ + "rgba(50, 172, 45, 0.97)", + "rgba(237, 129, 40, 0.89)", + "rgba(245, 54, 54, 0.9)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "mappingType": 1, + "pattern": "Value", + "thresholds": [ + "1", + "1" + ], + "type": "number", + "unit": "short" + }, + { + "alias": "", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "decimals": 2, + "pattern": "/.*/", + "thresholds": [], + "type": "hidden", + "unit": "short" + } + ], + "targets": [ + { + "expr": "pika_is_slots_cleaning{job=~\"$job\", group=~\"$group\", instance=~\"$instance\", addr=~\"$addr\", alias=~\"$alias\"}", + "format": "table", + "instant": true, + "intervalFactor": 2, + "refId": "A" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Slots Clean", + "transform": "table", + "type": "table" + }, + { + "columns": [], + "datasource": "${DS_PROMETHEUS}", + "fontSize": "100%", + "gridPos": { + "h": 3, + "w": 12, + "x": 12, + "y": 7 + }, + "hideTimeOverride": false, + "id": 51, + "links": [], + "pageSize": null, + "scroll": true, + "showHeader": true, + "sort": { + "col": 8, + "desc": true + }, + "styles": [ + { + "alias": "Time", + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "link": false, + "pattern": "Time", + "type": "date" + }, + { + "alias": "latest start time", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "mappingType": 1, + "pattern": "slots_reload_start_time", + "thresholds": [], + "type": "date", + "unit": "short" + }, + { + "alias": "is slots reloading", + "colorMode": "cell", + "colors": [ + "rgba(50, 172, 45, 0.97)", + "rgba(237, 129, 40, 0.89)", + "rgba(245, 54, 54, 0.9)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "mappingType": 1, + "pattern": "Value", + "thresholds": [ + "1", + "1" + ], + "type": "number", + "unit": "short" + }, + { + "alias": "", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "decimals": 2, + "pattern": "/.*/", + "thresholds": [], + "type": "hidden", + "unit": "short" + } + ], + "targets": [ + { + "expr": "pika_is_slots_reloading{job=~\"$job\", group=~\"$group\", instance=~\"$instance\", addr=~\"$addr\", alias=~\"$alias\"}", + "format": "table", + "instant": true, + "intervalFactor": 2, + "refId": "A" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Slots Reload", + "transform": "table", + "type": "table" + }, + { + "columns": [], + "datasource": "${DS_PROMETHEUS}", + "fontSize": "100%", + "gridPos": { + "h": 3, + "w": 24, + "x": 0, + "y": 10 + }, + "hideTimeOverride": false, + "id": 54, + "links": [], + "pageSize": null, + "scroll": true, + "showHeader": true, + "sort": { + "col": 8, + "desc": true + }, + "styles": [ + { + "alias": "Time", + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "link": false, + "pattern": "Time", + "type": "date" + }, + { + "alias": "compact cron", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "mappingType": 1, + "pattern": "compact_cron", + "thresholds": [], + "type": "string", + "unit": "short" + }, + { + "alias": "is compact", + "colorMode": "cell", + "colors": [ + "rgba(50, 172, 45, 0.97)", + "rgba(237, 129, 40, 0.89)", + "rgba(245, 54, 54, 0.9)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "mappingType": 1, + "pattern": "Value", + "thresholds": [ + "1", + "1" + ], + "type": "number", + "unit": "short" + }, + { + "alias": "compact interval", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "mappingType": 1, + "pattern": "compact_interval", + "thresholds": [], + "type": "string", + "unit": "short" + }, + { + "alias": "", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "decimals": 2, + "pattern": "/.*/", + "thresholds": [], + "type": "hidden", + "unit": "short" + } + ], + "targets": [ + { + "expr": "pika_is_compact{job=~\"$job\", group=~\"$group\", instance=~\"$instance\", addr=~\"$addr\", alias=~\"$alias\"}", + "format": "table", + "instant": true, + "intervalFactor": 2, + "refId": "A" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Compact", + "transform": "table", + "type": "table" + } + ], + "title": "Time-consuming operation", + "type": "row" + }, + { + "collapsed": true, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 4 + }, + "id": 56, + "panels": [ + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 1, + "gridPos": { + "h": 11, + "w": 12, + "x": 0, + "y": 5 + }, + "id": 62, + "legend": { + "alignAsTable": true, + "avg": false, + "current": true, + "max": true, + "min": true, + "show": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "pika_key_size{job=~\"$job\", group=~\"$group\", instance=~\"$instance\", addr=~\"$addr\", alias=~\"$alias\"}", + "format": "time_series", + "instant": false, + "intervalFactor": 2, + "legendFormat": " {{key}} {{key_type}} {{db}} ", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Key Size", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "none", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "columns": [], + "datasource": "${DS_PROMETHEUS}", + "fontSize": "100%", + "gridPos": { + "h": 11, + "w": 12, + "x": 12, + "y": 5 + }, + "id": 64, + "links": [], + "pageSize": null, + "scroll": true, + "showHeader": true, + "sort": { + "col": 0, + "desc": true + }, + "styles": [ + { + "alias": "Time", + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "pattern": "Time", + "type": "date" + }, + { + "alias": "DB", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "mappingType": 1, + "pattern": "db", + "thresholds": [], + "type": "string", + "unit": "short" + }, + { + "alias": "Key", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "mappingType": 1, + "pattern": "key", + "thresholds": [], + "type": "string", + "unit": "short" + }, + { + "alias": "Value", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "mappingType": 1, + "pattern": "key_value", + "thresholds": [], + "type": "string", + "unit": "short" + }, + { + "alias": "", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "decimals": 2, + "pattern": "/.*/", + "thresholds": [], + "type": "hidden", + "unit": "short" + } + ], + "targets": [ + { + "expr": "pika_key_value{job=~\"$job\", group=~\"$group\", instance=~\"$instance\", addr=~\"$addr\", alias=~\"$alias\"}", + "format": "table", + "instant": true, + "intervalFactor": 1, + "refId": "A" + } + ], + "title": "Key Value", + "transform": "table", + "type": "table" + } + ], + "title": "Keys Metrics", + "type": "row" + } + ], + "schemaVersion": 16, + "style": "dark", + "tags": [ + "prometheus", + "pika" + ], + "templating": { + "list": [ + { + "allValue": null, + "current": {}, + "datasource": "${DS_PROMETHEUS}", + "hide": 0, + "includeAll": false, + "label": "Job", + "multi": false, + "name": "job", + "options": [], + "query": "label_values(pika_server_info, job)", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 1, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": null, + "current": {}, + "datasource": "${DS_PROMETHEUS}", + "hide": 0, + "includeAll": false, + "label": "Group", + "multi": false, + "name": "group", + "options": [], + "query": "label_values(pika_server_info{job=~'$job'},group)", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 1, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": null, + "current": {}, + "datasource": "${DS_PROMETHEUS}", + "hide": 0, + "includeAll": true, + "label": "Collect Instance", + "multi": true, + "name": "instance", + "options": [], + "query": "label_values(pika_server_info{job=~\"$job\", group=~'$group'}, instance)", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 1, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": null, + "current": {}, + "datasource": "${DS_PROMETHEUS}", + "hide": 0, + "includeAll": false, + "label": "Pika Server Addr", + "multi": false, + "name": "addr", + "options": [], + "query": "label_values(pika_server_info{job=~\"$job\", group=~'$group'}, addr)", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 1, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": null, + "current": {}, + "datasource": "${DS_PROMETHEUS}", + "hide": 0, + "includeAll": false, + "label": "Pika Server Alias", + "multi": false, + "name": "alias", + "options": [], + "query": "label_values(pika_server_info{job=~\"$job\", group=~'$group', addr=~'$addr'}, alias)", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 1, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": null, + "current": {}, + "datasource": "${DS_PROMETHEUS}", + "hide": 2, + "includeAll": false, + "label": "Role", + "multi": false, + "name": "role", + "options": [], + "query": "label_values(pika_server_info{job=~\"$job\", group=~'$group', addr=~'$addr'}, role)", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 1, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": null, + "current": {}, + "datasource": "${DS_PROMETHEUS}", + "hide": 2, + "includeAll": false, + "label": "Server ID", + "multi": false, + "name": "serverid", + "options": [], + "query": "label_values(pika_server_info{job=~\"$job\", group=~'$group', addr=~'$addr'}, server_id)", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 1, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + } + ] + }, + "time": { + "from": "now-1h", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "", + "title": "Prometheus Pika Exporter", + "uid": "HYwVT4mZz", + "version": 22 +} \ No newline at end of file diff --git a/pika-tools/pika_exporter/contrib/keys_metrics.png b/pika-tools/pika_exporter/contrib/keys_metrics.png new file mode 100644 index 0000000000..7b124ad332 Binary files /dev/null and b/pika-tools/pika_exporter/contrib/keys_metrics.png differ diff --git a/pika-tools/pika_exporter/contrib/overview.png b/pika-tools/pika_exporter/contrib/overview.png new file mode 100644 index 0000000000..8172c1a404 Binary files /dev/null and b/pika-tools/pika_exporter/contrib/overview.png differ diff --git a/pika-tools/pika_exporter/contrib/replication.png b/pika-tools/pika_exporter/contrib/replication.png new file mode 100644 index 0000000000..0467fbffbb Binary files /dev/null and b/pika-tools/pika_exporter/contrib/replication.png differ diff --git a/pika-tools/pika_exporter/contrib/sample_pika_hosts_file.txt b/pika-tools/pika_exporter/contrib/sample_pika_hosts_file.txt new file mode 100644 index 0000000000..b401458831 --- /dev/null +++ b/pika-tools/pika_exporter/contrib/sample_pika_hosts_file.txt @@ -0,0 +1,4 @@ +localhost:6379 + +localhost:7000,password,alias +localhost:7000,second-pwd \ No newline at end of file diff --git a/pika-tools/pika_exporter/contrib/time_consuming_operation.png b/pika-tools/pika_exporter/contrib/time_consuming_operation.png new file mode 100644 index 0000000000..2ddd0a2843 Binary files /dev/null and b/pika-tools/pika_exporter/contrib/time_consuming_operation.png differ diff --git a/pika-tools/pika_exporter/discovery/discovery.go b/pika-tools/pika_exporter/discovery/discovery.go new file mode 100644 index 0000000000..7149b7a3fe --- /dev/null +++ b/pika-tools/pika_exporter/discovery/discovery.go @@ -0,0 +1,103 @@ +package discovery + +import ( + "encoding/csv" + "os" + "strings" + + log "github.com/sirupsen/logrus" +) + +const ( + defaultSeparator = "," +) + +type Instance struct { + Addr string + Password string + Alias string +} + +type Discovery interface { + GetInstances() []Instance +} + +type cmdArgsDiscovery struct { + instances []Instance +} + +func NewCmdArgsDiscovery(addr, password, alias string) (*cmdArgsDiscovery, error) { + if addr == "" { + addr = "localhost:9221" + } + addrs := strings.Split(addr, defaultSeparator) + passwords := strings.Split(password, defaultSeparator) + for len(passwords) < len(addrs) { + passwords = append(passwords, passwords[0]) + } + aliases := strings.Split(alias, defaultSeparator) + for len(aliases) < len(addrs) { + aliases = append(aliases, aliases[0]) + } + + instances := make([]Instance, len(addrs)) + for i := range addrs { + instances[i] = Instance{ + Addr: addrs[i], + Password: passwords[i], + Alias: aliases[i], + } + } + return &cmdArgsDiscovery{instances: instances}, nil +} + +func (d *cmdArgsDiscovery) GetInstances() []Instance { + return d.instances +} + +type fileDiscovery struct { + instances []Instance +} + +func NewFileDiscovery(fileName string) (*fileDiscovery, error) { + file, err := os.Open(fileName) + if err != nil { + return nil, err + } + defer file.Close() + + r := csv.NewReader(file) + r.FieldsPerRecord = -1 + records, err := r.ReadAll() + if err != nil { + return nil, err + } + + var instances []Instance + for _, record := range records { + instance := Instance{} + length := len(record) + switch length { + case 3: + instance.Addr = record[0] + instance.Password = record[1] + instance.Alias = record[2] + case 2: + instance.Addr = record[0] + instance.Password = record[1] + case 1: + instance.Addr = record[0] + default: + log.Warnln("pika hosts file has invalid data:", record) + continue + } + + instances = append(instances, instance) + } + + return &fileDiscovery{instances: instances}, nil +} + +func (d *fileDiscovery) GetInstances() []Instance { + return d.instances +} diff --git a/pika-tools/pika_exporter/exporter/client.go b/pika-tools/pika_exporter/exporter/client.go new file mode 100644 index 0000000000..bb176fbb0c --- /dev/null +++ b/pika-tools/pika_exporter/exporter/client.go @@ -0,0 +1,204 @@ +package exporter + +import ( + "bufio" + "errors" + "fmt" + "strings" + "time" + + "github.com/garyburd/redigo/redis" +) + +const ( + defaultScanCount = 100 +) + +const ( + keyTypeNone = "none" + keyTypeString = "string" + //keyTypeHyperLogLog = "hyperloglog" + keyTypeList = "list" + keyTypeSet = "set" + keyTypeZSet = "zset" + keyTypeHash = "hash" +) + +var ( + errNotFound = errors.New("key not found") +) + +type keyInfo struct { + size float64 + keyType string +} + +type client struct { + addr, alias string + conn redis.Conn +} + +func newClient(addr, password, alias string) (*client, error) { + conn, err := redis.Dial("tcp", addr, + redis.DialConnectTimeout(5*time.Second), + redis.DialWriteTimeout(5*time.Second), + redis.DialReadTimeout(5*time.Second), + redis.DialPassword(password)) + if err != nil { + return nil, err + } + + return &client{ + addr: addr, + alias: alias, + conn: conn, + }, nil +} + +func (c *client) Close() error { + if c.conn == nil { + return nil + } + return c.conn.Close() +} + +func (c *client) Addr() string { + return c.addr +} + +func (c *client) Alias() string { + return c.alias +} + +func (c *client) Select(db string) error { + _, err := c.conn.Do("SELECT", db) + return err +} + +// INFO ALL 命令查询返回 +func (c *client) Info() (string, error) { + return redis.String(c.conn.Do("INFO", "ALL")) +} + +func (c *client) InfoKeySpaceZero() (string, error) { + return redis.String(c.conn.Do("INFO", "KEYSPACE", 0)) +} + +func (c *client) InfoKeySpaceOne() (string, error) { + return redis.String(c.conn.Do("INFO", "KEYSPACE", 1)) +} + +// 返回模式信息 +func (c *client) InstanceModeInfo() (string, error) { + getslices, err := redis.Strings(c.conn.Do("CONFIG", "GET", "instance-mode")) + if err != nil { + return "", fmt.Errorf("CONFIG GET instance-mode '%s' ", err) + } + for _, gets := range getslices { + scanner := bufio.NewScanner(strings.NewReader(gets)) + for scanner.Scan() { + line := scanner.Text() + if line == "" { + continue + } + if line == "instance-mode" { + continue + } + return line, nil + } + } + return "", fmt.Errorf("error retrieving CONFIG GET instance-mode '%s' ", err) +} + +func (c *client) LabelConsensusLevelInfo() (string, error) { + getslices, err := redis.Strings(c.conn.Do("CONFIG", "GET", "consensus-level")) + if err != nil { + return "", fmt.Errorf("CONFIG GET consensus-level '%s' ", err) + } + for _, gets := range getslices { + scanner := bufio.NewScanner(strings.NewReader(gets)) + for scanner.Scan() { + line := scanner.Text() + if line == "" { + continue + } + if line == "consensus-level" { + continue + } + return line, nil + } + } + return "", fmt.Errorf("error retrieving CONFIG GET consensus-level '%s' ", err) +} + +// Pika的SCAN命令,会顺序迭代当前db的快照,由于Pika允许重名五次,所以SCAN有优先输出顺序,依次为:string -> hash -> list -> zset -> set +func (c *client) Scan(keyPattern string, count int) ([]string, error) { + if count == 0 { + count = defaultScanCount + } + + var ( + cursor int + keys []string + ) + for { + values, err := redis.Values(c.conn.Do("SCAN", cursor, "MATCH", keyPattern, "COUNT", count)) + if err != nil { + return keys, fmt.Errorf("error retrieving '%s' keys", keyPattern) + } + if len(values) != 2 { + return keys, fmt.Errorf("invalid response from SCAN for pattern: %s", keyPattern) + } + + ks, _ := redis.Strings(values[1], nil) + keys = append(keys, ks...) + + if cursor, _ = redis.Int(values[0], nil); cursor == 0 { + break + } + } + + return keys, nil +} + +// Pikad的TYPE命令,由于Pika允许重名五次,所以TYPE有优先输出顺序,依次为:string -> hash -> list -> zset -> set,如果这个key在string中存在,那么只输出sting,如果不存在,那么则输出hash的,依次类推 +func (c *client) Type(key string) (*keyInfo, error) { + keyType, err := redis.String(c.conn.Do("TYPE", key)) + if err != nil { + return nil, err + } + + info := &keyInfo{keyType: keyType} + switch keyType { + case keyTypeNone: + return nil, errNotFound + case keyTypeString: + if size, err := redis.Int64(c.conn.Do("STRLEN", key)); err == nil { + info.size = float64(size) + } + case keyTypeList: + if size, err := redis.Int64(c.conn.Do("LLEN", key)); err == nil { + info.size = float64(size) + } + case keyTypeSet: + if size, err := redis.Int64(c.conn.Do("SCARD", key)); err == nil { + info.size = float64(size) + } + case keyTypeZSet: + if size, err := redis.Int64(c.conn.Do("ZCARD", key)); err == nil { + info.size = float64(size) + } + case keyTypeHash: + if size, err := redis.Int64(c.conn.Do("HLEN", key)); err == nil { + info.size = float64(size) + } + default: + return nil, fmt.Errorf("unknown type: %v for key: %v", info.keyType, key) + } + + return info, nil +} + +func (c *client) Get(key string) (string, error) { + return redis.String(c.conn.Do("GET", key)) +} diff --git a/pika-tools/pika_exporter/exporter/future.go b/pika-tools/pika_exporter/exporter/future.go new file mode 100644 index 0000000000..8b393682ec --- /dev/null +++ b/pika-tools/pika_exporter/exporter/future.go @@ -0,0 +1,38 @@ +package exporter + +import "sync" + +type futureKey struct { + addr, alias string +} + +type future struct { + *sync.Mutex + wait sync.WaitGroup + m map[futureKey]error +} + +func newFuture() *future { + return &future{ + Mutex: new(sync.Mutex), + m: make(map[futureKey]error), + } +} + +func (f *future) Add() { + f.wait.Add(1) +} + +func (f *future) Done(key futureKey, val error) { + f.Lock() + defer f.Unlock() + f.m[key] = val + f.wait.Done() +} + +func (f *future) Wait() map[futureKey]error { + f.wait.Wait() + f.Lock() + defer f.Unlock() + return f.m +} diff --git a/pika-tools/pika_exporter/exporter/metrics/binlog.go b/pika-tools/pika_exporter/exporter/metrics/binlog.go new file mode 100644 index 0000000000..831f0b4147 --- /dev/null +++ b/pika-tools/pika_exporter/exporter/metrics/binlog.go @@ -0,0 +1,106 @@ +package metrics + +import "regexp" + +func init() { + Register(collectBinlogMetrics) +} + +var collectBinlogMetrics = map[string]MetricConfig{ + "binlog_log_size": { + Parser: &normalParser{}, + MetricMeta: &MetaData{ + Name: "log_size", + Help: "pika serve instance total binlog size in bytes", + Type: metricTypeGauge, + Labels: []string{LabelNameAddr, LabelNameAlias}, + ValueName: "log_size", + }, + }, + + "binlog_<3.1.0": { + Parser: &versionMatchParser{ + verC: mustNewVersionConstraint(`<3.1.0`), + Parser: ®exParser{ + name: "binlog_<3.1.0", + reg: regexp.MustCompile(`binlog_offset:(?P[^\s]*)\s*(?P[\d]*)`), + Parser: &normalParser{}, + }, + }, + MetricMeta: MetaDatas{ + { + Name: "binlog_offset_filenum", + Help: "pika serve instance binlog file num", + Type: metricTypeGauge, + Labels: []string{LabelNameAddr, LabelNameAlias}, + ValueName: "binlog_offset_filenum", + }, + { + Name: "binlog_offset", + Help: "pika serve instance binlog offset", + Type: metricTypeGauge, + Labels: []string{LabelNameAddr, LabelNameAlias, "safety_purge", "expire_logs_days", "expire_logs_nums"}, + ValueName: "binlog_offset", + }, + }, + }, + + "binlog_>=3.1.0": { + Parser: Parsers{ + &versionMatchParser{ + verC: mustNewVersionConstraint(`~3.1.0`), + Parser: ®exParser{ + name: "binlog_~3.1.0", + reg: regexp.MustCompile(`(?Pdb[\d]+):\s*binlog_offset=(?P[^\s]*)\s*(?P[\d]*),*safety_purge=(?P[^\s\r\n]*)`), + Parser: &normalParser{}, + }, + }, + &versionMatchParser{ + verC: mustNewVersionConstraint(`>=3.2.0`), + Parser: ®exParser{ + name: "binlog_>=3.2.0", + reg: regexp.MustCompile(`(?Pdb[\d]+)\s*binlog_offset=(?P[^\s]*)\s*(?P[\d]*),*safety_purge=(?P[^\s\r\n]*)`), + Parser: &normalParser{}, + }, + }, + }, + MetricMeta: MetaDatas{ + { + Name: "binlog_offset_filenum_db", + Help: "pika serve instance binlog file num for each db", + Type: metricTypeGauge, + Labels: []string{LabelNameAddr, LabelNameAlias, "db"}, + ValueName: "binlog_offset_filenum", + }, + { + Name: "binlog_offset_db", + Help: "pika serve instance binlog offset for each db", + Type: metricTypeGauge, + Labels: []string{LabelNameAddr, LabelNameAlias, "db", "safety_purge"}, + ValueName: "binlog_offset", + }, + }, + }, + + "consensus_last_log": { + Parser: Parsers{ + &versionMatchParser{ + verC: mustNewVersionConstraint(`>3.4.0`), + Parser: ®exParser{ + name: "consensus_last_log", + reg: regexp.MustCompile(`(?Pconsensus)\s*last_log=(?P[^\s\r\n]*)`), + Parser: &normalParser{}, + }, + }, + }, + MetricMeta: MetaDatas{ + { + Name: "consensus_last_log", + Help: "pika serve instance consensus last_log for each db when consensus-level is enabled", + Type: metricTypeGauge, + Labels: []string{LabelNameAddr, LabelNameAlias, "db"}, + ValueName: "consensus_last_log", + }, + }, + }, +} diff --git a/pika-tools/pika_exporter/exporter/metrics/clients.go b/pika-tools/pika_exporter/exporter/metrics/clients.go new file mode 100644 index 0000000000..ce3b9f2308 --- /dev/null +++ b/pika-tools/pika_exporter/exporter/metrics/clients.go @@ -0,0 +1,18 @@ +package metrics + +func init() { + Register(collectClientsMetrics) +} + +var collectClientsMetrics = map[string]MetricConfig{ + "clients_info": { + Parser: &normalParser{}, + MetricMeta: &MetaData{ + Name: "connected_clients", + Help: "pika serve instance total count of connected clients", + Type: metricTypeGauge, + Labels: []string{LabelNameAddr, LabelNameAlias}, + ValueName: "connected_clients", + }, + }, +} diff --git a/pika-tools/pika_exporter/exporter/metrics/command_exec_count.go b/pika-tools/pika_exporter/exporter/metrics/command_exec_count.go new file mode 100644 index 0000000000..b9c027101d --- /dev/null +++ b/pika-tools/pika_exporter/exporter/metrics/command_exec_count.go @@ -0,0 +1,32 @@ +package metrics + +import "regexp" + +func init() { + Register(collectCommandExecCountMetrics) +} + +var collectCommandExecCountMetrics = map[string]MetricConfig{ + "command_exec_count": { + Parser: &versionMatchParser{ + verC: mustNewVersionConstraint(`>=3.0.0`), + Parser: ®exParser{ + name: "command_exec_count_all_commands", + reg: regexp.MustCompile(`# Command_Exec_Count(?P[^#]*)`), + Parser: ®exParser{ + name: "command_exec_count_command", + source: "commands_count", + reg: regexp.MustCompile(`(\r|\n)*(?P[^:]+):(?P[\d]*)`), + Parser: &normalParser{}, + }, + }, + }, + MetricMeta: &MetaData{ + Name: "command_exec_count", + Help: "pika serve instance the count of each command executed", + Type: metricTypeCounter, + Labels: []string{LabelNameAddr, LabelNameAlias, "command"}, + ValueName: "count", + }, + }, +} diff --git a/pika-tools/pika_exporter/exporter/metrics/cpu.go b/pika-tools/pika_exporter/exporter/metrics/cpu.go new file mode 100644 index 0000000000..a30af203fb --- /dev/null +++ b/pika-tools/pika_exporter/exporter/metrics/cpu.go @@ -0,0 +1,60 @@ +package metrics + +func init() { + Register(collectCPUMetrics) +} + +var collectCPUMetrics = map[string]MetricConfig{ + "used_cpu_sys": { + Parser: &versionMatchParser{ + verC: mustNewVersionConstraint(`>= 2.3.x`), + Parser: &normalParser{}, + }, + MetricMeta: &MetaData{ + Name: "used_cpu_sys", + Help: "pika serve instance total count of used cpu sys", + Type: metricTypeCounter, + Labels: []string{LabelNameAddr, LabelNameAlias}, + ValueName: "used_cpu_sys", + }, + }, + "used_cpu_user": { + Parser: &versionMatchParser{ + verC: mustNewVersionConstraint(`>= 2.3.x`), + Parser: &normalParser{}, + }, + MetricMeta: &MetaData{ + Name: "used_cpu_user", + Help: "pika serve instance total count of used cpu user", + Type: metricTypeCounter, + Labels: []string{LabelNameAddr, LabelNameAlias}, + ValueName: "used_cpu_user", + }, + }, + "used_cpu_sys_children": { + Parser: &versionMatchParser{ + verC: mustNewVersionConstraint(`>= 2.3.x`), + Parser: &normalParser{}, + }, + MetricMeta: &MetaData{ + Name: "used_cpu_sys_children", + Help: "pika serve instance children total count of used cpu sys", + Type: metricTypeCounter, + Labels: []string{LabelNameAddr, LabelNameAlias}, + ValueName: "used_cpu_sys_children", + }, + }, + "used_cpu_user_children": { + Parser: &versionMatchParser{ + verC: mustNewVersionConstraint(`>= 2.3.x`), + Parser: &normalParser{}, + }, + MetricMeta: &MetaData{ + Name: "used_cpu_user_children", + Help: "pika serve instance children total count of used cpu user", + Type: metricTypeCounter, + Labels: []string{LabelNameAddr, LabelNameAlias}, + ValueName: "used_cpu_user_children", + }, + }, +} diff --git a/pika-tools/pika_exporter/exporter/metrics/data.go b/pika-tools/pika_exporter/exporter/metrics/data.go new file mode 100644 index 0000000000..ef4ed086e2 --- /dev/null +++ b/pika-tools/pika_exporter/exporter/metrics/data.go @@ -0,0 +1,58 @@ +package metrics + +func init() { + Register(collectDataMetrics) +} + +var collectDataMetrics = map[string]MetricConfig{ + "db_size": { + Parser: &normalParser{}, + MetricMeta: &MetaData{ + Name: "db_size", + Help: "pika serve instance total db data size in bytes", + Type: metricTypeGauge, + Labels: []string{LabelNameAddr, LabelNameAlias, "compression"}, + ValueName: "db_size", + }, + }, + "used_memory": { + Parser: &normalParser{}, + MetricMeta: &MetaData{ + Name: "used_memory", + Help: "pika serve instance total used memory size in bytes", + Type: metricTypeGauge, + Labels: []string{LabelNameAddr, LabelNameAlias}, + ValueName: "used_memory", + }, + }, + "db_memtable_usage": { + Parser: &normalParser{}, + MetricMeta: &MetaData{ + Name: "db_memtable_usage", + Help: "pika serve instance memtable total used memory size in bytes", + Type: metricTypeGauge, + Labels: []string{LabelNameAddr, LabelNameAlias}, + ValueName: "db_memtable_usage", + }, + }, + "db_tablereader_usage": { + Parser: &normalParser{}, + MetricMeta: &MetaData{ + Name: "db_tablereader_usage", + Help: "pika serve instance tablereader total used memory size in bytes", + Type: metricTypeGauge, + Labels: []string{LabelNameAddr, LabelNameAlias}, + ValueName: "db_tablereader_usage", + }, + }, + "db_fatal": { + Parser: &normalParser{}, + MetricMeta: &MetaData{ + Name: "db_fatal", + Help: "pika serve instance tablereader total errors ", + Type: metricTypeGauge, + Labels: []string{LabelNameAddr, LabelNameAlias}, + ValueName: "db_fatal", + }, + }, +} diff --git a/pika-tools/pika_exporter/exporter/metrics/keyspace.go b/pika-tools/pika_exporter/exporter/metrics/keyspace.go new file mode 100644 index 0000000000..c322d7c844 --- /dev/null +++ b/pika-tools/pika_exporter/exporter/metrics/keyspace.go @@ -0,0 +1,178 @@ +package metrics + +import "regexp" + +func init() { + Register(collectKeySpaceMetrics) +} + +var collectKeySpaceMetrics = map[string]MetricConfig{ + "keyspace_info": { + Parser: Parsers{ + &versionMatchParser{ + verC: mustNewVersionConstraint(`<3.0.5`), + Parser: ®exParser{ + name: "keyspace_info_<3.0.5", + reg: regexp.MustCompile(`(?P[^\s]*)\s*keys:(?P[\d]+)`), + Parser: &normalParser{}, + }, + }, + &versionMatchParser{ + verC: mustNewVersionConstraint(`~3.0.5`), + Parser: ®exParser{ + name: "keyspace_info_~3.0.5", + reg: regexp.MustCompile(`(?P\w*):\s*keys=(?P[\d]+)[,\s]*` + + `expires=(?P[\d]+)[,\s]*invaild_keys=(?P[\d]+)`), + Parser: &normalParser{}, + }, + }, + &versionMatchParser{ + verC: mustNewVersionConstraint(`~3.1.0`), + Parser: ®exParser{ + name: "keyspace_info_~3.1.0", + reg: regexp.MustCompile(`(?Pdb[\d]+)_\s*(?P[^:]+):\s*keys=(?P[\d]+)[,\s]*` + + `expires=(?P[\d]+)[,\s]*invaild_keys=(?P[\d]+)`), + Parser: &normalParser{}, + }, + }, + &versionMatchParser{ + verC: mustNewVersionConstraint(`3.2.0 - 3.3.2`), + Parser: ®exParser{ + name: "keyspace_info_3.1.0-3.3.2", + reg: regexp.MustCompile(`(?Pdb[\d]+)\s*(?P[^_]+)\w*keys=(?P[\d]+)[,\s]*` + + `expires=(?P[\d]+)[,\s]*invaild_keys=(?P[\d]+)`), + Parser: &normalParser{}, + }, + }, + &versionMatchParser{ + verC: mustNewVersionConstraint(`>=3.3.3`), + Parser: ®exParser{ + name: "keyspace_info_>=3.1.0", + reg: regexp.MustCompile(`(?Pdb[\d]+)\s*(?P[^_]+)\w*keys=(?P[\d]+)[,\s]*` + + `expires=(?P[\d]+)[,\s]*invalid_keys=(?P[\d]+)`), + Parser: &normalParser{}, + }, + }, + // &versionMatchParser{ + // verC: mustNewVersionConstraint(`>3.4.0`), + // Parser: ®exParser{ + // name: "keyspace_last_start_time>3.4.0", + // // # Time:2023-04-15 11:41:42 + // reg: regexp.MustCompile(`#\sTime:(?P[^\r\n]*)`), + // Parser: &timeParser{}, + // }, + // }, + }, + MetricMeta: MetaDatas{ + { + Name: "keys", + Help: "pika serve instance total count of the db's key-type keys", + Type: metricTypeGauge, + Labels: []string{LabelNameAddr, LabelNameAlias, "db", "type"}, + ValueName: "keys", + }, + // { + // Name: "keyspace_last_start_time", + // Help: "pika serve instance start time(unix seconds) of the last statistical keyspace", + // Type: metricTypeGauge, + // Labels: []string{LabelNameAddr, LabelNameAlias}, + // ValueName: "keyspace_last_start_time", + // }, + }, + }, + + "keyspace_info_all": { + Parser: Parsers{ + &versionMatchParser{ + verC: mustNewVersionConstraint(`~3.0.5`), + Parser: ®exParser{ + name: "keyspace_info_all_~3.0.5", + reg: regexp.MustCompile(`(?P\w*):\s*keys=(?P[\d]+)[,\s]*` + + `expires=(?P[\d]+)[,\s]*invaild_keys=(?P[\d]+)`), + Parser: &normalParser{}, + }, + }, + &versionMatchParser{ + verC: mustNewVersionConstraint(`~3.1.0`), + Parser: ®exParser{ + name: "keyspace_info_all_~3.1.0", + reg: regexp.MustCompile(`(?Pdb[\d]+)_\s*(?P[^:]+):\s*keys=(?P[\d]+)[,\s]*` + + `expires=(?P[\d]+)[,\s]*invaild_keys=(?P[\d]+)`), + Parser: &normalParser{}, + }, + }, + &versionMatchParser{ + verC: mustNewVersionConstraint(`3.2.0 - 3.3.2`), + Parser: ®exParser{ + name: "keyspace_info_all_3.1.0-3.3.2", + reg: regexp.MustCompile(`(?Pdb[\d]+)\s*(?P[^_]+)\w*keys=(?P[\d]+)[,\s]*` + + `expires=(?P[\d]+)[,\s]*invaild_keys=(?P[\d]+)`), + Parser: &normalParser{}, + }, + }, + &versionMatchParser{ + verC: mustNewVersionConstraint(`>=3.3.3`), + Parser: ®exParser{ + name: "keyspace_info_all_>=3.3.3", + reg: regexp.MustCompile(`(?Pdb[\d]+)\s*(?P[^_]+)\w*keys=(?P[\d]+)[,\s]*` + + `expires=(?P[\d]+)[,\s]*invalid_keys=(?P[\d]+)`), + Parser: &normalParser{}, + }, + }, + // &versionMatchParser{ + // verC: mustNewVersionConstraint(`>3.4.0`), + // Parser: ®exParser{ + // name: "keyspace_last_start_time>3.4.0", + // // # Time:2023-04-15 11:41:42 + // reg: regexp.MustCompile(`#\sTime:(?P[^\r\n]*)`), + // Parser: &timeParser{}, + // }, + // }, + }, + MetricMeta: MetaDatas{ + { + Name: "expire_keys", + Help: "pika serve instance total count of the db's key-type expire keys", + Type: metricTypeGauge, + Labels: []string{LabelNameAddr, LabelNameAlias, "db", "type"}, + ValueName: "expire_keys", + }, + { + Name: "invalid_keys", + Help: "pika serve instance total count of the db's key-type invalid keys", + Type: metricTypeGauge, + Labels: []string{LabelNameAddr, LabelNameAlias, "db", "type"}, + ValueName: "invalid_keys", + }, + // { + // Name: "keyspace_last_start_time", + // Help: "pika serve instance start time(unix seconds) of the last statistical keyspace", + // Type: metricTypeGauge, + // Labels: []string{LabelNameAddr, LabelNameAlias}, + // ValueName: "keyspace_last_start_time", + // }, + }, + }, + "keyspace_last": { + Parser: Parsers{ + &versionMatchParser{ + verC: mustNewVersionConstraint(`>3.4.0`), + Parser: ®exParser{ + name: "keyspace_last_start_time", + // # Time:2023-04-15 11:41:42 + reg: regexp.MustCompile(`#\sTime:(?P[^\r\n]*)`), + Parser: &timeParser{}, + }, + }, + }, + MetricMeta: MetaDatas{ + { + Name: "keyspace_last_start_time", + Help: "pika serve instance start time(unix seconds) of the last statistical keyspace", + Type: metricTypeGauge, + Labels: []string{LabelNameAddr, LabelNameAlias}, + ValueName: "keyspace_last_start_time", + }, + }, + }, +} diff --git a/pika-tools/pika_exporter/exporter/metrics/metrics.go b/pika-tools/pika_exporter/exporter/metrics/metrics.go new file mode 100644 index 0000000000..d571a1787c --- /dev/null +++ b/pika-tools/pika_exporter/exporter/metrics/metrics.go @@ -0,0 +1,107 @@ +package metrics + +import ( + "fmt" + + "github.com/prometheus/client_golang/prometheus" +) + +const ( + metricTypeCounter = "counter" + metricTypeGauge = "gauge" +) + +const ( + LabelNameAddr = "addr" + LabelNameAlias = "alias" + LabelInstanceMode = "instance-mode" + LabelConsensusLevel = "consensus-level" +) + +type Describer interface { + Describe(data MetaData) +} + +type DescribeFunc func(m MetaData) + +func (d DescribeFunc) Describe(m MetaData) { + d(m) +} + +type Collector interface { + Collect(metric Metric) error +} + +type CollectFunc func(metric Metric) error + +func (c CollectFunc) Collect(metric Metric) error { + return c(metric) +} + +type MetricMeta interface { + Desc(d Describer) + Lookup(func(m MetaData)) +} + +type MetaData struct { + Name string + Help string + Type string + Labels []string + ValueName string +} + +func (m MetaData) Desc(d Describer) { + d.Describe(m) +} + +func (m MetaData) Lookup(f func(m MetaData)) { + f(m) +} + +func (m MetaData) MetricsType() prometheus.ValueType { + switch m.Type { + case "counter": + return prometheus.CounterValue + case "gauge": + return prometheus.GaugeValue + default: + return prometheus.UntypedValue + } +} + +type MetaDatas []MetaData + +func (ms MetaDatas) Desc(d Describer) { + for _, m := range ms { + m.Desc(d) + } +} + +func (ms MetaDatas) Lookup(f func(m MetaData)) { + for _, m := range ms { + f(m) + } +} + +type Metric struct { + MetaData + LabelValues []string + Value float64 +} + +type MetricConfig struct { + Parser + MetricMeta +} + +var MetricConfigs = make(map[string]MetricConfig) + +func Register(mcs map[string]MetricConfig) { + for k, mc := range mcs { + if _, ok := MetricConfigs[k]; ok { + panic(fmt.Sprintf("register metrics config error. metricConfigName:%s existed", k)) + } + MetricConfigs[k] = mc + } +} diff --git a/pika-tools/pika_exporter/exporter/metrics/parser.go b/pika-tools/pika_exporter/exporter/metrics/parser.go new file mode 100644 index 0000000000..e236a5befa --- /dev/null +++ b/pika-tools/pika_exporter/exporter/metrics/parser.go @@ -0,0 +1,266 @@ +package metrics + +import ( + "regexp" + "strconv" + "strings" + "time" + + "github.com/Masterminds/semver" + log "github.com/sirupsen/logrus" +) + +const ( + defaultValue = 0 +) + +type ParseOption struct { + Version *semver.Version + Extracts map[string]string + Info string +} + +type Parser interface { + Parse(m MetricMeta, c Collector, opt ParseOption) +} + +type Parsers []Parser + +func (ps Parsers) Parse(m MetricMeta, c Collector, opt ParseOption) { + for _, p := range ps { + p.Parse(m, c, opt) + } +} + +type versionMatchParser struct { + verC *semver.Constraints + Parser +} + +func (p *versionMatchParser) Parse(m MetricMeta, c Collector, opt ParseOption) { + if opt.Version == nil || !p.verC.Check(opt.Version) { + return + } + p.Parser.Parse(m, c, opt) +} + +type Matcher interface { + Match(v string) bool +} + +type equalMatcher struct { + v string +} + +func (m *equalMatcher) Match(v string) bool { + return strings.ToLower(v) == strings.ToLower(m.v) +} + +type intMatcher struct { + condition string + v int +} + +func (m *intMatcher) Match(v string) bool { + nv, err := strconv.Atoi(v) + if err != nil { + return false + } + + switch m.condition { + case ">": + return nv > m.v + case "<": + return nv < m.v + case ">=": + return nv >= m.v + case "<=": + return nv <= m.v + } + return false +} + +type keyMatchParser struct { + matchers map[string]Matcher + Parser +} + +func (p *keyMatchParser) Parse(m MetricMeta, c Collector, opt ParseOption) { + for key, matcher := range p.matchers { + if v, _ := opt.Extracts[key]; !matcher.Match(v) { + return + } + } + p.Parser.Parse(m, c, opt) +} + +type regexParser struct { + name string + source string + reg *regexp.Regexp + Parser +} + +func (p *regexParser) Parse(m MetricMeta, c Collector, opt ParseOption) { + s := opt.Info + if p.source != "" { + s = opt.Extracts[p.source] + } + + matchMaps := p.regMatchesToMap(s) + if len(matchMaps) == 0 { + log.Warnf("regexParser::Parse reg find sub match nil. name:%s text:%s", p.name, s) + } + + extracts := make(map[string]string) + for k, v := range opt.Extracts { + extracts[k] = v + } + + opt.Extracts = extracts + for _, matches := range matchMaps { + for k, v := range matches { + extracts[k] = v + } + p.Parser.Parse(m, c, opt) + } +} + +func (p *regexParser) regMatchesToMap(s string) []map[string]string { + if s == "" { + return nil + } + + multiMatches := p.reg.FindAllStringSubmatch(s, -1) + if len(multiMatches) == 0 { + log.Errorf("regexParser::regMatchesToMap reg find sub match nil. name:%s text:%s", p.name, s) + return nil + } + + ms := make([]map[string]string, len(multiMatches)) + for i, matches := range multiMatches { + ms[i] = make(map[string]string) + for j, name := range p.reg.SubexpNames() { + ms[i][name] = trimSpace(matches[j]) + } + } + return ms +} + +type normalParser struct{} + +func (p *normalParser) Parse(m MetricMeta, c Collector, opt ParseOption) { + m.Lookup(func(m MetaData) { + metric := Metric{ + MetaData: m, + LabelValues: make([]string, len(m.Labels)), + Value: defaultValue, + } + + for i, labelName := range m.Labels { + labelValue, ok := findInMap(labelName, opt.Extracts) + if !ok { + log.Debugf("normalParser::Parse not found label value. metricName:%s labelName:%s", + m.Name, labelName) + } + + metric.LabelValues[i] = labelValue + } + + if m.ValueName != "" { + if v, ok := findInMap(m.ValueName, opt.Extracts); !ok { + log.Warnf("normalParser::Parse not found value. metricName:%s valueName:%s", m.Name, m.ValueName) + return + } else { + metric.Value = convertToFloat64(v) + } + } + + if err := c.Collect(metric); err != nil { + log.Errorf("normalParser::Parse metric collect failed. metric:%#v err:%s", + m, m.ValueName) + } + }) +} + +type timeParser struct{} + +func (p *timeParser) Parse(m MetricMeta, c Collector, opt ParseOption) { + m.Lookup(func(m MetaData) { + metric := Metric{ + MetaData: m, + LabelValues: make([]string, len(m.Labels)), + Value: defaultValue, + } + + for i, labelName := range m.Labels { + labelValue, ok := findInMap(labelName, opt.Extracts) + if !ok { + log.Debugf("timeParser::Parse not found label value. metricName:%s labelName:%s", + m.Name, labelName) + } + + metric.LabelValues[i] = labelValue + } + + if m.ValueName != "" { + if v, ok := findInMap(m.ValueName, opt.Extracts); !ok { + log.Warnf("timeParser::Parse not found value. metricName:%s valueName:%s", m.Name, m.ValueName) + return + } else { + metric.Value = float64(converTimeToUnix(v)) + } + } + + if err := c.Collect(metric); err != nil { + log.Errorf("timeParser::Parse metric collect failed. metric:%#v err:%s", + m, m.ValueName) + } + }) +} + +func findInMap(key string, ms ...map[string]string) (string, bool) { + for _, m := range ms { + if v, ok := m[key]; ok { + return v, true + } + } + return "", false +} + +func trimSpace(s string) string { + return strings.TrimRight(strings.TrimLeft(s, " "), " ") +} + +func convertToFloat64(s string) float64 { + s = strings.ToLower(s) + + switch s { + case "yes", "up", "online": + return 1 + case "no", "down", "offline", "null": + return 0 + } + + n, err := strconv.ParseFloat(s, 64) + if err != nil { + return 0 + } + return n +} + +func mustNewVersionConstraint(version string) *semver.Constraints { + c, err := semver.NewConstraint(version) + if err != nil { + panic(err) + } + return c +} + +func converTimeToUnix(ts string) int64 { + t, err := time.Parse("2006-01-02 15:04:05", ts) + if err != nil { + panic(err) + } + return t.Unix() +} diff --git a/pika-tools/pika_exporter/exporter/metrics/replication.go b/pika-tools/pika_exporter/exporter/metrics/replication.go new file mode 100644 index 0000000000..514dd7dc6d --- /dev/null +++ b/pika-tools/pika_exporter/exporter/metrics/replication.go @@ -0,0 +1,300 @@ +package metrics + +import "regexp" + +func init() { + Register(collectReplicationMetrics) +} + +var collectReplicationMetrics = map[string]MetricConfig{ + "master_connected_slaves": { + Parser: &keyMatchParser{ + matchers: map[string]Matcher{ + "role": &equalMatcher{v: "master"}, + }, + Parser: Parsers{ + &normalParser{}, + }, + }, + MetricMeta: &MetaData{ + Name: "connected_slaves", + Help: "the count of connected slaves, when pika serve instance's role is master", + Type: metricTypeGauge, + Labels: []string{LabelNameAddr, LabelNameAlias}, + ValueName: "connected_slaves", + }, + }, + + "master_slave_info": { + Parser: &keyMatchParser{ + matchers: map[string]Matcher{ + "role": &equalMatcher{v: "master"}, + "connected_slaves": &intMatcher{condition: ">", v: 0}, + }, + Parser: Parsers{ + &versionMatchParser{ + verC: mustNewVersionConstraint(`<2.3.x`), + Parser: ®exParser{ + name: "master_slave_info_slave_state", + reg: regexp.MustCompile(`slave\d+:ip=(?P[\d.]+),port=(?P[\d.]+),` + + `state=(?P[a-z]+)`), + Parser: &normalParser{}, + }, + }, + &versionMatchParser{ + verC: mustNewVersionConstraint(`>=2.3.x,<3.1.0`), + Parser: ®exParser{ + name: "master_slave_info_slave_state", + reg: regexp.MustCompile(`slave\d+:ip=(?P[\d.]+),port=(?P[\d.]+),` + + `state=(?P[a-z]+),sid=(?P[\d]+),lag=(?P[\d]+)`), + Parser: &normalParser{}, + }, + }, + }, + }, + MetricMeta: &MetaDatas{ + { + Name: "slave_state", + Help: "pika serve instance slave's state", + Type: metricTypeGauge, + Labels: []string{LabelNameAddr, LabelNameAlias, "slave_sid", "slave_conn_fd", "slave_ip", "slave_port"}, + ValueName: "slave_state", + }, + }, + }, + + "master_slave_info_slave_lag": { + Parser: &keyMatchParser{ + matchers: map[string]Matcher{ + "role": &equalMatcher{v: "master"}, + "connected_slaves": &intMatcher{condition: ">", v: 0}, + "instance-mode": &equalMatcher{v: "classic"}, + }, + Parser: Parsers{ + &versionMatchParser{ + verC: mustNewVersionConstraint(`>=2.3.x,<3.1.0`), + Parser: ®exParser{ + name: "master_slave_info_slave_lag_<3.1.0", + reg: regexp.MustCompile(`slave\d+:ip=(?P[\d.]+),port=(?P[\d.]+),` + + `state=(?P[a-z]+),sid=(?P[\d]+),lag=(?P[\d]+)`), + Parser: &normalParser{}, + }, + }, + &versionMatchParser{ + verC: mustNewVersionConstraint(`>=3.1.0`), + Parser: ®exParser{ + name: "master_slave_info_slave_lag_>=3.1.0", + reg: regexp.MustCompile(`slave\d+:ip=(?P[\d.]+),port=(?P[\d.]+),` + + `conn_fd=(?P[\d]+),lag=(?P[^\r\n]*)`), + Parser: ®exParser{ + name: "master_slave_info_slave_lag_db_>=3.1.0", + source: "slave_lag", + reg: regexp.MustCompile(`((?Pdb[\d.]+):(?P[\d]+))`), + Parser: &normalParser{}, + }, + }, + }, + }, + }, + MetricMeta: &MetaDatas{ + { + Name: "slave_lag", + Help: "pika serve instance slave's partition binlog lag", + Type: metricTypeGauge, + Labels: []string{LabelNameAddr, LabelNameAlias, "slave_conn_fd", "slave_ip", "slave_port", "partition"}, + ValueName: "slave_lag", + }, + }, + }, + "master_sharding_slave_info_slave_lag": { + Parser: &keyMatchParser{ + matchers: map[string]Matcher{ + "role": &equalMatcher{v: "master"}, + "connected_slaves": &intMatcher{condition: ">", v: 0}, + "instance-mode": &equalMatcher{v: "sharding"}, + }, + Parser: Parsers{ + &versionMatchParser{ + verC: mustNewVersionConstraint(`>=3.4.0`), + Parser: ®exParser{ + name: "master_sharding_slave_info_slave_lag", + reg: regexp.MustCompile(`slave\d+:ip=(?P[\d.]+),port=(?P[\d.]+),` + + `conn_fd=(?P[\d]+),lag=(?P[^\r\n]*)`), + Parser: ®exParser{ + name: "master_sharding_slave_info_slave_lag", + source: "slave_lag", + reg: regexp.MustCompile(`((?Pdb[\d.]+:[\d.]+).*:(?P[\d]+))`), + Parser: &normalParser{}, + }, + }, + }, + &versionMatchParser{ + verC: mustNewVersionConstraint(`>=3.4.0`), + Parser: ®exParser{ + name: "master_sharding_slave_info_slave_lag", + reg: regexp.MustCompile(`db_repl_state:(?P[^\r\n]*)`), + Parser: ®exParser{ + name: "master_sharding_slave_info_slave_lag", + source: "slave_lag", + reg: regexp.MustCompile(`((?Pdb[\d.]+:[\d.]+).*:(?P[\d]+))`), + Parser: &normalParser{}, + }, + }, + }, + }, + }, + MetricMeta: &MetaDatas{ + { + Name: "partition_slave_lag", + Help: "pika serve instance slave's partition binlog lag", + Type: metricTypeGauge, + Labels: []string{LabelNameAddr, LabelNameAlias, "slave_conn_fd", "slave_ip", "slave_port", "partition"}, + ValueName: "partition_slave_lag", + }, + }, + }, + + "slave_info>=3..0": { + Parser: &keyMatchParser{ + matchers: map[string]Matcher{ + "role": &equalMatcher{v: "slave"}, + }, + Parser: Parsers{ + &normalParser{}, + }, + }, + MetricMeta: MetaDatas{ + { + Name: "master_link_status", + Help: "connection state between slave and master, when pika serve instance's " + + "role is slave", + Type: metricTypeGauge, + Labels: []string{LabelNameAddr, LabelNameAlias, "master_host", "master_port"}, + ValueName: "master_link_status", + }, + }, + }, + + "slave_info<3.2.0": { + Parser: &keyMatchParser{ + matchers: map[string]Matcher{ + "role": &equalMatcher{v: "slave"}, + }, + Parser: &versionMatchParser{ + verC: mustNewVersionConstraint(`<3.2.0`), + Parser: &normalParser{}, + }, + }, + MetricMeta: MetaDatas{ + { + Name: "repl_state", + Help: "sync connection state between slave and master, when pika serve instance's " + + "role is slave", + Type: metricTypeGauge, + Labels: []string{LabelNameAddr, LabelNameAlias, "master_host", "master_port", "repl_state"}, + }, + { + Name: "slave_read_only", + Help: "is slave read only, when pika serve instance's role is slave", + Type: metricTypeGauge, + Labels: []string{LabelNameAddr, LabelNameAlias, "master_host", "master_port"}, + ValueName: "slave_read_only", + }, + }, + }, + + "slave_info>=3.0.0": { + Parser: &keyMatchParser{ + matchers: map[string]Matcher{ + "role": &equalMatcher{v: "slave"}, + }, + Parser: &versionMatchParser{ + verC: mustNewVersionConstraint(`>=3.0.0`), + Parser: &normalParser{}, + }, + }, + MetricMeta: &MetaData{ + Name: "slave_priority", + Help: "slave priority, when pika serve instance's role is slave", + Type: metricTypeGauge, + Labels: []string{LabelNameAddr, LabelNameAlias, "master_host", "master_port"}, + ValueName: "slave_priority", + }, + }, + + "sharding_slave_info>=3.4.0": { + Parser: &keyMatchParser{ + matchers: map[string]Matcher{ + "role": &equalMatcher{v: "slave"}, + "instance-mode": &equalMatcher{v: "sharding"}, + }, + Parser: &versionMatchParser{ + verC: mustNewVersionConstraint(`>=3.4.0`), + Parser: &normalParser{}, + }, + }, + MetricMeta: &MetaData{ + Name: "partition_repl_state", + Help: "sync connection state between slave and master for each partition, when pika instance's role is slave", + Type: metricTypeGauge, + Labels: []string{LabelNameAddr, LabelNameAlias, "master_host", "master_port"}, + ValueName: "partition_repl_state", + }, + }, + + "double_master_info": { + Parser: &keyMatchParser{ + matchers: map[string]Matcher{ + "role": &equalMatcher{v: "master"}, + "double_master_mode": &equalMatcher{v: "true"}, + }, + Parser: ®exParser{ + name: "double_master_info", + reg: regexp.MustCompile(`the peer-master host:(?P[^\r\n]*)[\s\S]*` + + `the peer-master port:(?P[^\r\n]*)[\s\S]*` + + `the peer-master server_id:(?P[^\r\n]*)[\s\S]*` + + `repl_state:(?P[^\r\n]*)[\s\S]*` + + `double_master_recv_info:\s*filenum\s*(?P[^\s]*)` + + `\s*offset\s*(?P[^\r\n]*)`), + Parser: &normalParser{}, + }, + }, + MetricMeta: MetaDatas{ + { + Name: "double_master_info", + Help: "the peer master info, when pika serve instance's role is master and " + + "double_master_mode is true", + Type: metricTypeGauge, + Labels: []string{LabelNameAddr, LabelNameAlias, "the_peer_master_server_id", + "the_peer_master_host", "the_peer_master_port"}, + }, + { + Name: "double_master_repl_state", + Help: "double master sync state, when pika serve instance's role is master and " + + "double_master_mode is true", + Type: metricTypeGauge, + Labels: []string{LabelNameAddr, LabelNameAlias, "the_peer_master_server_id", + "the_peer_master_host", "the_peer_master_port"}, + ValueName: "double_master_repl_state", + }, + { + Name: "double_master_recv_info_binlog_filenum", + Help: "double master recv binlog file num, when pika serve instance's role is master and " + + "double_master_mode is true", + Type: metricTypeGauge, + Labels: []string{LabelNameAddr, LabelNameAlias, "the_peer_master_server_id", + "the_peer_master_host", "the_peer_master_port"}, + ValueName: "double_master_recv_info_binlog_filenum", + }, + { + Name: "double_master_recv_info_binlog_offset", + Help: "double master recv binlog offset, when pika serve instance's role is master and " + + "double_master_mode is true", + Type: metricTypeGauge, + Labels: []string{LabelNameAddr, LabelNameAlias, "the_peer_master_server_id", + "the_peer_master_host", "the_peer_master_port"}, + ValueName: "double_master_recv_info_binlog_offset", + }, + }, + }, +} diff --git a/pika-tools/pika_exporter/exporter/metrics/server.go b/pika-tools/pika_exporter/exporter/metrics/server.go new file mode 100644 index 0000000000..bd19715c2a --- /dev/null +++ b/pika-tools/pika_exporter/exporter/metrics/server.go @@ -0,0 +1,56 @@ +package metrics + +func init() { + Register(collectServerMetrics) +} + +var collectServerMetrics = map[string]MetricConfig{ + "build_info": { + Parser: &normalParser{}, + MetricMeta: &MetaData{ + Name: "build_info", + Help: "pika binary file build info", + Type: metricTypeGauge, + Labels: []string{LabelNameAddr, LabelNameAlias, "os", "arch_bits", "pika_version", "pika_git_sha", "pika_build_compile_date"}, + }, + }, + "server_info": { + Parser: &normalParser{}, + MetricMeta: &MetaData{ + Name: "server_info", + Help: "pika serve instance info", + Type: metricTypeGauge, + Labels: []string{LabelNameAddr, LabelNameAlias, "process_id", "tcp_port", "config_file", "server_id", "role"}, + }, + }, + "uptime_in_seconds": { + Parser: &normalParser{}, + MetricMeta: &MetaData{ + Name: "uptime_in_seconds", + Help: "pika serve instance uptime in seconds", + Type: metricTypeGauge, + Labels: []string{LabelNameAddr, LabelNameAlias}, + ValueName: "uptime_in_seconds", + }, + }, + "thread_num": { + Parser: &normalParser{}, + MetricMeta: &MetaData{ + Name: "thread_num", + Help: "pika serve instance thread num", + Type: metricTypeGauge, + Labels: []string{LabelNameAddr, LabelNameAlias}, + ValueName: "thread_num", + }, + }, + "sync_thread_num": { + Parser: &normalParser{}, + MetricMeta: &MetaData{ + Name: "sync_thread_num", + Help: "pika serve instance sync thread num", + Type: metricTypeGauge, + Labels: []string{LabelNameAddr, LabelNameAlias}, + ValueName: "sync_thread_num", + }, + }, +} diff --git a/pika-tools/pika_exporter/exporter/metrics/stats.go b/pika-tools/pika_exporter/exporter/metrics/stats.go new file mode 100644 index 0000000000..99efd11101 --- /dev/null +++ b/pika-tools/pika_exporter/exporter/metrics/stats.go @@ -0,0 +1,81 @@ +package metrics + +import "regexp" + +func init() { + Register(collectStatsMetrics) +} + +var collectStatsMetrics = map[string]MetricConfig{ + "total_connections_received": { + Parser: &normalParser{}, + MetricMeta: &MetaData{ + Name: "total_connections_received", + Help: "pika serve instance total count of received connections from clients", + Type: metricTypeCounter, + Labels: []string{LabelNameAddr, LabelNameAlias}, + ValueName: "total_connections_received", + }, + }, + "instantaneous_ops_per_sec": { + Parser: &normalParser{}, + MetricMeta: &MetaData{ + Name: "instantaneous_ops_per_sec", + Help: "pika serve instance prcessed operations in per second", + Type: metricTypeGauge, + Labels: []string{LabelNameAddr, LabelNameAlias}, + ValueName: "instantaneous_ops_per_sec", + }, + }, + "total_commands_processed": { + Parser: &normalParser{}, + MetricMeta: &MetaData{ + Name: "total_commands_processed", + Help: "pika serve instance total count of processed commands", + Type: metricTypeCounter, + Labels: []string{LabelNameAddr, LabelNameAlias}, + ValueName: "total_commands_processed", + }, + }, + "is_bgsaving": { + Parser: ®exParser{ + name: "is_bgsaving", + reg: regexp.MustCompile(`is_bgsaving:(?P(No|Yes)),?(?P[^,\r\n]*)`), + Parser: &normalParser{}, + }, + MetricMeta: &MetaData{ + Name: "is_bgsaving", + Help: "pika serve instance bg save info", + Type: metricTypeGauge, + Labels: []string{LabelNameAddr, LabelNameAlias, "bgsave_name"}, + ValueName: "is_bgsaving", + }, + }, + "is_scaning_keyspace": { + Parser: ®exParser{ + name: "is_scaning_keyspace", + reg: regexp.MustCompile(`is_scaning_keyspace:(?P(No|Yes))[\s\S]*#\s*Time:(?P[^\r\n]*)`), + Parser: &normalParser{}, + }, + MetricMeta: &MetaData{ + Name: "is_scaning_keyspace", + Help: "pika serve instance scan keyspace info", + Type: metricTypeGauge, + Labels: []string{LabelNameAddr, LabelNameAlias, "keyspace_time"}, + ValueName: "is_scaning_keyspace", + }, + }, + "compact": { + Parser: ®exParser{ + name: "compact", + reg: regexp.MustCompile(`is_compact:(?P[^\r\n]*)[\s\S]*compact_cron:(?P[^\r\n]*)([\s\S]*compact_interval:(?P[^\r\n]*))?`), + Parser: &normalParser{}, + }, + MetricMeta: &MetaData{ + Name: "compact", + Help: "pika serve instance compact info", + Type: metricTypeGauge, + Labels: []string{LabelNameAddr, LabelNameAlias, "is_compact", "compact_cron", "compact_interval"}, + }, + }, +} diff --git a/pika-tools/pika_exporter/exporter/parser.go b/pika-tools/pika_exporter/exporter/parser.go new file mode 100644 index 0000000000..b6543dfb46 --- /dev/null +++ b/pika-tools/pika_exporter/exporter/parser.go @@ -0,0 +1,77 @@ +package exporter + +import ( + "bufio" + "errors" + "strings" + + "github.com/Masterminds/semver" +) + +const ( + keyValueSeparator = ":" + doubleQuotationMark = "\"" + pikaVersionKey = "pika_version" +) + +func parseInfo(info string) (*semver.Version, map[string]string, error) { + extracts, err := extractInfo(info) + if err != nil { + return nil, nil, err + } + + version, err := semver.NewVersion(getVersion(extracts)) + if err != nil { + return nil, nil, errors.New("invalid version in info") + } + + return version, extracts, nil +} + +func extractInfo(s string) (map[string]string, error) { + m := make(map[string]string) + scanner := bufio.NewScanner(strings.NewReader(s)) + for scanner.Scan() { + line := scanner.Text() + + cleanLine := trimSpace(line) + if cleanLine == "" { + continue + } + + k, v := fetchKV(cleanLine) + m[k] = v + } + if err := scanner.Err(); err != nil { + return nil, err + } + + return m, scanner.Err() +} + +func trimSpace(s string) string { + s = strings.TrimLeft(s, " ") + s = strings.TrimRight(s, " ") + return s +} + +func fetchKV(s string) (k, v string) { + pos := strings.Index(s, keyValueSeparator) + if pos < 0 { + k = s + return + } + + k = trimSpace(s[:pos]) + v = trimSpace(s[pos+1:]) + return +} + +func getVersion(extracted map[string]string) (version string) { + version, _ = extracted[pikaVersionKey] + vv := strings.Split(version, ".") + if len(vv) > 3 { + version = strings.Join(vv[:3], ".") + } + return +} diff --git a/pika-tools/pika_exporter/exporter/parser_test.go b/pika-tools/pika_exporter/exporter/parser_test.go new file mode 100644 index 0000000000..71a818358c --- /dev/null +++ b/pika-tools/pika_exporter/exporter/parser_test.go @@ -0,0 +1,92 @@ +package exporter + +import ( + "fmt" + "github.com/Masterminds/semver" + "github.com/OpenAtomFoundation/pika/pika-tools/pika_exporter/exporter/metrics" + "github.com/OpenAtomFoundation/pika/pika-tools/pika_exporter/exporter/test" + "github.com/stretchr/testify/assert" + "testing" +) + +func mustNewVersionConstraint(version string) *semver.Constraints { + c, err := semver.NewConstraint(version) + if err != nil { + panic(err) + } + return c +} + +func Test_Parse_Info(t *testing.T) { + for _, infoCase := range test.InfoCases { + version, extracts, err := parseInfo(infoCase.Info) + if err != nil { + t.Errorf("%s parse info fialed. err:%s", infoCase.Name, err.Error()) + } + + extracts[metrics.LabelNameAddr] = "127.0.0.1" + extracts[metrics.LabelNameAlias] = "" + + collector := metrics.CollectFunc(func(m metrics.Metric) error { + t.Logf("metric:%#v", m) + return nil + }) + parseOpt := metrics.ParseOption{ + Version: version, + Extracts: extracts, + Info: infoCase.Info, + } + + // for k, v := range extracts { + // fmt.Println(k, ' ... ', v) + // } + + t.Logf("##########%s begin parse###########", infoCase.Name) + for _, m := range metrics.MetricConfigs { + m.Parse(m, collector, parseOpt) + fmt.Println(m) + } + } +} + +func Test_Parse_Version_Error(t *testing.T) { + assert := assert.New(t) + + info := `# Server +pika_version:aaa +pika_git_sha:b22b0561f9093057d2e2d5cc783ff630fb2c8884 +pika_build_compile_date: Nov 7 2019 +os:Linux 3.10.0-1062.9.1.el7.x86_64 x86_64` + + version, _, err := parseInfo(info) + assert.Nil(version) + assert.Error(err) +} + +func Benchmark_Parse(b *testing.B) { + b.RunParallel(func(pb *testing.PB) { + for pb.Next() { + info := test.V320MasterInfo + + version, extracts, err := parseInfo(info) + if err != nil { + b.Error(err) + } + + extracts[metrics.LabelNameAddr] = "127.0.0.1" + extracts[metrics.LabelNameAlias] = "" + + collector := metrics.CollectFunc(func(m metrics.Metric) error { + return nil + }) + parseOpt := metrics.ParseOption{ + Version: version, + Extracts: extracts, + Info: info, + } + for _, m := range metrics.MetricConfigs { + m.Parse(m, collector, parseOpt) + } + } + }) +} diff --git a/pika-tools/pika_exporter/exporter/pika.go b/pika-tools/pika_exporter/exporter/pika.go new file mode 100644 index 0000000000..9283acd161 --- /dev/null +++ b/pika-tools/pika_exporter/exporter/pika.go @@ -0,0 +1,389 @@ +package exporter + +import ( + "fmt" + "net/url" + "regexp" + "strings" + "sync" + "time" + + "github.com/OpenAtomFoundation/pika/pika-tools/pika_exporter/discovery" + + "github.com/OpenAtomFoundation/pika/pika-tools/pika_exporter/exporter/metrics" + "github.com/prometheus/client_golang/prometheus" + log "github.com/sirupsen/logrus" +) + +type dbKeyPair struct { + db, key string +} + +type exporter struct { + dis discovery.Discovery + namespace string + keyPatterns, keys []dbKeyPair + scanCount int + collectDuration prometheus.Histogram + collectCount prometheus.Counter + scrapeDuration *prometheus.HistogramVec + scrapeErrors *prometheus.CounterVec + scrapeLastError *prometheus.GaugeVec + scrapeCount *prometheus.CounterVec + up *prometheus.GaugeVec + keyValues, keySizes *prometheus.GaugeVec + mutex *sync.Mutex + wg sync.WaitGroup + done chan struct{} +} + +func NewPikaExporter(dis discovery.Discovery, namespace string, + keyPatterns, keys string, scanCount, statsClockHour int) (*exporter, error) { + e := &exporter{ + dis: dis, + namespace: namespace, + mutex: new(sync.Mutex), + done: make(chan struct{}), + } + + var err error + if e.keyPatterns, err = parseKeyArg(keyPatterns); err != nil { + return nil, err + } + if e.keys, err = parseKeyArg(keys); err != nil { + return nil, err + } + e.scanCount = scanCount + + e.initMetrics() + e.wg.Add(1) + go e.statsKeySpace(statsClockHour) + return e, nil +} + +func (e *exporter) initMetrics() { + e.collectDuration = prometheus.NewHistogram(prometheus.HistogramOpts{ + Namespace: e.namespace, + Name: "exporter_collect_duration_seconds", + Help: "the duration of pika-exporter collect in seconds", + Buckets: []float64{ // 1ms ~ 10s + 0.001, 0.005, 0.01, + 0.015, 0.02, 0.025, 0.03, 0.035, 0.04, 0.045, 0.05, 0.055, 0.06, 0.065, 0.07, 0.075, 0.08, 0.085, 0.09, 0.095, 0.1, + 0.11, 0.12, 0.13, 0.14, 0.15, 0.16, 0.17, 0.18, 0.19, 0.20, + 0.25, 0.5, 0.75, + 1, 2, 5, 10, + }}) + e.collectCount = prometheus.NewCounter(prometheus.CounterOpts{ + Namespace: e.namespace, + Name: "exporter_collect_count", + Help: "the count of pika-exporter collect"}) + e.scrapeDuration = prometheus.NewHistogramVec(prometheus.HistogramOpts{ + Namespace: e.namespace, + Name: "exporter_scrape_duration_seconds", + Help: "the each of pika scrape duration in seconds", + Buckets: []float64{ // 1ms ~ 10s + 0.001, 0.005, 0.01, + 0.015, 0.02, 0.025, 0.03, 0.035, 0.04, 0.045, 0.05, 0.055, 0.06, 0.065, 0.07, 0.075, 0.08, 0.085, 0.09, 0.095, 0.1, + 0.11, 0.12, 0.13, 0.14, 0.15, 0.16, 0.17, 0.18, 0.19, 0.20, + 0.25, 0.5, 0.75, + 1, 2, 5, 10, + }, + }, []string{metrics.LabelNameAddr, metrics.LabelNameAlias}) + e.scrapeErrors = prometheus.NewCounterVec(prometheus.CounterOpts{ + Namespace: e.namespace, + Name: "exporter_scrape_errors", + Help: "the each of pika scrape error count", + }, []string{metrics.LabelNameAddr, metrics.LabelNameAlias}) + e.scrapeLastError = prometheus.NewGaugeVec(prometheus.GaugeOpts{ + Namespace: e.namespace, + Name: "exporter_last_scrape_error", + Help: "the each of pika scrape last error", + }, []string{metrics.LabelNameAddr, metrics.LabelNameAlias, "error"}) + e.scrapeCount = prometheus.NewCounterVec(prometheus.CounterOpts{ + Namespace: e.namespace, + Name: "exporter_scrape_count", + Help: "the each of pika scrape count", + }, []string{metrics.LabelNameAddr, metrics.LabelNameAlias}) + e.up = prometheus.NewGaugeVec(prometheus.GaugeOpts{ + Namespace: e.namespace, + Name: "up", + Help: "the each of pika connection status", + }, []string{metrics.LabelNameAddr, metrics.LabelNameAlias}) + + e.keyValues = prometheus.NewGaugeVec(prometheus.GaugeOpts{ + Namespace: e.namespace, + Name: "key_value", + }, []string{"addr", "alias", "db", "key", "key_value"}) + e.keySizes = prometheus.NewGaugeVec(prometheus.GaugeOpts{ + Namespace: e.namespace, + Name: "key_size", + }, []string{"addr", "alias", "db", "key", "key_type"}) +} + +func (e *exporter) Close() error { + close(e.done) + e.wg.Wait() + return nil +} + +func (e *exporter) Describe(ch chan<- *prometheus.Desc) { + describer := metrics.DescribeFunc(func(m metrics.MetaData) { + ch <- prometheus.NewDesc(prometheus.BuildFQName(e.namespace, "", m.Name), m.Help, m.Labels, nil) + }) + for _, metric := range metrics.MetricConfigs { + metric.Desc(describer) + } + + ch <- e.collectDuration.Desc() + ch <- e.collectCount.Desc() + + e.scrapeDuration.Describe(ch) + e.scrapeErrors.Describe(ch) + e.scrapeLastError.Describe(ch) + e.scrapeCount.Describe(ch) + + e.up.Describe(ch) + + e.keyValues.Describe(ch) + e.keySizes.Describe(ch) +} + +func (e *exporter) Collect(ch chan<- prometheus.Metric) { + e.mutex.Lock() + defer e.mutex.Unlock() + + startTime := time.Now() + defer func() { + e.collectCount.Inc() + e.collectDuration.Observe(time.Since(startTime).Seconds()) + ch <- e.collectCount + ch <- e.collectDuration + }() + + e.keySizes.Reset() + e.keyValues.Reset() + + e.scrape(ch) + + e.scrapeDuration.Collect(ch) + e.scrapeErrors.Collect(ch) + e.scrapeLastError.Collect(ch) + e.scrapeCount.Collect(ch) + + e.up.Collect(ch) + + e.keySizes.Collect(ch) + e.keyValues.Collect(ch) +} + +func (e *exporter) scrape(ch chan<- prometheus.Metric) { + startTime := time.Now() + + fut := newFuture() + for _, instance := range e.dis.GetInstances() { + fut.Add() + go func(addr, password, alias string) { + e.scrapeCount.WithLabelValues(addr, alias).Inc() + defer func() { + e.scrapeDuration.WithLabelValues(addr, alias).Observe(time.Since(startTime).Seconds()) + }() + + c, err := newClient(addr, password, alias) + if err != nil { + e.up.WithLabelValues(addr, alias).Set(0) + + fut.Done(futureKey{addr: addr, alias: alias}, + fmt.Errorf("exporter::scrape new pika client failed. err:%s", err.Error())) + } else { + defer c.Close() + e.up.WithLabelValues(addr, alias).Set(1) + + fut.Add() + fut.Done(futureKey{addr: c.Addr(), alias: c.Alias()}, e.collectInfo(c, ch)) + fut.Done(futureKey{addr: c.Addr(), alias: c.Alias()}, e.collectKeys(c)) + } + }(instance.Addr, instance.Password, instance.Alias) + } + for k, v := range fut.Wait() { + if v != nil { + e.scrapeErrors.WithLabelValues(k.addr, k.alias).Inc() + e.scrapeLastError.WithLabelValues(k.addr, k.alias, v.Error()).Set(0) + + log.Errorf("exporter::scrape collect pika failed. pika server:%#v err:%s", k, v.Error()) + } + } +} + +func (e *exporter) collectInfo(c *client, ch chan<- prometheus.Metric) error { + info, err := c.Info() + if err != nil { + return err + } + + version, extracts, err := parseInfo(info) + if err != nil { + return err + } + extracts[metrics.LabelNameAddr] = c.Addr() + extracts[metrics.LabelNameAlias] = c.Alias() + extracts[metrics.LabelInstanceMode], err = c.InstanceModeInfo() + if err != nil { + return err + } + extracts[metrics.LabelConsensusLevel], err = c.LabelConsensusLevelInfo() + if err != nil { + return err + } + + collector := metrics.CollectFunc(func(m metrics.Metric) error { + promMetric, err := prometheus.NewConstMetric( + prometheus.NewDesc(prometheus.BuildFQName(e.namespace, "", m.Name), m.Help, m.Labels, nil), + m.MetricsType(), m.Value, m.LabelValues...) + if err != nil { + return err + } + + ch <- promMetric + return nil + }) + parseOpt := metrics.ParseOption{ + Version: version, + Extracts: extracts, + Info: info, + } + for _, m := range metrics.MetricConfigs { + m.Parse(m, collector, parseOpt) + } + + return nil +} + +func (e *exporter) collectKeys(c *client) error { + allKeys := append([]dbKeyPair{}, e.keys...) + keys, err := getKeysFromPatterns(c, e.keyPatterns, e.scanCount) + if err != nil { + log.Errorf("get keys from patterns failed. addr:%s err:%s", c.Addr(), err.Error()) + } else { + allKeys = append(allKeys, keys...) + } + + log.Debugf("collectKeys allKeys:%#v", allKeys) + for _, k := range allKeys { + if err := c.Select(k.db); err != nil { + log.Warnf("couldn't select database %s when getting key info. addr:%s", k.db, c.Addr()) + continue + } + + keyInfo, err := c.Type(k.key) + if err != nil { + log.Warnf("get key info failed. addr:%s key:%s err:%s", c.Addr(), k.key, err.Error()) + continue + } + + e.keySizes.WithLabelValues(c.Addr(), c.Alias(), "db"+k.db, k.key, keyInfo.keyType).Set(keyInfo.size) + if value, err := c.Get(k.key); err == nil { + e.keyValues.WithLabelValues(c.Addr(), c.Alias(), "db"+k.db, k.key, value).Set(1) + } + } + + return nil +} + +func getKeysFromPatterns(c *client, keyPatterns []dbKeyPair, scanCount int) ([]dbKeyPair, error) { + var expandedKeys []dbKeyPair + for _, kp := range keyPatterns { + if regexp.MustCompile(`[\?*\[\]\^]+`).MatchString(kp.key) { + if err := c.Select(kp.db); err != nil { + return expandedKeys, err + } + keyNames, err := c.Scan(kp.key, scanCount) + if err != nil { + log.Errorln("get keys from patterns scan failed. pattern:", kp.key) + continue + } + for _, keyName := range keyNames { + expandedKeys = append(expandedKeys, dbKeyPair{db: kp.db, key: keyName}) + } + } else { + expandedKeys = append(expandedKeys, kp) + } + } + return expandedKeys, nil +} + +func (e *exporter) statsKeySpace(hour int) { + defer e.wg.Done() + + if hour < 0 { + log.Infoln("stats KeySpace not open") + return + } + + timer := time.NewTimer(getClockDuration(hour)) + defer timer.Stop() + + for { + select { + case <-e.done: + return + case <-timer.C: + timer.Reset(getClockDuration(hour)) + } + + for _, v := range e.dis.GetInstances() { + c, err := newClient(v.Addr, v.Password, v.Alias) + if err != nil { + log.Warnln("stats KeySpace new pika client failed. err:", err) + continue + } + if _, err := c.InfoKeySpaceOne(); err != nil { + log.Warnln("stats KeySpace execute INFO KEYSPACE 1 failed. err:", err) + } + c.Close() + } + } +} + +func parseKeyArg(keysArgString string) ([]dbKeyPair, error) { + if keysArgString == "" { + return nil, nil + } + + var ( + keys []dbKeyPair + err error + ) + for _, k := range strings.Split(keysArgString, ",") { + db := "0" + key := "" + frags := strings.Split(k, "=") + switch len(frags) { + case 1: + db = "0" + key, err = url.QueryUnescape(strings.TrimSpace(frags[0])) + case 2: + db = strings.Replace(strings.TrimSpace(frags[0]), "db", "", -1) + key, err = url.QueryUnescape(strings.TrimSpace(frags[1])) + default: + return keys, fmt.Errorf("invalid key list argument: %s", k) + } + if err != nil { + return keys, fmt.Errorf("couldn't parse db/key string: %s", k) + } + + keys = append(keys, dbKeyPair{db, key}) + } + return keys, err +} + +func getClockDuration(hour int) time.Duration { + timeNow, timeDst := time.Now(), time.Now() + subHour := hour - timeNow.Hour() + if subHour <= 0 { + timeDst = timeNow.AddDate(0, 0, 1).Add(time.Duration(subHour) * time.Hour).Truncate(time.Hour) + } else { + timeDst = timeNow.Add(time.Duration(subHour) * time.Hour).Truncate(time.Hour) + } + + return timeDst.Sub(timeNow) +} diff --git a/pika-tools/pika_exporter/exporter/pika_test.go b/pika-tools/pika_exporter/exporter/pika_test.go new file mode 100644 index 0000000000..2d48129ba0 --- /dev/null +++ b/pika-tools/pika_exporter/exporter/pika_test.go @@ -0,0 +1,25 @@ +package exporter + +import ( + "github.com/OpenAtomFoundation/pika/pika-tools/pika_exporter/discovery" + "github.com/prometheus/client_golang/prometheus" + "github.com/stretchr/testify/assert" + "testing" +) + +type fakeDiscovery struct { +} + +func (d *fakeDiscovery) GetInstances() []discovery.Instance { + return nil +} + +func TestExporter_Describe(t *testing.T) { + assert := assert.New(t) + + e, err := NewPikaExporter(&fakeDiscovery{}, "pika", "", "", 100, 0) + assert.NoError(err) + defer e.Close() + + assert.NoError(prometheus.Register(e)) +} diff --git a/pika-tools/pika_exporter/exporter/test/test.go b/pika-tools/pika_exporter/exporter/test/test.go new file mode 100644 index 0000000000..a9a4f9a502 --- /dev/null +++ b/pika-tools/pika_exporter/exporter/test/test.go @@ -0,0 +1,35 @@ +package test + +var InfoCases = []struct { + Name string + Info string +}{ + {"v3.4.2_master", V342MasterInfo}, + {"v3.4.2_slave", V342SlaveInfo}, + + // {"v2.2.3.3_master", V2233MasterInfo}, + // {"v2.2.3.3_slave", V2233SlaveInfo}, + + // {"v2.2.6_master", V226MasterInfo}, + // {"v2.2.6_slave", V226SlaveInfo}, + + // {"v2.3.6_master", V236MasterInfo}, + // {"v2.3.6_slave", V236SlaveInfo}, + + // {"v3.0.10_master", V3010MasterInfo}, + // {"v3.0.10_slave", V3010SlaveInfo}, + + // {"v3.0.16_master", V3016MasterInfo}, + // {"v3.0.16_slave", V3016SlaveInfo}, + + // {"v3.1.0_master", V310MasterInfo}, + // {"v3.1.0_slave", V310SlaveInfo}, + + // {"v3.2.0_master", V320MasterInfo}, + // {"v3.2.0_slave", V320SlaveInfo}, + + // {"v3.2.7_slave", V327SlaveInfo}, + + // {"v3.3.5_master", V335MasterInfo}, + // {"v3.3.5_slave", V335SlaveInfo}, +} diff --git a/pika-tools/pika_exporter/exporter/test/v3.3.5_master.go b/pika-tools/pika_exporter/exporter/test/v3.3.5_master.go new file mode 100644 index 0000000000..21a1c4bd1d --- /dev/null +++ b/pika-tools/pika_exporter/exporter/test/v3.3.5_master.go @@ -0,0 +1,91 @@ +package test + +var V335MasterInfo = `# Server +pika_version:3.3.5 +pika_git_sha:16283243d4d8e87668549d632d6cd13c8ac94016 +pika_build_compile_date: Jul 7 2020 +os:Linux 3.10.0-862.el7.x86_64 x86_64 +arch_bits:64 +process_id:312168 +tcp_port:9223 +thread_num:24 +sync_thread_num:6 +uptime_in_seconds:83481 +uptime_in_days:2 +config_file:/redis/pika-v3.3.5/multi/9223/conf/9223.conf +server_id:1 + +# Data +db_size:1558037767 +db_size_human:1485M +log_size:10393611442 +log_size_human:9912M +compression:snappy +used_memory:634104203 +used_memory_human:604M +db_memtable_usage:469733952 +db_tablereader_usage:164370251 +db_fatal:0 +db_fatal_msg:NULL + +# Clients +connected_clients:5 + +# Stats +total_connections_received:2131 +instantaneous_ops_per_sec:3233 +total_commands_processed:295232194 +is_bgsaving:No +is_scaning_keyspace:No +is_compact:No +compact_cron: +compact_interval: + +# Command_Exec_Count +RPUSH:5111302 +MSET:5011300 +CLIENT:1 +LPUSH:10176174 +SUBSCRIBE:794 +LPOP:5111300 +INFO:24980 +SPOP:5111300 +ZADD:2 +SELECT:4 +SLAVEOF:2 +PING:10462381 +AUTH:2103 +HSET:5111300 +GET:105131100 +SET:106399878 +MONITOR:4 +CONFIG:3 +LRANGE:20044400 +BGSAVE:1 +HMSET:2 +SADD:5111300 +INCR:5111300 +RPOP:5111300 +PUBLISH:122339 + +# CPU +used_cpu_sys:40341.43 +used_cpu_user:23306.89 +used_cpu_sys_children:0.00 +used_cpu_user_children:0.00 + +# Replication(MASTER) +role:master +connected_slaves:2 +slave0:ip=10.200.14.148,port=9222,conn_fd=131,lag=(db0:0) +slave1:ip=10.200.14.148,port=9221,conn_fd=135,lag=(db0:0) +db0 binlog_offset=143 9122210,safety_purge=write2file133 + +# Keyspace +# Time:2020-07-23 14:26:33 +# Duration: 15s +db0 Strings_keys=83922112, expires=0, invalid_keys=0 +db0 Hashes_keys=4887344, expires=0, invalid_keys=0 +db0 Lists_keys=1, expires=0, invalid_keys=0 +db0 Zsets_keys=1, expires=0, invalid_keys=0 +db0 Sets_keys=0, expires=0, invalid_keys=1` \ No newline at end of file diff --git a/pika-tools/pika_exporter/exporter/test/v3.3.5_slave.go b/pika-tools/pika_exporter/exporter/test/v3.3.5_slave.go new file mode 100644 index 0000000000..987ccb4c00 --- /dev/null +++ b/pika-tools/pika_exporter/exporter/test/v3.3.5_slave.go @@ -0,0 +1,92 @@ +package test + +var V335SlaveInfo = `# Server +pika_version:3.3.5 +pika_git_sha:16283243d4d8e87668549d632d6cd13c8ac94016 +pika_build_compile_date: Jul 7 2020 +os:Linux 3.10.0-862.el7.x86_64 x86_64 +arch_bits:64 +process_id:315022 +tcp_port:9221 +thread_num:24 +sync_thread_num:6 +uptime_in_seconds:1359 +uptime_in_days:1 +config_file:/redis/pika-v3.3.5/multi/9221/conf/9221.conf +server_id:1 + +# Data +db_size:8884577 +db_size_human:8M +log_size:87471185 +log_size_human:83M +compression:snappy +used_memory:1464237 +used_memory_human:1M +db_memtable_usage:8000 +db_tablereader_usage:1456237 +db_fatal:0 +db_fatal_msg:NULL + +# Clients +connected_clients:5 + +# Stats +total_connections_received:421 +instantaneous_ops_per_sec:4 +total_commands_processed:7172 +is_bgsaving:No +is_scaning_keyspace:No +is_compact:No +compact_cron: +compact_interval: + +# Command_Exec_Count +RPUSH:5111302 +MSET:5011300 +CLIENT:1 +LPUSH:10176174 +SUBSCRIBE:794 +LPOP:5111300 +INFO:24980 +SPOP:5111300 +ZADD:2 +SELECT:4 +SLAVEOF:2 +PING:10462381 +AUTH:2103 +HSET:5111300 +GET:105131100 +SET:106399878 +MONITOR:4 +CONFIG:3 +LRANGE:20044400 +BGSAVE:1 +HMSET:2 +SADD:5111300 +INCR:5111300 +RPOP:5111300 +PUBLISH:122339 + +# CPU +used_cpu_sys:4.40 +used_cpu_user:4.85 +used_cpu_sys_children:0.00 +used_cpu_user_children:0.00 + +# Replication(SLAVE) +role:slave +master_host:10.200.14.148 +master_port:9223 +master_link_status:up +slave_priority:100 +slave_read_only:1 +db0 binlog_offset=0 87377376,safety_purge=none + +# Keyspace +# Time:1970-01-01 08:00:00 +db0 Strings_keys=1000, expires=0, invalid_keys=0 +db0 Hashes_keys=0, expires=0, invalid_keys=0 +db0 Lists_keys=0, expires=0, invalid_keys=0 +db0 Zsets_keys=0, expires=100, invalid_keys=0 +db0 Sets_keys=0, expires=0, invalid_keys=0` \ No newline at end of file diff --git a/pika-tools/pika_exporter/exporter/test/v3.4.2_master.go b/pika-tools/pika_exporter/exporter/test/v3.4.2_master.go new file mode 100644 index 0000000000..d6a6c8a1b4 --- /dev/null +++ b/pika-tools/pika_exporter/exporter/test/v3.4.2_master.go @@ -0,0 +1,75 @@ +package test + +var V342MasterInfo = `# Server +pika_version:3.4.0 +pika_git_sha:bd30511bf82038c2c6531b3d84872c9825fe836a +pika_build_compile_date: Sep 8 2021 +os:Linux 3.10.0-693.el7.x86_64 x86_64 +arch_bits:64 +process_id:12549 +tcp_port:9221 +thread_num:4 +sync_thread_num:6 +uptime_in_seconds:8056286 +uptime_in_days:94 +config_file:/app/pika/pika-9221.conf +server_id:1 + +# Data +db_size:41971885221 +db_size_human:40027M +log_size:5150573069 +log_size_human:4911M +compression:snappy +used_memory:1445394489 +used_memory_human:1378M +db_memtable_usage:42493512 +db_tablereader_usage:1402900977 +db_fatal:0 +db_fatal_msg:NULL + +# Clients +connected_clients:7 + +# Stats +total_connections_received:496042 +instantaneous_ops_per_sec:106 +total_commands_processed:11590807682 +is_bgsaving:No +is_scaning_keyspace:No +is_compact:No +compact_cron:03-04/30 +compact_interval: + +# Command_Exec_Count +INFO:464159 +DEL:27429572 +PING:2033416 +EXPIRE:3717952643 +GET:3807086732 +SET:4035576044 +HGETALL:1 +CONFIG:132516 +SLOWLOG:132599 + +# CPU +used_cpu_sys:226152.34 +used_cpu_user:842762.56 +used_cpu_sys_children:0.00 +used_cpu_user_children:0.00 + +# Replication(MASTER) +role:master +connected_slaves:1 +slave0:ip=192.168.201.82,port=9221,conn_fd=88,lag=(db0:0) +db0 binlog_offset=17794 8127680,safety_purge=write2file17784 +consensus last_log=11111111111 + +# Keyspace +# Time:2023-04-14 01:16:01 +# Duration: 41s +db0 Strings_keys=40523556, expires=33332598, invalid_keys=0 +db0 Hashes_keys=0, expires=0, invalid_keys=0 +db0 Lists_keys=0, expires=0, invalid_keys=0 +db0 Zsets_keys=0, expires=0, invalid_keys=0 +db0 Sets_keys=0, expires=0, invalid_keys=0` diff --git a/pika-tools/pika_exporter/exporter/test/v3.4.2_slave.go b/pika-tools/pika_exporter/exporter/test/v3.4.2_slave.go new file mode 100644 index 0000000000..dd51a06dfd --- /dev/null +++ b/pika-tools/pika_exporter/exporter/test/v3.4.2_slave.go @@ -0,0 +1,77 @@ +package test + +var V342SlaveInfo = `# Server +pika_version:3.4.0 +pika_git_sha:bd30511bf82038c2c6531b3d84872c9825fe836a +pika_build_compile_date: Sep 8 2021 +os:Linux 3.10.0-693.el7.x86_64 x86_64 +arch_bits:64 +process_id:138825 +tcp_port:9221 +thread_num:4 +sync_thread_num:6 +uptime_in_seconds:8056021 +uptime_in_days:94 +config_file:/app/pika/pika.conf +server_id:1 + +# Data +db_size:41977897912 +db_size_human:40033M +log_size:5150607654 +log_size_human:4912M +compression:snappy +used_memory:1421201619 +used_memory_human:1355M +db_memtable_usage:17944432 +db_tablereader_usage:1403257187 +db_fatal:0 +db_fatal_msg:NULL + +# Clients +connected_clients:1 + +# Stats +total_connections_received:331470 +instantaneous_ops_per_sec:0 +total_commands_processed:7781820120 +is_bgsaving:No +is_scaning_keyspace:No +is_compact:No +compact_cron:03-04/30 +compact_interval: + +# Command_Exec_Count +EXPIREAT:3717952643 +INFO:464149 +DEL:27429572 +SLAVEOF:1 +PING:132598 +SET:4035576044 +CONFIG:132514 +COMPACT:1 +SLOWLOG:132598 + +# CPU +used_cpu_sys:120451.99 +used_cpu_user:644919.06 +used_cpu_sys_children:0.00 +used_cpu_user_children:0.00 + +# Replication(SLAVE) +role:slave +master_host:192.168.201.81 +master_port:9221 +master_link_status:up +slave_priority:100 +slave_read_only:1 +db0 binlog_offset=17794 8127680,safety_purge=write2file17784 + +# Keyspace +# Time:2023-04-14 01:16:01 +# Duration: 37s +db0 Strings_keys=40523556, expires=33332458, invalid_keys=0 +db0 Hashes_keys=0, expires=0, invalid_keys=0 +db0 Lists_keys=0, expires=0, invalid_keys=0 +db0 Zsets_keys=0, expires=0, invalid_keys=0 +db0 Sets_keys=0, expires=0, invalid_keys=0` diff --git a/pika-tools/pika_exporter/go.mod b/pika-tools/pika_exporter/go.mod new file mode 100644 index 0000000000..a53c9c0ae1 --- /dev/null +++ b/pika-tools/pika_exporter/go.mod @@ -0,0 +1,28 @@ +module github.com/OpenAtomFoundation/pika/pika-tools/pika_exporter + +go 1.19 + +require ( + github.com/Masterminds/semver v1.5.0 + github.com/garyburd/redigo v1.6.4 + github.com/prometheus/client_golang v1.15.0 + github.com/sirupsen/logrus v1.9.0 + github.com/stretchr/testify v1.8.2 +) + +require ( + github.com/beorn7/perks v1.0.1 // indirect + github.com/cespare/xxhash/v2 v2.2.0 // indirect + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/golang/protobuf v1.5.3 // indirect + github.com/kr/text v0.2.0 // indirect + github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/prometheus/client_model v0.3.0 // indirect + github.com/prometheus/common v0.42.0 // indirect + github.com/prometheus/procfs v0.9.0 // indirect + github.com/rogpeppe/go-internal v1.10.0 // indirect + golang.org/x/sys v0.6.0 // indirect + google.golang.org/protobuf v1.30.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect +) diff --git a/pika-tools/pika_exporter/go.sum b/pika-tools/pika_exporter/go.sum new file mode 100644 index 0000000000..2893043e01 --- /dev/null +++ b/pika-tools/pika_exporter/go.sum @@ -0,0 +1,60 @@ +github.com/Masterminds/semver v1.5.0 h1:H65muMkzWKEuNDnfl9d70GUjFniHKHRbFPGBuZ3QEww= +github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y= +github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= +github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/garyburd/redigo v1.6.4 h1:LFu2R3+ZOPgSMWMOL+saa/zXRjw0ID2G8FepO53BGlg= +github.com/garyburd/redigo v1.6.4/go.mod h1:rTb6epsqigu3kYKBnaF028A7Tf/Aw5s0cqA47doKKqw= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= +github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= +github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/prometheus/client_golang v1.15.0 h1:5fCgGYogn0hFdhyhLbw7hEsWxufKtY9klyvdNfFlFhM= +github.com/prometheus/client_golang v1.15.0/go.mod h1:e9yaBhRPU2pPNsZwE+JdQl0KEt1N9XgF6zxWmaC0xOk= +github.com/prometheus/client_model v0.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4= +github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w= +github.com/prometheus/common v0.42.0 h1:EKsfXEYo4JpWMHH5cg+KOUWeuJSov1Id8zGR8eeI1YM= +github.com/prometheus/common v0.42.0/go.mod h1:xBwqVerjNdUDjgODMpudtOMwlOwf2SaTr1yjz4b7Zbc= +github.com/prometheus/procfs v0.9.0 h1:wzCHvIvM5SxWqYvwgVL7yJY8Lz3PKn49KQtpgMYJfhI= +github.com/prometheus/procfs v0.9.0/go.mod h1:+pB4zwohETzFnmlpe6yd2lSc+0/46IYZRB/chUwxUZY= +github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= +github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= +github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0= +github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= +github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= +google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/pika-tools/pika_exporter/main.go b/pika-tools/pika_exporter/main.go new file mode 100644 index 0000000000..c6570560a1 --- /dev/null +++ b/pika-tools/pika_exporter/main.go @@ -0,0 +1,113 @@ +package main + +import ( + "flag" + "net/http" + "os" + "strconv" + + "github.com/OpenAtomFoundation/pika/pika-tools/pika_exporter/discovery" + "github.com/OpenAtomFoundation/pika/pika-tools/pika_exporter/exporter" + + "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/client_golang/prometheus/promhttp" + log "github.com/sirupsen/logrus" +) + +var ( + hostFile = flag.String("pika.host-file", getEnv("PIKA_HOST_FILE", ""), "Path to file containing one or more pika nodes, separated by newline. NOTE: mutually exclusive with pika.addr.") + addr = flag.String("pika.addr", getEnv("PIKA_ADDR", ""), "Address of one or more pika nodes, separated by comma.") + password = flag.String("pika.password", getEnv("PIKA_PASSWORD", ""), "Password for one or more pika nodes, separated by comma.") + alias = flag.String("pika.alias", getEnv("PIKA_ALIAS", ""), "Pika instance alias for one or more pika nodes, separated by comma.") + namespace = flag.String("namespace", getEnv("PIKA_EXPORTER_NAMESPACE", "pika"), "Namespace for metrics.") + metricsFile = flag.String("metrics-file", getEnv("PIKA_EXPORTER_METRICS_FILE", ""), "Metrics definition file.") + keySpaceStatsClock = flag.Int("keyspace-stats-clock", getEnvInt("PIKA_EXPORTER_KEYSPACE_STATS_CLOCK", -1), "Stats the number of keys at keyspace-stats-clock o'clock every day, in the range [0, 23].If < 0, not open this feature.") + checkKeyPatterns = flag.String("check.key-patterns", getEnv("PIKA_EXPORTER_CHECK_KEY_PARTTERNS", ""), "Comma separated list of key-patterns to export value and length/size, searched for with SCAN.") + checkKeys = flag.String("check.keys", getEnv("PIKA_EXPORTER_CHECK_KEYS", ""), "Comma separated list of keys to export value and length/size.") + checkScanCount = flag.Int("check.scan-count", getEnvInt("PIKA_EXPORTER_CHECK_SCAN_COUNT", 100), "When check keys and executing SCAN command, scan-count assigned to COUNT.") + listenAddress = flag.String("web.listen-address", getEnv("PIKA_EXPORTER_WEB_LISTEN_ADDRESS", ":9121"), "Address to listen on for web interface and telemetry.") + metricPath = flag.String("web.telemetry-path", getEnv("PIKA_EXPORTER_WEB_TELEMETRY_PATH", "/metrics"), "Path under which to expose metrics.") + logLevel = flag.String("log.level", getEnv("PIKA_EXPORTER_LOG_LEVEL", "info"), "Log level, valid options: panic fatal error warn warning info debug.") + logFormat = flag.String("log.format", getEnv("PIKA_EXPORTER_LOG_FORMAT", "json"), "Log format, valid options: txt and json.") + showVersion = flag.Bool("version", false, "Show version information and exit.") +) + +func getEnv(key string, defaultVal string) string { + if envVal, ok := os.LookupEnv(key); ok { + return envVal + } + return defaultVal +} + +func getEnvInt(key string, defaultVal int) int { + if envVal, ok := os.LookupEnv(key); ok { + if v, err := strconv.Atoi(envVal); err == nil { + return v + } + } + return defaultVal +} + +func main() { + flag.Parse() + + log.Println("Pika Metrics Exporter ", BuildVersion, "build date:", BuildDate, "sha:", BuildCommitSha, "go version:", GoVersion) + if *showVersion { + return + } + + level, err := log.ParseLevel(*logLevel) + if err != nil { + log.Fatalln("parse log.level failed, err:", err) + } + log.SetLevel(level) + switch *logFormat { + case "json": + log.SetFormatter(&log.JSONFormatter{}) + default: + log.SetFormatter(&log.TextFormatter{}) + } + + var dis discovery.Discovery + if *hostFile != "" { + dis, err = discovery.NewFileDiscovery(*hostFile) + } else { + dis, err = discovery.NewCmdArgsDiscovery(*addr, *password, *alias) + } + if err != nil { + log.Fatalln(" failed. err:", err) + } + + e, err := exporter.NewPikaExporter(dis, *namespace, *checkKeyPatterns, *checkKeys, *checkScanCount, *keySpaceStatsClock) + if err != nil { + log.Fatalln("exporter init failed. err:", err) + } + defer e.Close() + + buildInfo := prometheus.NewGaugeVec(prometheus.GaugeOpts{ + Name: "pika_exporter_build_info", + Help: "pika exporter build_info", + }, []string{"build_version", "commit_sha", "build_date", "golang_version"}) + buildInfo.WithLabelValues(BuildVersion, BuildCommitSha, BuildDate, GoVersion).Set(1) + + registry := prometheus.NewRegistry() + registry.MustRegister(e) + registry.MustRegister(buildInfo) + + http.Handle(*metricPath, promhttp.HandlerFor(registry, promhttp.HandlerOpts{})) + http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { + w.Write([]byte(` +Pika Exporter v` + BuildVersion + ` + +

Pika Exporter ` + BuildVersion + `

+

Metrics

+ +`)) + }) + + log.Printf("Providing metrics on %s%s", *listenAddress, *metricPath) + for _, instance := range dis.GetInstances() { + log.Println("Connecting to Pika:", instance.Addr, "Alias:", instance.Alias) + } + log.Fatal(http.ListenAndServe(*listenAddress, nil)) +} diff --git a/pika-tools/pika_exporter/version.go b/pika-tools/pika_exporter/version.go new file mode 100644 index 0000000000..8deff1ced6 --- /dev/null +++ b/pika-tools/pika_exporter/version.go @@ -0,0 +1,8 @@ +package main + +const ( + BuildVersion = "Filled in by build" + BuildCommitSha = "Filled in by build" + BuildDate = "Filled in by build" + GoVersion = "Filled in by build" +)