diff --git a/docs/ENV_VARIABLES.md b/docs/ENV_VARIABLES.md index 64903fcc7e..198d4b1f54 100644 --- a/docs/ENV_VARIABLES.md +++ b/docs/ENV_VARIABLES.md @@ -16,12 +16,10 @@ Some variables influence multiple components. Command line parameters override e - **PW3_PGPASSWORD** Config DB password. Default: pgwatch3admin - **PW3_PGSSL** Config DB SSL connection only. Default: False - **PW3_GROUP** Logical grouping/sharding key to monitor a subset of configured hosts. Default: - -- **PW3_DATASTORE** Backend for metric storage - [postgres|prometheus|graphite|json]. Default: postgres +- **PW3_DATASTORE** Backend for metric storage - [postgres|prometheus|json]. Default: postgres - **PW3_VERBOSE** Logging vebosity. By default warning and errors are logged. Use [-v|-vv] to include [info|debug]. Default: - - **PW3_PG_METRIC_STORE_CONN_STR** Postgres metric store connection string. Required when PW3_DATASTORE=postgres. Default: - - **PW3_PG_RETENTION_DAYS** Effective when PW3_DATASTORE=postgres. Default: 14 -- **PW3_GRAPHITEHOST** Graphite host. Default: - -- **PW3_GRAPHITEPORT** Graphite port. Default: - - **PW3_CONFIG** File mode. File or folder of YAML (.yaml/.yml) files containing info on which DBs to monitor and where to store metrics - **PW3_METRICS_FOLDER** File mode. Folder of metrics definitions - **PW3_BATCHING_MAX_DELAY_MS** Max milliseconds to wait for a batched metrics flush. Default: 250 @@ -78,7 +76,6 @@ Some variables influence multiple components. Command line parameters override e - **PW3_GRAFANA_BASEURL** For linking to Grafana "Query details" dashboard from "Stat_stmt. overview". Default: http://0.0.0.0:3000 - **PW3_AES_GCM_KEYPHRASE** Keyphrase for encryption/decpyption of connect string passwords. - **PW3_AES_GCM_KEYPHRASE_FILE** File containing a keyphrase for encryption/decpyption of connect string passwords. -- **PW3_DATASTORE** Backend for metric storage - [postgres|graphite]. Default: postgres - **PW3_PG_METRIC_STORE_CONN_STR** Postgres metric store connection string. Required when PW3_DATASTORE=postgres. Default: - diff --git a/docs/features.rst b/docs/features.rst index bc6941f3af..417963aa0c 100644 --- a/docs/features.rst +++ b/docs/features.rst @@ -10,7 +10,7 @@ List of main features * Easy extensibility of metrics which are defined in pure SQL, thus they could also be from the business domain -* Many metric data storage options - PostgreSQL, PostgreSQL with the compression enabled TimescaleDB extension, Graphite or Prometheus scraping +* Many metric data storage options - PostgreSQL, PostgreSQL with the compression enabled TimescaleDB extension, or Prometheus scraping * Multiple deployment options - PostgreSQL configuration DB, YAML or ENV configuration, supporting both "push" and "pull" models diff --git a/src/config/cmdparser.go b/src/config/cmdparser.go index 3984643723..d67a226baa 100644 --- a/src/config/cmdparser.go +++ b/src/config/cmdparser.go @@ -24,15 +24,13 @@ type MetricOpts struct { Group string `short:"g" long:"group" mapstructure:"group" description:"Group (or groups, comma separated) for filtering which DBs to monitor. By default all are monitored" env:"PW3_GROUP"` MetricsFolder string `short:"m" long:"metrics-folder" mapstructure:"metrics-folder" description:"Folder of metrics definitions" env:"PW3_METRICS_FOLDER"` NoHelperFunctions bool `long:"no-helper-functions" mapstructure:"no-helper-functions" description:"Ignore metric definitions using helper functions (in form get_smth()) and don't also roll out any helpers automatically" env:"PW3_NO_HELPER_FUNCTIONS"` - Datastore string `long:"datastore" mapstructure:"datastore" choice:"postgres" choice:"prometheus" choice:"graphite" choice:"json" default:"postgres" env:"PW3_DATASTORE"` + Datastore string `long:"datastore" mapstructure:"datastore" choice:"postgres" choice:"prometheus" choice:"json" default:"postgres" env:"PW3_DATASTORE"` PGMetricStoreConnStr string `long:"pg-metric-store-conn-str" mapstructure:"pg-metric-store-conn-str" description:"PG Metric Store" env:"PW3_PG_METRIC_STORE_CONN_STR"` PGRetentionDays int64 `long:"pg-retention-days" mapstructure:"pg-retention-days" description:"If set, metrics older than that will be deleted" default:"14" env:"PW3_PG_RETENTION_DAYS"` PrometheusPort int64 `long:"prometheus-port" mapstructure:"prometheus-port" description:"Prometheus port. Effective with --datastore=prometheus" default:"9187" env:"PW3_PROMETHEUS_PORT"` PrometheusListenAddr string `long:"prometheus-listen-addr" mapstructure:"prometheus-listen-addr" description:"Network interface to listen on" default:"0.0.0.0" env:"PW3_PROMETHEUS_LISTEN_ADDR"` PrometheusNamespace string `long:"prometheus-namespace" mapstructure:"prometheus-namespace" description:"Prefix for all non-process (thus Postgres) metrics" default:"pgwatch3" env:"PW3_PROMETHEUS_NAMESPACE"` PrometheusAsyncMode bool `long:"prometheus-async-mode" mapstructure:"prometheus-async-mode" description:"Gather in background as with other storage and cache last fetch results in memory" env:"PW3_PROMETHEUS_ASYNC_MODE"` - GraphiteHost string `long:"graphite-host" mapstructure:"graphite-host" description:"Graphite host" env:"PW3_GRAPHITEHOST"` - GraphitePort string `long:"graphite-port" mapstructure:"graphite-port" description:"Graphite port" env:"PW3_GRAPHITEPORT"` JSONStorageFile string `long:"json-storage-file" mapstructure:"json-storage-file" description:"Path to file where metrics will be stored when --datastore=json, one metric set per line" env:"PW3_JSON_STORAGE_FILE"` } @@ -63,24 +61,23 @@ type WebUIOpts struct { } type CmdOptions struct { - Connection ConnectionOpts `group:"Connection" mapstructure:"Connection"` - Metric MetricOpts `group:"Metric" mapstructure:"Metric"` - Logging LoggingOpts `group:"Logging" mapstructure:"Logging"` - WebUI WebUIOpts `group:"WebUI" mapstructure:"WebUI"` - Start StartOpts `group:"Start" mapstructure:"Start"` - // Params for running based on local config files, enabled distributed "push model" based metrics gathering. Metrics are sent directly to Influx/Graphite. - Config string `short:"c" long:"config" mapstructure:"config" description:"File or folder of YAML files containing info on which DBs to monitor and where to store metrics" env:"PW3_CONFIG"` - BatchingDelayMs int64 `long:"batching-delay-ms" mapstructure:"batching-delay-ms" description:"Max milliseconds to wait for a batched metrics flush. [Default: 250]" default:"250" env:"PW3_BATCHING_MAX_DELAY_MS"` - AdHocConnString string `long:"adhoc-conn-str" mapstructure:"adhoc-conn-str" description:"Ad-hoc mode: monitor a single Postgres DB specified by a standard Libpq connection string" env:"PW3_ADHOC_CONN_STR"` - AdHocDBType string `long:"adhoc-dbtype" mapstructure:"adhoc-dbtype" description:"Ad-hoc mode: postgres|postgres-continuous-discovery" default:"postgres" env:"PW3_ADHOC_DBTYPE"` - AdHocConfig string `long:"adhoc-config" mapstructure:"adhoc-config" description:"Ad-hoc mode: a preset config name or a custom JSON config" env:"PW3_ADHOC_CONFIG"` - AdHocCreateHelpers bool `long:"adhoc-create-helpers" mapstructure:"adhoc-create-helpers" description:"Ad-hoc mode: try to auto-create helpers. Needs superuser to succeed" env:"PW3_ADHOC_CREATE_HELPERS"` - AdHocUniqueName string `long:"adhoc-name" mapstructure:"adhoc-name" description:"Ad-hoc mode: Unique 'dbname' for Influx" default:"adhoc" env:"PW3_ADHOC_NAME"` - DirectOSStats bool `long:"direct-os-stats" mapstructure:"direct-os-stats" description:"Extract OS related psutil statistics not via PL/Python wrappers but directly on host" env:"PW3_DIRECT_OS_STATS"` - UseConnPooling bool `long:"use-conn-pooling" mapstructure:"use-conn-pooling" description:"Enable re-use of metrics fetching connections" env:"PW3_USE_CONN_POOLING"` - AesGcmKeyphrase string `long:"aes-gcm-keyphrase" mapstructure:"aes-gcm-keyphrase" description:"Decryption key for AES-GCM-256 passwords" env:"PW3_AES_GCM_KEYPHRASE"` - AesGcmKeyphraseFile string `long:"aes-gcm-keyphrase-file" mapstructure:"aes-gcm-keyphrase-file" description:"File with decryption key for AES-GCM-256 passwords" env:"PW3_AES_GCM_KEYPHRASE_FILE"` - AesGcmPasswordToEncrypt string `long:"aes-gcm-password-to-encrypt" mapstructure:"aes-gcm-password-to-encrypt" description:"A special mode, returns the encrypted plain-text string and quits. Keyphrase(file) must be set. Useful for YAML mode" env:"PW3_AES_GCM_PASSWORD_TO_ENCRYPT"` + Connection ConnectionOpts `group:"Connection" mapstructure:"Connection"` + Metric MetricOpts `group:"Metric" mapstructure:"Metric"` + Logging LoggingOpts `group:"Logging" mapstructure:"Logging"` + WebUI WebUIOpts `group:"WebUI" mapstructure:"WebUI"` + Start StartOpts `group:"Start" mapstructure:"Start"` + Config string `short:"c" long:"config" mapstructure:"config" description:"File or folder of YAML files containing info on which DBs to monitor and where to store metrics" env:"PW3_CONFIG"` + BatchingDelayMs int64 `long:"batching-delay-ms" mapstructure:"batching-delay-ms" description:"Max milliseconds to wait for a batched metrics flush. [Default: 250]" default:"250" env:"PW3_BATCHING_MAX_DELAY_MS"` + AdHocConnString string `long:"adhoc-conn-str" mapstructure:"adhoc-conn-str" description:"Ad-hoc mode: monitor a single Postgres DB specified by a standard Libpq connection string" env:"PW3_ADHOC_CONN_STR"` + AdHocDBType string `long:"adhoc-dbtype" mapstructure:"adhoc-dbtype" description:"Ad-hoc mode: postgres|postgres-continuous-discovery" default:"postgres" env:"PW3_ADHOC_DBTYPE"` + AdHocConfig string `long:"adhoc-config" mapstructure:"adhoc-config" description:"Ad-hoc mode: a preset config name or a custom JSON config" env:"PW3_ADHOC_CONFIG"` + AdHocCreateHelpers bool `long:"adhoc-create-helpers" mapstructure:"adhoc-create-helpers" description:"Ad-hoc mode: try to auto-create helpers. Needs superuser to succeed" env:"PW3_ADHOC_CREATE_HELPERS"` + AdHocUniqueName string `long:"adhoc-name" mapstructure:"adhoc-name" description:"Ad-hoc mode: Unique 'dbname' for Influx" default:"adhoc" env:"PW3_ADHOC_NAME"` + DirectOSStats bool `long:"direct-os-stats" mapstructure:"direct-os-stats" description:"Extract OS related psutil statistics not via PL/Python wrappers but directly on host" env:"PW3_DIRECT_OS_STATS"` + UseConnPooling bool `long:"use-conn-pooling" mapstructure:"use-conn-pooling" description:"Enable re-use of metrics fetching connections" env:"PW3_USE_CONN_POOLING"` + AesGcmKeyphrase string `long:"aes-gcm-keyphrase" mapstructure:"aes-gcm-keyphrase" description:"Decryption key for AES-GCM-256 passwords" env:"PW3_AES_GCM_KEYPHRASE"` + AesGcmKeyphraseFile string `long:"aes-gcm-keyphrase-file" mapstructure:"aes-gcm-keyphrase-file" description:"File with decryption key for AES-GCM-256 passwords" env:"PW3_AES_GCM_KEYPHRASE_FILE"` + AesGcmPasswordToEncrypt string `long:"aes-gcm-password-to-encrypt" mapstructure:"aes-gcm-password-to-encrypt" description:"A special mode, returns the encrypted plain-text string and quits. Keyphrase(file) must be set. Useful for YAML mode" env:"PW3_AES_GCM_PASSWORD_TO_ENCRYPT"` // "Test data" mode needs to be combined with "ad-hoc" mode to get an initial set of metrics from a real source TestdataMultiplier int `long:"testdata-multiplier" mapstructure:"testdata-multiplier" description:"For how many hosts to generate data" env:"PW3_TESTDATA_MULTIPLIER"` TestdataDays int `long:"testdata-days" mapstructure:"testdata-days" description:"For how many days to generate data" env:"PW3_TESTDATA_DAYS"` diff --git a/src/go.mod b/src/go.mod index 232cdd5eb5..ac1d6c1f13 100644 --- a/src/go.mod +++ b/src/go.mod @@ -9,7 +9,6 @@ require ( github.com/hashicorp/consul/api v1.24.0 github.com/jackc/pgx/v5 v5.4.3 github.com/jessevdk/go-flags v1.5.0 - github.com/marpaia/graphite-golang v0.0.0-20190519024811-caf161d2c2b1 github.com/prometheus/client_golang v1.16.0 github.com/rifflock/lfshook v0.0.0-20180920164130-b9218ef580f5 github.com/samuel/go-zookeeper v0.0.0-20201211165307-7117e9ea2414 diff --git a/src/go.sum b/src/go.sum index 42f18323df..a5d3dd1118 100644 --- a/src/go.sum +++ b/src/go.sum @@ -50,6 +50,7 @@ github.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+ github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8= +github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= @@ -90,6 +91,7 @@ github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYF github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs= github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw= github.com/frankban/quicktest v1.14.4 h1:g2rn0vABPOOXmZUj+vbmUp0lPoXEMuhTpIluN0XL9UY= +github.com/frankban/quicktest v1.14.4/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= @@ -139,6 +141,7 @@ github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiu github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.1 h1:gK4Kx5IaGY9CD5sPJ36FHiBJ6ZXl0kilRiiCj+jdYp4= +github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= @@ -176,8 +179,10 @@ github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/ad github.com/hashicorp/consul/api v1.24.0 h1:u2XyStA2j0jnCiVUU7Qyrt8idjRn4ORhK6DlvZ3bWhA= github.com/hashicorp/consul/api v1.24.0/go.mod h1:NZJGRFYruc/80wYowkPFCp1LbGmJC9L8izrwfyVx/Wg= github.com/hashicorp/consul/sdk v0.14.1 h1:ZiwE2bKb+zro68sWzZ1SgHF3kRMBZ94TwOCFRF4ylPs= +github.com/hashicorp/consul/sdk v0.14.1/go.mod h1:vFt03juSzocLRFo59NkeQHHmQa6+g7oU0pfzdI1mUhg= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= +github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= @@ -188,19 +193,24 @@ github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJ github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= github.com/hashicorp/go-msgpack v0.5.5 h1:i9R9JSrqIz0QVLz3sz+i3YJdT7TTSLcfLLzJi9aZTuI= +github.com/hashicorp/go-msgpack v0.5.5/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA= github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= github.com/hashicorp/go-rootcerts v1.0.2 h1:jzhAVGtqPKbwpyCPELlgNWhE1znq+qwJtW5Oi2viEzc= github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc= +github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A= github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= +github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-version v1.2.1 h1:zEfKbn2+PDgroKdiOzqiE8rsmLqU2uwi5PB5pBJ3TkI= +github.com/hashicorp/go-version v1.2.1/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= @@ -237,16 +247,16 @@ github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= github.com/lufia/plan9stats v0.0.0-20230326075908-cb1d2100619a h1:N9zuLhTvBSRt0gWSiJswwQ2HqDmtX/ZCDJURnKUt1Ik= github.com/lufia/plan9stats v0.0.0-20230326075908-cb1d2100619a/go.mod h1:JKx41uQRwqlTZabZc+kILPrO/3jlKnQ2Z8b7YiVw5cE= github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= -github.com/marpaia/graphite-golang v0.0.0-20190519024811-caf161d2c2b1 h1:lODGHy+2Namopi4v7AeiqW106eo4QMXqj9aE8jVXcO4= -github.com/marpaia/graphite-golang v0.0.0-20190519024811-caf161d2c2b1/go.mod h1:llZw8JbFm5CvdRrtgdjaQNlZR1bQhAWsBKtb0HTX+sw= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= @@ -321,6 +331,7 @@ github.com/rifflock/lfshook v0.0.0-20180920164130-b9218ef580f5 h1:mZHayPoR0lNmnH github.com/rifflock/lfshook v0.0.0-20180920164130-b9218ef580f5/go.mod h1:GEXHk5HgEKCvEIIrSpFI3ozzG5xOKA2DVlEX/gGnewM= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= 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/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/samuel/go-zookeeper v0.0.0-20201211165307-7117e9ea2414 h1:AJNDS0kP60X8wwWFvbLPwDuojxubj9pbfK7pjHw0vKg= github.com/samuel/go-zookeeper v0.0.0-20201211165307-7117e9ea2414/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E= @@ -394,6 +405,7 @@ go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE= go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI= +go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60= @@ -734,6 +746,7 @@ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8 gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= diff --git a/src/main.go b/src/main.go index 0c2515c1f6..8fc7df0e98 100644 --- a/src/main.go +++ b/src/main.go @@ -38,8 +38,6 @@ import ( "github.com/shopspring/decimal" "github.com/coreos/go-systemd/daemon" - "github.com/marpaia/graphite-golang" - "golang.org/x/crypto/pbkdf2" "gopkg.in/yaml.v2" ) @@ -69,7 +67,7 @@ type MonitoredDatabase struct { PresetMetricsStandby string `yaml:"preset_metrics_standby"` IsSuperuser bool `yaml:"is_superuser"` IsEnabled bool `yaml:"is_enabled"` - CustomTags map[string]string `yaml:"custom_tags"` // ignored on graphite + CustomTags map[string]string `yaml:"custom_tags"` HostConfig HostConfigAttrs `yaml:"host_config"` OnlyIfMaster bool `yaml:"only_if_master"` } @@ -201,15 +199,13 @@ type ExtensionInfo struct { const ( epochColumnName string = "epoch_ns" // this column (epoch in nanoseconds) is expected in every metric query tagPrefix string = "tag_" - metricDefinitionRefreshTime int64 = 120 // min time before checking for new/changed metric definitions - graphiteMetricsPrefix string = "pgwatch3" + metricDefinitionRefreshTime int64 = 120 // min time before checking for new/changed metric definitions persistQueueMaxSize = 10000 // storage queue max elements. when reaching the limit, older metrics will be dropped. ) // actual requirements depend a lot of metric type and nr. of obects in schemas, // but 100k should be enough for 24h, assuming 5 hosts monitored with "exhaustive" preset config. this would also require ~2 GB RAM per one Influx host const ( - datastoreGraphite = "graphite" datastoreJSON = "json" datastorePostgres = "postgres" datastorePrometheus = "prometheus" @@ -255,9 +251,6 @@ var dbTypeMap = map[string]bool{config.DbTypePg: true, config.DbTypePgCont: true var dbTypes = []string{config.DbTypePg, config.DbTypePgCont, config.DbTypeBouncer, config.DbTypePatroni, config.DbTypePatroniCont, config.DbTypePatroniNamespaceDiscovery} // used for informational purposes var specialMetrics = map[string]bool{recoMetricName: true, specialMetricChangeEvents: true, specialMetricServerLogEventCounts: true} var directlyFetchableOSMetrics = map[string]bool{metricPsutilCPU: true, metricPsutilDisk: true, metricPsutilDiskIoTotal: true, metricPsutilMem: true, metricCPULoad: true} -var graphiteConnection *graphite.Graphite -var graphiteHost string -var graphitePort int var metricDefinitionMap map[string]map[uint]MetricVersionProperties var metricDefMapLock = sync.RWMutex{} var hostMetricIntervalMap = make(map[string]float64) // [db1_metric] = 30 @@ -501,94 +494,6 @@ func GetMonitoredDatabasesFromConfigDB() ([]MonitoredDatabase, error) { return monitoredDBs, err } -func InitGraphiteConnection(host string, port int) { - var err error - logger.Debug("Connecting to Graphite...") - graphiteConnection, err = graphite.NewGraphite(host, port) - if err != nil { - logger.Fatal("could not connect to Graphite:", err) - } - logger.Debug("OK") -} - -func SendToGraphite(dbname, measurement string, data MetricData) error { - if len(data) == 0 { - logger.Warning("No data passed to SendToGraphite call") - return nil - } - logger.Debugf("Writing %d rows to Graphite", len(data)) - - metricBasePrefix := graphiteMetricsPrefix + "." + measurement + "." + dbname + "." - metrics := make([]graphite.Metric, 0, len(data)*len(data[0])) - - for _, dr := range data { - var epochS int64 - - // we loop over columns the first time just to find the timestamp - for k, v := range dr { - if v == nil || v == "" { - continue // not storing NULLs - } else if k == epochColumnName { - epochS = v.(int64) / 1e9 - break - } - } - - if epochS == 0 { - logger.Warning("No timestamp_ns found, server time will be used. measurement:", measurement) - epochS = time.Now().Unix() - } - - for k, v := range dr { - if v == nil || v == "" { - continue // not storing NULLs - } - if k == epochColumnName { - continue - } - var metric graphite.Metric - - if strings.HasPrefix(k, tagPrefix) { // ignore tags for Graphite - metric.Name = metricBasePrefix + k[4:] - } else { - metric.Name = metricBasePrefix + k - } - switch t := v.(type) { - case int: - metric.Value = fmt.Sprintf("%d", v) - case int32: - metric.Value = fmt.Sprintf("%d", v) - case int64: - metric.Value = fmt.Sprintf("%d", v) - case float64: - metric.Value = fmt.Sprintf("%f", v) - default: - logger.Infof("Invalid (non-numeric) column type ignored: metric %s, column: %v, return type: %T", measurement, k, t) - continue - } - metric.Timestamp = epochS - metrics = append(metrics, metric) - - } - } // dr - - logger.Debug("Sending", len(metrics), "metric points to Graphite...") - t1 := time.Now() - err := graphiteConnection.SendMetrics(metrics) - diff := time.Since(t1) - if err != nil { - atomic.AddUint64(&datastoreWriteFailuresCounter, 1) - logger.Error("could not send metric to Graphite:", err) - } else { - atomic.StoreInt64(&lastSuccessfulDatastoreWriteTimeEpoch, t1.Unix()) - atomic.AddUint64(&datastoreTotalWriteTimeMicroseconds, uint64(diff.Microseconds())) - atomic.AddUint64(&datastoreWriteSuccessCounter, 1) - logger.Debug("Sent in ", diff.Microseconds(), "us") - } - - return err -} - func GetMonitoredDatabaseByUniqueName(name string) (MonitoredDatabase, error) { monitoredDbCacheLock.RLock() defer monitoredDbCacheLock.RUnlock() @@ -621,14 +526,6 @@ func ProcessRetryQueue(dataSource, _, connIdent string, retryQueue *list.List, l if dataSource == datastorePostgres { err = SendToPostgres(msg) - } else if dataSource == datastoreGraphite { - for _, m := range msg { - err = SendToGraphite(m.DBUniqueName, m.MetricName, m.Data) // TODO add baching - if err != nil { - logger.Info("Reconnect to graphite") - InitGraphiteConnection(graphiteHost, graphitePort) - } - } } else { logger.Fatal("Invalid datastore:", dataSource) } @@ -766,13 +663,6 @@ func MetricsPersister(ctx context.Context, dataStore string, storageCh <-chan [] partitionMapMetric = make(map[string]ExistingPartitionInfo) partitionMapMetricDbname = make(map[string]map[string]ExistingPartitionInfo) } - } else if dataStore == datastoreGraphite { - for _, m := range msgArr { - err = SendToGraphite(m.DBUniqueName, m.MetricName, m.Data) // TODO does Graphite library support batching? - if err != nil { - atomic.AddUint64(&datastoreWriteFailuresCounter, 1) - } - } } else if dataStore == datastoreJSON { err = WriteMetricsToJSONFile(msgArr, opts.Metric.JSONStorageFile) } else { @@ -2609,17 +2499,7 @@ func main() { go MetricsBatcher(mainContext, opts.BatchingDelayMs, bufferedPersistCh, persistCh) } - if opts.Metric.Datastore == datastoreGraphite { - if opts.Metric.GraphiteHost == "" || opts.Metric.GraphitePort == "" { - logger.Fatal("--graphite-host/port needed!") - } - port, _ := strconv.ParseInt(opts.Metric.GraphitePort, 10, 32) - graphiteHost = opts.Metric.GraphiteHost - graphitePort = int(port) - InitGraphiteConnection(graphiteHost, graphitePort) - logger.Info("starting GraphitePersister...") - go MetricsPersister(mainContext, datastoreGraphite, persistCh) - } else if opts.Metric.Datastore == datastoreJSON { + if opts.Metric.Datastore == datastoreJSON { if len(opts.Metric.JSONStorageFile) == 0 { logger.Fatal("--datastore=json requires --json-storage-file to be set") }