From 2d357f3e3dae1531e79974b31a046115b2e41aa7 Mon Sep 17 00:00:00 2001 From: Ben Blattberg Date: Tue, 6 May 2025 15:55:37 -0500 Subject: [PATCH 01/10] Add pg_hba checksum metric We want OTel metrics to be as close to parity with the postgres_exporter solution as possible; so this PR adds the initial setup and metric query to get 'ccp_pg_hba_checksum', as well as the util function to mark a pg_hba setting as valid. Issues: [PGO-2395] --- .../generated/postgres_5m_metrics.json | 2 +- internal/collector/postgres_5m_metrics.yaml | 10 +- .../postgrescluster/metrics_setup.sql | 147 ++++++++++++++++++ 3 files changed, 157 insertions(+), 2 deletions(-) diff --git a/internal/collector/generated/postgres_5m_metrics.json b/internal/collector/generated/postgres_5m_metrics.json index a9a3500a02..2dd76b73bd 100644 --- a/internal/collector/generated/postgres_5m_metrics.json +++ b/internal/collector/generated/postgres_5m_metrics.json @@ -1 +1 @@ -[{"metrics":[{"attribute_columns":["dbname"],"description":"Database size in bytes","metric_name":"ccp_database_size_bytes","static_attributes":{"server":"localhost:5432"},"value_column":"bytes"}],"sql":"SELECT datname as dbname , pg_database_size(datname) as bytes FROM pg_catalog.pg_database WHERE datistemplate = false;\n"},{"metrics":[{"description":"Count of sequences that have reached greater than or equal to 75% of their max available numbers.\nFunction monitor.sequence_status() can provide more details if run directly on system.\n","metric_name":"ccp_sequence_exhaustion_count","static_attributes":{"server":"localhost:5432"},"value_column":"count"}],"sql":"SELECT count(*) AS count FROM (\n SELECT CEIL((s.max_value-min_value::NUMERIC+1)/s.increment_by::NUMERIC) AS slots\n , CEIL((COALESCE(s.last_value,s.min_value)-s.min_value::NUMERIC+1)/s.increment_by::NUMERIC) AS used\n FROM pg_catalog.pg_sequences s\n) x WHERE (ROUND(used/slots*100)::int) \u003e 75;\n"},{"metrics":[{"attribute_columns":["dbname"],"description":"Number of times disk blocks were found already in the buffer cache, so that a read was not necessary","metric_name":"ccp_stat_database_blks_hit","static_attributes":{"server":"localhost:5432"},"value_column":"blks_hit"},{"attribute_columns":["dbname"],"description":"Number of disk blocks read in this database","metric_name":"ccp_stat_database_blks_read","static_attributes":{"server":"localhost:5432"},"value_column":"blks_read"},{"attribute_columns":["dbname"],"description":"Number of queries canceled due to conflicts with recovery in this database","metric_name":"ccp_stat_database_conflicts","static_attributes":{"server":"localhost:5432"},"value_column":"conflicts"},{"attribute_columns":["dbname"],"description":"Number of deadlocks detected in this database","metric_name":"ccp_stat_database_deadlocks","static_attributes":{"server":"localhost:5432"},"value_column":"deadlocks"},{"attribute_columns":["dbname"],"description":"Total amount of data written to temporary files by queries in this database","metric_name":"ccp_stat_database_temp_bytes","static_attributes":{"server":"localhost:5432"},"value_column":"temp_bytes"},{"attribute_columns":["dbname"],"description":"Number of rows deleted by queries in this database","metric_name":"ccp_stat_database_temp_files","static_attributes":{"server":"localhost:5432"},"value_column":"temp_files"},{"attribute_columns":["dbname"],"description":"Number of rows deleted by queries in this database","metric_name":"ccp_stat_database_tup_deleted","static_attributes":{"server":"localhost:5432"},"value_column":"tup_deleted"},{"attribute_columns":["dbname"],"description":"Number of rows fetched by queries in this database","metric_name":"ccp_stat_database_tup_fetched","static_attributes":{"server":"localhost:5432"},"value_column":"tup_fetched"},{"attribute_columns":["dbname"],"description":"Number of rows inserted by queries in this database","metric_name":"ccp_stat_database_tup_inserted","static_attributes":{"server":"localhost:5432"},"value_column":"tup_inserted"},{"attribute_columns":["dbname"],"description":"Number of rows returned by queries in this database","metric_name":"ccp_stat_database_tup_returned","static_attributes":{"server":"localhost:5432"},"value_column":"tup_returned"},{"attribute_columns":["dbname"],"description":"Number of rows updated by queries in this database","metric_name":"ccp_stat_database_tup_updated","static_attributes":{"server":"localhost:5432"},"value_column":"tup_updated"},{"attribute_columns":["dbname"],"description":"Number of transactions in this database that have been committed","metric_name":"ccp_stat_database_xact_commit","static_attributes":{"server":"localhost:5432"},"value_column":"xact_commit"},{"attribute_columns":["dbname"],"description":"Number of transactions in this database that have been rolled back","metric_name":"ccp_stat_database_xact_rollback","static_attributes":{"server":"localhost:5432"},"value_column":"xact_rollback"}],"sql":"SELECT s.datname AS dbname , s.xact_commit , s.xact_rollback , s.blks_read , s.blks_hit , s.tup_returned , s.tup_fetched , s.tup_inserted , s.tup_updated , s.tup_deleted , s.conflicts , s.temp_files , s.temp_bytes , s.deadlocks FROM pg_catalog.pg_stat_database s JOIN pg_catalog.pg_database d ON d.datname = s.datname WHERE d.datistemplate = false;\n"}] +[{"metrics":[{"attribute_columns":["dbname"],"description":"Database size in bytes","metric_name":"ccp_database_size_bytes","static_attributes":{"server":"localhost:5432"},"value_column":"bytes"}],"sql":"SELECT datname as dbname , pg_database_size(datname) as bytes FROM pg_catalog.pg_database WHERE datistemplate = false;\n"},{"metrics":[{"description":"Count of sequences that have reached greater than or equal to 75% of their max available numbers.\nFunction monitor.sequence_status() can provide more details if run directly on system.\n","metric_name":"ccp_sequence_exhaustion_count","static_attributes":{"server":"localhost:5432"},"value_column":"count"}],"sql":"SELECT count(*) AS count FROM (\n SELECT CEIL((s.max_value-min_value::NUMERIC+1)/s.increment_by::NUMERIC) AS slots\n , CEIL((COALESCE(s.last_value,s.min_value)-s.min_value::NUMERIC+1)/s.increment_by::NUMERIC) AS used\n FROM pg_catalog.pg_sequences s\n) x WHERE (ROUND(used/slots*100)::int) \u003e 75;\n"},{"metrics":[{"attribute_columns":["dbname"],"description":"Number of times disk blocks were found already in the buffer cache, so that a read was not necessary","metric_name":"ccp_stat_database_blks_hit","static_attributes":{"server":"localhost:5432"},"value_column":"blks_hit"},{"attribute_columns":["dbname"],"description":"Number of disk blocks read in this database","metric_name":"ccp_stat_database_blks_read","static_attributes":{"server":"localhost:5432"},"value_column":"blks_read"},{"attribute_columns":["dbname"],"description":"Number of queries canceled due to conflicts with recovery in this database","metric_name":"ccp_stat_database_conflicts","static_attributes":{"server":"localhost:5432"},"value_column":"conflicts"},{"attribute_columns":["dbname"],"description":"Number of deadlocks detected in this database","metric_name":"ccp_stat_database_deadlocks","static_attributes":{"server":"localhost:5432"},"value_column":"deadlocks"},{"attribute_columns":["dbname"],"description":"Total amount of data written to temporary files by queries in this database","metric_name":"ccp_stat_database_temp_bytes","static_attributes":{"server":"localhost:5432"},"value_column":"temp_bytes"},{"attribute_columns":["dbname"],"description":"Number of rows deleted by queries in this database","metric_name":"ccp_stat_database_temp_files","static_attributes":{"server":"localhost:5432"},"value_column":"temp_files"},{"attribute_columns":["dbname"],"description":"Number of rows deleted by queries in this database","metric_name":"ccp_stat_database_tup_deleted","static_attributes":{"server":"localhost:5432"},"value_column":"tup_deleted"},{"attribute_columns":["dbname"],"description":"Number of rows fetched by queries in this database","metric_name":"ccp_stat_database_tup_fetched","static_attributes":{"server":"localhost:5432"},"value_column":"tup_fetched"},{"attribute_columns":["dbname"],"description":"Number of rows inserted by queries in this database","metric_name":"ccp_stat_database_tup_inserted","static_attributes":{"server":"localhost:5432"},"value_column":"tup_inserted"},{"attribute_columns":["dbname"],"description":"Number of rows returned by queries in this database","metric_name":"ccp_stat_database_tup_returned","static_attributes":{"server":"localhost:5432"},"value_column":"tup_returned"},{"attribute_columns":["dbname"],"description":"Number of rows updated by queries in this database","metric_name":"ccp_stat_database_tup_updated","static_attributes":{"server":"localhost:5432"},"value_column":"tup_updated"},{"attribute_columns":["dbname"],"description":"Number of transactions in this database that have been committed","metric_name":"ccp_stat_database_xact_commit","static_attributes":{"server":"localhost:5432"},"value_column":"xact_commit"},{"attribute_columns":["dbname"],"description":"Number of transactions in this database that have been rolled back","metric_name":"ccp_stat_database_xact_rollback","static_attributes":{"server":"localhost:5432"},"value_column":"xact_rollback"}],"sql":"SELECT s.datname AS dbname , s.xact_commit , s.xact_rollback , s.blks_read , s.blks_hit , s.tup_returned , s.tup_fetched , s.tup_inserted , s.tup_updated , s.tup_deleted , s.conflicts , s.temp_files , s.temp_bytes , s.deadlocks FROM pg_catalog.pg_stat_database s JOIN pg_catalog.pg_database d ON d.datname = s.datname WHERE d.datistemplate = false;\n"},{"metrics":[{"description":"Value of checksum monitioring status for pg_catalog.pg_settings (postgresql.conf).\n0 = valid config. 1 = settings changed. \nTo reset current config to valid after alert, run monitor.pg_settings_checksum_set_valid().\n","metric_name":"ccp_pg_hba_checksum","value_column":"status"}],"sql":"SELECT monitor.pg_hba_checksum() AS status;"}] diff --git a/internal/collector/postgres_5m_metrics.yaml b/internal/collector/postgres_5m_metrics.yaml index 9f5c3212dc..8cc7bccc02 100644 --- a/internal/collector/postgres_5m_metrics.yaml +++ b/internal/collector/postgres_5m_metrics.yaml @@ -140,4 +140,12 @@ attribute_columns: ["dbname"] static_attributes: server: "localhost:5432" - + + - sql: SELECT monitor.pg_hba_checksum() AS status; + metrics: + - metric_name: ccp_pg_hba_checksum + value_column: status + description: | + Value of checksum monitioring status for pg_catalog.pg_settings (postgresql.conf). + 0 = valid config. 1 = settings changed. + To reset current config to valid after alert, run monitor.pg_settings_checksum_set_valid(). diff --git a/internal/controller/postgrescluster/metrics_setup.sql b/internal/controller/postgrescluster/metrics_setup.sql index 728de80c3e..e6befd4364 100644 --- a/internal/controller/postgrescluster/metrics_setup.sql +++ b/internal/controller/postgrescluster/metrics_setup.sql @@ -220,3 +220,150 @@ BEGIN END; $$ LANGUAGE plpgsql; +/* + * Tables and functions for monitoring changes to pg_hba_file_rules system catalogs. + * Tables allow recording of existing settings so they can be referred back to to see what changed + * If checksum function returns 0, then NO settings have changed + * If checksum function returns 1, then something has changed since last known valid state + * For replicas, logging past settings is not possible to compare what may have changed + * For replicas, by default, it is expected that its settings will match the primary + * For replicas, if the pg_hba.conf are necessarily different from the primary, a known good hash of that replica's + settings can be sent as an argument to the relevant checksum function. Views are provided to easily obtain the hash values used by this monitoring tool. + * If any known hash parameters are passed to the checksum function, note that it will override any past hash values stored in the log table when doing comparisons and completely re-evaluate the entire state. This is true even if done on a primary where the current state will then also be logged for comparison if it differs from the given hash. + Taken from https://github.com/CrunchyData/pgmonitor/blob/development/postgres_exporter/common + */ + +-- Table used to store the old pg_hba, hash, and set the valid column +DROP TABLE IF EXISTS monitor.pg_hba_checksum; +CREATE TABLE monitor.pg_hba_checksum ( + hba_hash_generated text NOT NULL + , hba_hash_known_provided text + , hba_string text NOT NULL + , created_at timestamptz DEFAULT now() NOT NULL + , valid smallint NOT NULL ); + +COMMENT ON COLUMN monitor.pg_hba_checksum.valid IS 'Set this column to zero if this group of settings is a valid change'; +CREATE INDEX ON monitor.pg_hba_checksum (created_at); +-- End table that stores pg_hba hash + +-- Function used to compare old pg_hba hash and current hash +DROP FUNCTION IF EXISTS monitor.pg_hba_checksum(text); +CREATE FUNCTION monitor.pg_hba_checksum(p_known_hba_hash text DEFAULT NULL) + RETURNS smallint + LANGUAGE plpgsql SECURITY DEFINER + SET search_path TO pg_catalog, pg_temp +AS $function$ +DECLARE + +v_hba_hash text; +v_hba_hash_old text; +v_hba_match smallint := 0; +v_hba_string text; +v_hba_string_old text; +v_is_in_recovery boolean; +v_valid smallint; + +BEGIN + +SELECT pg_is_in_recovery() INTO v_is_in_recovery; + +IF current_setting('server_version_num')::int >= 100000 THEN + + SELECT sha256_hash + , hba_string + INTO v_hba_hash + , v_hba_string + FROM monitor.pg_hba_hash; + +ELSE + RAISE EXCEPTION 'pg_hba change monitoring unsupported in versions older than PostgreSQL 10'; +END IF; + +SELECT hba_hash_generated, valid +INTO v_hba_hash_old, v_valid +FROM monitor.pg_hba_checksum +ORDER BY created_at DESC LIMIT 1; + +IF p_known_hba_hash IS NOT NULL THEN + v_hba_hash_old := p_known_hba_hash; + -- Do not base validity on the stored value if manual hash is given. + v_valid := 0; +END IF; + +IF (v_hba_hash_old IS NOT NULL) THEN + + IF (v_hba_hash != v_hba_hash_old) THEN + + v_valid := 1; + + IF v_is_in_recovery = false THEN + INSERT INTO monitor.pg_hba_checksum ( + hba_hash_generated + , hba_hash_known_provided + , hba_string + , valid) + VALUES ( + v_hba_hash + , p_known_hba_hash + , v_hba_string + , v_valid); + END IF; + END IF; + +ELSE + + v_valid := 0; + IF v_is_in_recovery = false THEN + INSERT INTO monitor.pg_hba_checksum ( + hba_hash_generated + , hba_hash_known_provided + , hba_string + , valid) + VALUES (v_hba_hash + , p_known_hba_hash + , v_hba_string + , v_valid); + END IF; + +END IF; + +RETURN v_valid; + +END +$function$; +-- End function used to compare hashes + +-- View used to create hash of pg_hba +DROP VIEW IF EXISTS monitor.pg_hba_hash; +CREATE VIEW monitor.pg_hba_hash AS + -- Order by line number so it's caught if no content is changed but the order of entries is changed + WITH hba_ordered_list AS ( + SELECT COALESCE(type, '<>') AS type + , array_to_string(COALESCE(database, ARRAY['<>']), ',') AS database + , array_to_string(COALESCE(user_name, ARRAY['<>']), ',') AS user_name + , COALESCE(address, '<>') AS address + , COALESCE(netmask, '<>') AS netmask + , COALESCE(auth_method, '<>') AS auth_method + , array_to_string(COALESCE(options, ARRAY['<>']), ',') AS options + FROM pg_catalog.pg_hba_file_rules + ORDER BY line_number) + SELECT sha256((string_agg(type||database||user_name||address||netmask||auth_method||options, ','))::bytea) AS sha256_hash + , string_agg(type||database||user_name||address||netmask||auth_method||options, ',') AS hba_string + FROM hba_ordered_list; +-- End view used to create hash of pg_hba + +-- Function used to set pg_hba as valid +/* + * This function provides quick, clear interface for resetting the checksum monitor to treat the currently detected configuration as valid after alerting on a change. Note that configuration history will be cleared. + */ +DROP FUNCTION IF EXISTS monitor.pg_hba_checksum_set_valid(); +CREATE FUNCTION monitor.pg_hba_checksum_set_valid() RETURNS smallint + LANGUAGE sql +AS $function$ + +TRUNCATE monitor.pg_hba_checksum; + +SELECT monitor.pg_hba_checksum(); + +$function$; +-- End function used to set pg_hba as valid From f0b98814ab12ff04e000bbff9aa06798d8134165 Mon Sep 17 00:00:00 2001 From: Ben Blattberg Date: Tue, 6 May 2025 16:06:09 -0500 Subject: [PATCH 02/10] update test --- internal/collector/postgres_metrics_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/collector/postgres_metrics_test.go b/internal/collector/postgres_metrics_test.go index 8a22f42b52..63a6c654f3 100644 --- a/internal/collector/postgres_metrics_test.go +++ b/internal/collector/postgres_metrics_test.go @@ -17,9 +17,9 @@ func TestRemoveMetricsFromQueries(t *testing.T) { err := json.Unmarshal(fiveMinuteMetrics, &fiveMinuteMetricsArr) assert.NilError(t, err) - assert.Equal(t, len(fiveMinuteMetricsArr), 3) + assert.Equal(t, len(fiveMinuteMetricsArr), 4) newArr := removeMetricsFromQueries([]string{"ccp_database_size_bytes"}, fiveMinuteMetricsArr) - assert.Equal(t, len(newArr), 2) + assert.Equal(t, len(newArr), 3) t.Run("DeleteOneMetric", func(t *testing.T) { sqlMetricsData := `[ From c23514685890a3faf76b9d1c2c03d177ed876d19 Mon Sep 17 00:00:00 2001 From: Ben Blattberg Date: Tue, 6 May 2025 16:20:12 -0500 Subject: [PATCH 03/10] fix comment --- internal/collector/generated/postgres_5m_metrics.json | 2 +- internal/collector/postgres_5m_metrics.yaml | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/internal/collector/generated/postgres_5m_metrics.json b/internal/collector/generated/postgres_5m_metrics.json index 2dd76b73bd..11ddce0544 100644 --- a/internal/collector/generated/postgres_5m_metrics.json +++ b/internal/collector/generated/postgres_5m_metrics.json @@ -1 +1 @@ -[{"metrics":[{"attribute_columns":["dbname"],"description":"Database size in bytes","metric_name":"ccp_database_size_bytes","static_attributes":{"server":"localhost:5432"},"value_column":"bytes"}],"sql":"SELECT datname as dbname , pg_database_size(datname) as bytes FROM pg_catalog.pg_database WHERE datistemplate = false;\n"},{"metrics":[{"description":"Count of sequences that have reached greater than or equal to 75% of their max available numbers.\nFunction monitor.sequence_status() can provide more details if run directly on system.\n","metric_name":"ccp_sequence_exhaustion_count","static_attributes":{"server":"localhost:5432"},"value_column":"count"}],"sql":"SELECT count(*) AS count FROM (\n SELECT CEIL((s.max_value-min_value::NUMERIC+1)/s.increment_by::NUMERIC) AS slots\n , CEIL((COALESCE(s.last_value,s.min_value)-s.min_value::NUMERIC+1)/s.increment_by::NUMERIC) AS used\n FROM pg_catalog.pg_sequences s\n) x WHERE (ROUND(used/slots*100)::int) \u003e 75;\n"},{"metrics":[{"attribute_columns":["dbname"],"description":"Number of times disk blocks were found already in the buffer cache, so that a read was not necessary","metric_name":"ccp_stat_database_blks_hit","static_attributes":{"server":"localhost:5432"},"value_column":"blks_hit"},{"attribute_columns":["dbname"],"description":"Number of disk blocks read in this database","metric_name":"ccp_stat_database_blks_read","static_attributes":{"server":"localhost:5432"},"value_column":"blks_read"},{"attribute_columns":["dbname"],"description":"Number of queries canceled due to conflicts with recovery in this database","metric_name":"ccp_stat_database_conflicts","static_attributes":{"server":"localhost:5432"},"value_column":"conflicts"},{"attribute_columns":["dbname"],"description":"Number of deadlocks detected in this database","metric_name":"ccp_stat_database_deadlocks","static_attributes":{"server":"localhost:5432"},"value_column":"deadlocks"},{"attribute_columns":["dbname"],"description":"Total amount of data written to temporary files by queries in this database","metric_name":"ccp_stat_database_temp_bytes","static_attributes":{"server":"localhost:5432"},"value_column":"temp_bytes"},{"attribute_columns":["dbname"],"description":"Number of rows deleted by queries in this database","metric_name":"ccp_stat_database_temp_files","static_attributes":{"server":"localhost:5432"},"value_column":"temp_files"},{"attribute_columns":["dbname"],"description":"Number of rows deleted by queries in this database","metric_name":"ccp_stat_database_tup_deleted","static_attributes":{"server":"localhost:5432"},"value_column":"tup_deleted"},{"attribute_columns":["dbname"],"description":"Number of rows fetched by queries in this database","metric_name":"ccp_stat_database_tup_fetched","static_attributes":{"server":"localhost:5432"},"value_column":"tup_fetched"},{"attribute_columns":["dbname"],"description":"Number of rows inserted by queries in this database","metric_name":"ccp_stat_database_tup_inserted","static_attributes":{"server":"localhost:5432"},"value_column":"tup_inserted"},{"attribute_columns":["dbname"],"description":"Number of rows returned by queries in this database","metric_name":"ccp_stat_database_tup_returned","static_attributes":{"server":"localhost:5432"},"value_column":"tup_returned"},{"attribute_columns":["dbname"],"description":"Number of rows updated by queries in this database","metric_name":"ccp_stat_database_tup_updated","static_attributes":{"server":"localhost:5432"},"value_column":"tup_updated"},{"attribute_columns":["dbname"],"description":"Number of transactions in this database that have been committed","metric_name":"ccp_stat_database_xact_commit","static_attributes":{"server":"localhost:5432"},"value_column":"xact_commit"},{"attribute_columns":["dbname"],"description":"Number of transactions in this database that have been rolled back","metric_name":"ccp_stat_database_xact_rollback","static_attributes":{"server":"localhost:5432"},"value_column":"xact_rollback"}],"sql":"SELECT s.datname AS dbname , s.xact_commit , s.xact_rollback , s.blks_read , s.blks_hit , s.tup_returned , s.tup_fetched , s.tup_inserted , s.tup_updated , s.tup_deleted , s.conflicts , s.temp_files , s.temp_bytes , s.deadlocks FROM pg_catalog.pg_stat_database s JOIN pg_catalog.pg_database d ON d.datname = s.datname WHERE d.datistemplate = false;\n"},{"metrics":[{"description":"Value of checksum monitioring status for pg_catalog.pg_settings (postgresql.conf).\n0 = valid config. 1 = settings changed. \nTo reset current config to valid after alert, run monitor.pg_settings_checksum_set_valid().\n","metric_name":"ccp_pg_hba_checksum","value_column":"status"}],"sql":"SELECT monitor.pg_hba_checksum() AS status;"}] +[{"metrics":[{"attribute_columns":["dbname"],"description":"Database size in bytes","metric_name":"ccp_database_size_bytes","static_attributes":{"server":"localhost:5432"},"value_column":"bytes"}],"sql":"SELECT datname as dbname , pg_database_size(datname) as bytes FROM pg_catalog.pg_database WHERE datistemplate = false;\n"},{"metrics":[{"description":"Count of sequences that have reached greater than or equal to 75% of their max available numbers.\nFunction monitor.sequence_status() can provide more details if run directly on system.\n","metric_name":"ccp_sequence_exhaustion_count","static_attributes":{"server":"localhost:5432"},"value_column":"count"}],"sql":"SELECT count(*) AS count FROM (\n SELECT CEIL((s.max_value-min_value::NUMERIC+1)/s.increment_by::NUMERIC) AS slots\n , CEIL((COALESCE(s.last_value,s.min_value)-s.min_value::NUMERIC+1)/s.increment_by::NUMERIC) AS used\n FROM pg_catalog.pg_sequences s\n) x WHERE (ROUND(used/slots*100)::int) \u003e 75;\n"},{"metrics":[{"attribute_columns":["dbname"],"description":"Number of times disk blocks were found already in the buffer cache, so that a read was not necessary","metric_name":"ccp_stat_database_blks_hit","static_attributes":{"server":"localhost:5432"},"value_column":"blks_hit"},{"attribute_columns":["dbname"],"description":"Number of disk blocks read in this database","metric_name":"ccp_stat_database_blks_read","static_attributes":{"server":"localhost:5432"},"value_column":"blks_read"},{"attribute_columns":["dbname"],"description":"Number of queries canceled due to conflicts with recovery in this database","metric_name":"ccp_stat_database_conflicts","static_attributes":{"server":"localhost:5432"},"value_column":"conflicts"},{"attribute_columns":["dbname"],"description":"Number of deadlocks detected in this database","metric_name":"ccp_stat_database_deadlocks","static_attributes":{"server":"localhost:5432"},"value_column":"deadlocks"},{"attribute_columns":["dbname"],"description":"Total amount of data written to temporary files by queries in this database","metric_name":"ccp_stat_database_temp_bytes","static_attributes":{"server":"localhost:5432"},"value_column":"temp_bytes"},{"attribute_columns":["dbname"],"description":"Number of rows deleted by queries in this database","metric_name":"ccp_stat_database_temp_files","static_attributes":{"server":"localhost:5432"},"value_column":"temp_files"},{"attribute_columns":["dbname"],"description":"Number of rows deleted by queries in this database","metric_name":"ccp_stat_database_tup_deleted","static_attributes":{"server":"localhost:5432"},"value_column":"tup_deleted"},{"attribute_columns":["dbname"],"description":"Number of rows fetched by queries in this database","metric_name":"ccp_stat_database_tup_fetched","static_attributes":{"server":"localhost:5432"},"value_column":"tup_fetched"},{"attribute_columns":["dbname"],"description":"Number of rows inserted by queries in this database","metric_name":"ccp_stat_database_tup_inserted","static_attributes":{"server":"localhost:5432"},"value_column":"tup_inserted"},{"attribute_columns":["dbname"],"description":"Number of rows returned by queries in this database","metric_name":"ccp_stat_database_tup_returned","static_attributes":{"server":"localhost:5432"},"value_column":"tup_returned"},{"attribute_columns":["dbname"],"description":"Number of rows updated by queries in this database","metric_name":"ccp_stat_database_tup_updated","static_attributes":{"server":"localhost:5432"},"value_column":"tup_updated"},{"attribute_columns":["dbname"],"description":"Number of transactions in this database that have been committed","metric_name":"ccp_stat_database_xact_commit","static_attributes":{"server":"localhost:5432"},"value_column":"xact_commit"},{"attribute_columns":["dbname"],"description":"Number of transactions in this database that have been rolled back","metric_name":"ccp_stat_database_xact_rollback","static_attributes":{"server":"localhost:5432"},"value_column":"xact_rollback"}],"sql":"SELECT s.datname AS dbname , s.xact_commit , s.xact_rollback , s.blks_read , s.blks_hit , s.tup_returned , s.tup_fetched , s.tup_inserted , s.tup_updated , s.tup_deleted , s.conflicts , s.temp_files , s.temp_bytes , s.deadlocks FROM pg_catalog.pg_stat_database s JOIN pg_catalog.pg_database d ON d.datname = s.datname WHERE d.datistemplate = false;\n"},{"metrics":[{"description":"Value of checksum monitioring status for pg_catalog.pg_hba_file_rules (pg_hba.conf).\n0 = valid config. 1 = settings changed. \nSettings history is available for review in the table `monitor.pg_hba_checksum`.\nTo reset current config to valid after alert, run monitor.pg_hba_checksum_set_valid(). Note this will clear the history table.\n","metric_name":"ccp_pg_hba_checksum","value_column":"status"}],"sql":"SELECT monitor.pg_hba_checksum() AS status;"}] diff --git a/internal/collector/postgres_5m_metrics.yaml b/internal/collector/postgres_5m_metrics.yaml index 8cc7bccc02..c521ac03b2 100644 --- a/internal/collector/postgres_5m_metrics.yaml +++ b/internal/collector/postgres_5m_metrics.yaml @@ -146,6 +146,7 @@ - metric_name: ccp_pg_hba_checksum value_column: status description: | - Value of checksum monitioring status for pg_catalog.pg_settings (postgresql.conf). + Value of checksum monitioring status for pg_catalog.pg_hba_file_rules (pg_hba.conf). 0 = valid config. 1 = settings changed. - To reset current config to valid after alert, run monitor.pg_settings_checksum_set_valid(). + Settings history is available for review in the table `monitor.pg_hba_checksum`. + To reset current config to valid after alert, run monitor.pg_hba_checksum_set_valid(). Note this will clear the history table. From 1c1ba518176f9a62a90301b6efd35da9fa67937e Mon Sep 17 00:00:00 2001 From: Benjamin Blattberg Date: Wed, 7 May 2025 09:26:38 -0500 Subject: [PATCH 04/10] Update internal/collector/postgres_5m_metrics.yaml Co-authored-by: Tony Landreth <56887169+tony-landreth@users.noreply.github.com> --- internal/collector/postgres_5m_metrics.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/collector/postgres_5m_metrics.yaml b/internal/collector/postgres_5m_metrics.yaml index c521ac03b2..7de7d94caa 100644 --- a/internal/collector/postgres_5m_metrics.yaml +++ b/internal/collector/postgres_5m_metrics.yaml @@ -146,7 +146,7 @@ - metric_name: ccp_pg_hba_checksum value_column: status description: | - Value of checksum monitioring status for pg_catalog.pg_hba_file_rules (pg_hba.conf). + Value of checksum monitoring status for pg_catalog.pg_hba_file_rules (pg_hba.conf). 0 = valid config. 1 = settings changed. Settings history is available for review in the table `monitor.pg_hba_checksum`. To reset current config to valid after alert, run monitor.pg_hba_checksum_set_valid(). Note this will clear the history table. From 216f2b727455617cb8b3797b8aaed99cae877f07 Mon Sep 17 00:00:00 2001 From: Benjamin Blattberg Date: Wed, 7 May 2025 09:32:50 -0500 Subject: [PATCH 05/10] Update internal/controller/postgrescluster/metrics_setup.sql Co-authored-by: Tony Landreth <56887169+tony-landreth@users.noreply.github.com> --- internal/controller/postgrescluster/metrics_setup.sql | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/internal/controller/postgrescluster/metrics_setup.sql b/internal/controller/postgrescluster/metrics_setup.sql index e6befd4364..65fbe989c4 100644 --- a/internal/controller/postgrescluster/metrics_setup.sql +++ b/internal/controller/postgrescluster/metrics_setup.sql @@ -269,10 +269,8 @@ SELECT pg_is_in_recovery() INTO v_is_in_recovery; IF current_setting('server_version_num')::int >= 100000 THEN - SELECT sha256_hash - , hba_string - INTO v_hba_hash - , v_hba_string + SELECT sha256_hash, hba_string + INTO v_hba_hash, v_hba_string FROM monitor.pg_hba_hash; ELSE From 4c534cf5b67473bb9041125ce5c5c9a6c9f4494c Mon Sep 17 00:00:00 2001 From: Ben Blattberg Date: Wed, 7 May 2025 09:41:17 -0500 Subject: [PATCH 06/10] fix: --- internal/controller/postgrescluster/metrics_setup.sql | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/internal/controller/postgrescluster/metrics_setup.sql b/internal/controller/postgrescluster/metrics_setup.sql index 65fbe989c4..7493c6234f 100644 --- a/internal/controller/postgrescluster/metrics_setup.sql +++ b/internal/controller/postgrescluster/metrics_setup.sql @@ -221,6 +221,7 @@ END; $$ LANGUAGE plpgsql; /* +-- TODO: WHAT IS REALLY HAPPENING HERE? * Tables and functions for monitoring changes to pg_hba_file_rules system catalogs. * Tables allow recording of existing settings so they can be referred back to to see what changed * If checksum function returns 0, then NO settings have changed @@ -257,9 +258,7 @@ DECLARE v_hba_hash text; v_hba_hash_old text; -v_hba_match smallint := 0; v_hba_string text; -v_hba_string_old text; v_is_in_recovery boolean; v_valid smallint; From 8167a6369989d59489657aea021c317f3005bc61 Mon Sep 17 00:00:00 2001 From: Ben Blattberg Date: Wed, 7 May 2025 15:40:47 -0500 Subject: [PATCH 07/10] comments, rework pg_hba func --- .../postgrescluster/metrics_setup.sql | 109 ++++++++++-------- 1 file changed, 59 insertions(+), 50 deletions(-) diff --git a/internal/controller/postgrescluster/metrics_setup.sql b/internal/controller/postgrescluster/metrics_setup.sql index 7493c6234f..344870eefb 100644 --- a/internal/controller/postgrescluster/metrics_setup.sql +++ b/internal/controller/postgrescluster/metrics_setup.sql @@ -221,20 +221,25 @@ END; $$ LANGUAGE plpgsql; /* --- TODO: WHAT IS REALLY HAPPENING HERE? - * Tables and functions for monitoring changes to pg_hba_file_rules system catalogs. - * Tables allow recording of existing settings so they can be referred back to to see what changed - * If checksum function returns 0, then NO settings have changed - * If checksum function returns 1, then something has changed since last known valid state - * For replicas, logging past settings is not possible to compare what may have changed - * For replicas, by default, it is expected that its settings will match the primary - * For replicas, if the pg_hba.conf are necessarily different from the primary, a known good hash of that replica's - settings can be sent as an argument to the relevant checksum function. Views are provided to easily obtain the hash values used by this monitoring tool. - * If any known hash parameters are passed to the checksum function, note that it will override any past hash values stored in the log table when doing comparisons and completely re-evaluate the entire state. This is true even if done on a primary where the current state will then also be logged for comparison if it differs from the given hash. - Taken from https://github.com/CrunchyData/pgmonitor/blob/development/postgres_exporter/common - */ +* The `pg_hba_checksum` table, functions, and view are taken from +* https://github.com/CrunchyData/pgmonitor/blob/development/postgres_exporter/common +* +* The goal of these table, functions, and view is to monitor changes +* to the pg_hba_file_rules system catalog. +* +* This material is used in the metric `ccp_pg_hba_checksum`. +*/ --- Table used to store the old pg_hba, hash, and set the valid column +/* +* `monitor.pg_hba_checksum` table is used to store +* - the pg_hba settings as string (for reference) +* - the pg_hba settings as hash (for quick comparison) +* - the `hba_hash_known_provided` (for overide hash manually given to the `monitor.pg_hba_checksum` function) +* - the `valid` field to signal whether the pg_hba settings have not changed since they were accepted as valid +* +* We create an index on `created_at` in order to pull the most recent entry for +* comparison in the `monitor.pg_hba_checksum` function +*/ DROP TABLE IF EXISTS monitor.pg_hba_checksum; CREATE TABLE monitor.pg_hba_checksum ( hba_hash_generated text NOT NULL @@ -242,12 +247,23 @@ CREATE TABLE monitor.pg_hba_checksum ( , hba_string text NOT NULL , created_at timestamptz DEFAULT now() NOT NULL , valid smallint NOT NULL ); - COMMENT ON COLUMN monitor.pg_hba_checksum.valid IS 'Set this column to zero if this group of settings is a valid change'; CREATE INDEX ON monitor.pg_hba_checksum (created_at); --- End table that stores pg_hba hash --- Function used to compare old pg_hba hash and current hash +/* + * `monitor.pg_hba_checksum(text)` is used to compare the previous pg_hba hash + * with a hash made of the current pg_hba hash, derived from the `monitor.pg_hba_hash` view below. + * + * This function returns + * - 0, indicating NO settings have changed + * - 1, indicating something has changed since last known valid state + * + * `monitor.pg_hba_checksum` can take a hash to be used as an override. + * This may be useful when you have a standby with different pg_hba rules; + * since it will have different rules (and therefore a different hash), you + * could alter the metric function to pass the actual hash, which would be + * used in lieu of this table's value (derived from the primary cluster's rules). + */ DROP FUNCTION IF EXISTS monitor.pg_hba_checksum(text); CREATE FUNCTION monitor.pg_hba_checksum(p_known_hba_hash text DEFAULT NULL) RETURNS smallint @@ -264,73 +280,67 @@ v_valid smallint; BEGIN -SELECT pg_is_in_recovery() INTO v_is_in_recovery; - +-- Retrieve the current settings from the `monitor.pg_hba_hash` view below IF current_setting('server_version_num')::int >= 100000 THEN - SELECT sha256_hash, hba_string INTO v_hba_hash, v_hba_string FROM monitor.pg_hba_hash; - ELSE RAISE EXCEPTION 'pg_hba change monitoring unsupported in versions older than PostgreSQL 10'; END IF; +-- Retrieve the last previous hash from the table SELECT hba_hash_generated, valid INTO v_hba_hash_old, v_valid FROM monitor.pg_hba_checksum ORDER BY created_at DESC LIMIT 1; +-- If an manual/override hash has been given, we will use that: +-- Do not base validity on the stored value if manual hash is given. IF p_known_hba_hash IS NOT NULL THEN v_hba_hash_old := p_known_hba_hash; - -- Do not base validity on the stored value if manual hash is given. v_valid := 0; END IF; -IF (v_hba_hash_old IS NOT NULL) THEN - - IF (v_hba_hash != v_hba_hash_old) THEN - - v_valid := 1; - - IF v_is_in_recovery = false THEN - INSERT INTO monitor.pg_hba_checksum ( - hba_hash_generated - , hba_hash_known_provided - , hba_string - , valid) - VALUES ( - v_hba_hash - , p_known_hba_hash - , v_hba_string - , v_valid); - END IF; - END IF; - +IF (v_hba_hash_old IS NOT NULL) AND (v_hba_hash != v_hba_hash_old) THEN + v_valid := 1; ELSE - v_valid := 0; +END IF; + +/* + * We only want to insert into the table if we're on a primary and + * - the table/manually entered hash is empty, e.g., we've just started the cluster; or + * - the hashes don't match + * + * There's no value added by inserting into the table when no change was detected. + */ +IF (v_hba_hash_old IS NULL) OR (v_hba_hash != v_hba_hash_old) THEN + SELECT pg_is_in_recovery() INTO v_is_in_recovery; IF v_is_in_recovery = false THEN INSERT INTO monitor.pg_hba_checksum ( hba_hash_generated , hba_hash_known_provided , hba_string , valid) - VALUES (v_hba_hash + VALUES ( + v_hba_hash , p_known_hba_hash , v_hba_string , v_valid); END IF; - END IF; RETURN v_valid; END $function$; --- End function used to compare hashes --- View used to create hash of pg_hba +/* + * The `monitor.pg_hba_hash` view return both a hash and a string aggregate of the + * pg_catalog.pg_hba_file_rules. + * Note: We use `sha256` to hash to allow this to run on FIPS environments. + */ DROP VIEW IF EXISTS monitor.pg_hba_hash; CREATE VIEW monitor.pg_hba_hash AS -- Order by line number so it's caught if no content is changed but the order of entries is changed @@ -347,11 +357,11 @@ CREATE VIEW monitor.pg_hba_hash AS SELECT sha256((string_agg(type||database||user_name||address||netmask||auth_method||options, ','))::bytea) AS sha256_hash , string_agg(type||database||user_name||address||netmask||auth_method||options, ',') AS hba_string FROM hba_ordered_list; --- End view used to create hash of pg_hba --- Function used to set pg_hba as valid /* - * This function provides quick, clear interface for resetting the checksum monitor to treat the currently detected configuration as valid after alerting on a change. Note that configuration history will be cleared. + * The `monitor.pg_hba_checksum_set_valid` function provides an interface for resetting the + * checksum monitor. + * Note: configuration history will be cleared. */ DROP FUNCTION IF EXISTS monitor.pg_hba_checksum_set_valid(); CREATE FUNCTION monitor.pg_hba_checksum_set_valid() RETURNS smallint @@ -363,4 +373,3 @@ TRUNCATE monitor.pg_hba_checksum; SELECT monitor.pg_hba_checksum(); $function$; --- End function used to set pg_hba as valid From dc25f7b260aec2c50b635f542b34acb2ea9d8d42 Mon Sep 17 00:00:00 2001 From: Ben Blattberg Date: Wed, 7 May 2025 16:04:26 -0500 Subject: [PATCH 08/10] comments, rework pg_hba func --- .../controller/postgrescluster/metrics_setup.sql | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/internal/controller/postgrescluster/metrics_setup.sql b/internal/controller/postgrescluster/metrics_setup.sql index 344870eefb..858f95c023 100644 --- a/internal/controller/postgrescluster/metrics_setup.sql +++ b/internal/controller/postgrescluster/metrics_setup.sql @@ -302,8 +302,16 @@ IF p_known_hba_hash IS NOT NULL THEN v_valid := 0; END IF; -IF (v_hba_hash_old IS NOT NULL) AND (v_hba_hash != v_hba_hash_old) THEN - v_valid := 1; +/* If the table is not empty or a manual hash was given, + * then we want to compare the old hash (from the table) + * with the new hash: if those differ, then we set the validity to 1; + * if they are the same, then we honor what the validity was + * in the table (which would be 1). + */ +IF (v_hba_hash_old IS NOT NULL) THEN + IF (v_hba_hash != v_hba_hash_old) THEN + v_valid := 1; + END IF; ELSE v_valid := 0; END IF; From 30dfce66ce6ff11e3fd898303b7e70805e0f6fbe Mon Sep 17 00:00:00 2001 From: Ben Blattberg Date: Wed, 7 May 2025 16:15:54 -0500 Subject: [PATCH 09/10] fix --- internal/collector/generated/postgres_5m_metrics.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/collector/generated/postgres_5m_metrics.json b/internal/collector/generated/postgres_5m_metrics.json index 11ddce0544..da5aad3701 100644 --- a/internal/collector/generated/postgres_5m_metrics.json +++ b/internal/collector/generated/postgres_5m_metrics.json @@ -1 +1 @@ -[{"metrics":[{"attribute_columns":["dbname"],"description":"Database size in bytes","metric_name":"ccp_database_size_bytes","static_attributes":{"server":"localhost:5432"},"value_column":"bytes"}],"sql":"SELECT datname as dbname , pg_database_size(datname) as bytes FROM pg_catalog.pg_database WHERE datistemplate = false;\n"},{"metrics":[{"description":"Count of sequences that have reached greater than or equal to 75% of their max available numbers.\nFunction monitor.sequence_status() can provide more details if run directly on system.\n","metric_name":"ccp_sequence_exhaustion_count","static_attributes":{"server":"localhost:5432"},"value_column":"count"}],"sql":"SELECT count(*) AS count FROM (\n SELECT CEIL((s.max_value-min_value::NUMERIC+1)/s.increment_by::NUMERIC) AS slots\n , CEIL((COALESCE(s.last_value,s.min_value)-s.min_value::NUMERIC+1)/s.increment_by::NUMERIC) AS used\n FROM pg_catalog.pg_sequences s\n) x WHERE (ROUND(used/slots*100)::int) \u003e 75;\n"},{"metrics":[{"attribute_columns":["dbname"],"description":"Number of times disk blocks were found already in the buffer cache, so that a read was not necessary","metric_name":"ccp_stat_database_blks_hit","static_attributes":{"server":"localhost:5432"},"value_column":"blks_hit"},{"attribute_columns":["dbname"],"description":"Number of disk blocks read in this database","metric_name":"ccp_stat_database_blks_read","static_attributes":{"server":"localhost:5432"},"value_column":"blks_read"},{"attribute_columns":["dbname"],"description":"Number of queries canceled due to conflicts with recovery in this database","metric_name":"ccp_stat_database_conflicts","static_attributes":{"server":"localhost:5432"},"value_column":"conflicts"},{"attribute_columns":["dbname"],"description":"Number of deadlocks detected in this database","metric_name":"ccp_stat_database_deadlocks","static_attributes":{"server":"localhost:5432"},"value_column":"deadlocks"},{"attribute_columns":["dbname"],"description":"Total amount of data written to temporary files by queries in this database","metric_name":"ccp_stat_database_temp_bytes","static_attributes":{"server":"localhost:5432"},"value_column":"temp_bytes"},{"attribute_columns":["dbname"],"description":"Number of rows deleted by queries in this database","metric_name":"ccp_stat_database_temp_files","static_attributes":{"server":"localhost:5432"},"value_column":"temp_files"},{"attribute_columns":["dbname"],"description":"Number of rows deleted by queries in this database","metric_name":"ccp_stat_database_tup_deleted","static_attributes":{"server":"localhost:5432"},"value_column":"tup_deleted"},{"attribute_columns":["dbname"],"description":"Number of rows fetched by queries in this database","metric_name":"ccp_stat_database_tup_fetched","static_attributes":{"server":"localhost:5432"},"value_column":"tup_fetched"},{"attribute_columns":["dbname"],"description":"Number of rows inserted by queries in this database","metric_name":"ccp_stat_database_tup_inserted","static_attributes":{"server":"localhost:5432"},"value_column":"tup_inserted"},{"attribute_columns":["dbname"],"description":"Number of rows returned by queries in this database","metric_name":"ccp_stat_database_tup_returned","static_attributes":{"server":"localhost:5432"},"value_column":"tup_returned"},{"attribute_columns":["dbname"],"description":"Number of rows updated by queries in this database","metric_name":"ccp_stat_database_tup_updated","static_attributes":{"server":"localhost:5432"},"value_column":"tup_updated"},{"attribute_columns":["dbname"],"description":"Number of transactions in this database that have been committed","metric_name":"ccp_stat_database_xact_commit","static_attributes":{"server":"localhost:5432"},"value_column":"xact_commit"},{"attribute_columns":["dbname"],"description":"Number of transactions in this database that have been rolled back","metric_name":"ccp_stat_database_xact_rollback","static_attributes":{"server":"localhost:5432"},"value_column":"xact_rollback"}],"sql":"SELECT s.datname AS dbname , s.xact_commit , s.xact_rollback , s.blks_read , s.blks_hit , s.tup_returned , s.tup_fetched , s.tup_inserted , s.tup_updated , s.tup_deleted , s.conflicts , s.temp_files , s.temp_bytes , s.deadlocks FROM pg_catalog.pg_stat_database s JOIN pg_catalog.pg_database d ON d.datname = s.datname WHERE d.datistemplate = false;\n"},{"metrics":[{"description":"Value of checksum monitioring status for pg_catalog.pg_hba_file_rules (pg_hba.conf).\n0 = valid config. 1 = settings changed. \nSettings history is available for review in the table `monitor.pg_hba_checksum`.\nTo reset current config to valid after alert, run monitor.pg_hba_checksum_set_valid(). Note this will clear the history table.\n","metric_name":"ccp_pg_hba_checksum","value_column":"status"}],"sql":"SELECT monitor.pg_hba_checksum() AS status;"}] +[{"metrics":[{"attribute_columns":["dbname"],"description":"Database size in bytes","metric_name":"ccp_database_size_bytes","static_attributes":{"server":"localhost:5432"},"value_column":"bytes"}],"sql":"SELECT datname as dbname , pg_database_size(datname) as bytes FROM pg_catalog.pg_database WHERE datistemplate = false;\n"},{"metrics":[{"description":"Count of sequences that have reached greater than or equal to 75% of their max available numbers.\nFunction monitor.sequence_status() can provide more details if run directly on system.\n","metric_name":"ccp_sequence_exhaustion_count","static_attributes":{"server":"localhost:5432"},"value_column":"count"}],"sql":"SELECT count(*) AS count FROM (\n SELECT CEIL((s.max_value-min_value::NUMERIC+1)/s.increment_by::NUMERIC) AS slots\n , CEIL((COALESCE(s.last_value,s.min_value)-s.min_value::NUMERIC+1)/s.increment_by::NUMERIC) AS used\n FROM pg_catalog.pg_sequences s\n) x WHERE (ROUND(used/slots*100)::int) \u003e 75;\n"},{"metrics":[{"attribute_columns":["dbname"],"description":"Number of times disk blocks were found already in the buffer cache, so that a read was not necessary","metric_name":"ccp_stat_database_blks_hit","static_attributes":{"server":"localhost:5432"},"value_column":"blks_hit"},{"attribute_columns":["dbname"],"description":"Number of disk blocks read in this database","metric_name":"ccp_stat_database_blks_read","static_attributes":{"server":"localhost:5432"},"value_column":"blks_read"},{"attribute_columns":["dbname"],"description":"Number of queries canceled due to conflicts with recovery in this database","metric_name":"ccp_stat_database_conflicts","static_attributes":{"server":"localhost:5432"},"value_column":"conflicts"},{"attribute_columns":["dbname"],"description":"Number of deadlocks detected in this database","metric_name":"ccp_stat_database_deadlocks","static_attributes":{"server":"localhost:5432"},"value_column":"deadlocks"},{"attribute_columns":["dbname"],"description":"Total amount of data written to temporary files by queries in this database","metric_name":"ccp_stat_database_temp_bytes","static_attributes":{"server":"localhost:5432"},"value_column":"temp_bytes"},{"attribute_columns":["dbname"],"description":"Number of rows deleted by queries in this database","metric_name":"ccp_stat_database_temp_files","static_attributes":{"server":"localhost:5432"},"value_column":"temp_files"},{"attribute_columns":["dbname"],"description":"Number of rows deleted by queries in this database","metric_name":"ccp_stat_database_tup_deleted","static_attributes":{"server":"localhost:5432"},"value_column":"tup_deleted"},{"attribute_columns":["dbname"],"description":"Number of rows fetched by queries in this database","metric_name":"ccp_stat_database_tup_fetched","static_attributes":{"server":"localhost:5432"},"value_column":"tup_fetched"},{"attribute_columns":["dbname"],"description":"Number of rows inserted by queries in this database","metric_name":"ccp_stat_database_tup_inserted","static_attributes":{"server":"localhost:5432"},"value_column":"tup_inserted"},{"attribute_columns":["dbname"],"description":"Number of rows returned by queries in this database","metric_name":"ccp_stat_database_tup_returned","static_attributes":{"server":"localhost:5432"},"value_column":"tup_returned"},{"attribute_columns":["dbname"],"description":"Number of rows updated by queries in this database","metric_name":"ccp_stat_database_tup_updated","static_attributes":{"server":"localhost:5432"},"value_column":"tup_updated"},{"attribute_columns":["dbname"],"description":"Number of transactions in this database that have been committed","metric_name":"ccp_stat_database_xact_commit","static_attributes":{"server":"localhost:5432"},"value_column":"xact_commit"},{"attribute_columns":["dbname"],"description":"Number of transactions in this database that have been rolled back","metric_name":"ccp_stat_database_xact_rollback","static_attributes":{"server":"localhost:5432"},"value_column":"xact_rollback"}],"sql":"SELECT s.datname AS dbname , s.xact_commit , s.xact_rollback , s.blks_read , s.blks_hit , s.tup_returned , s.tup_fetched , s.tup_inserted , s.tup_updated , s.tup_deleted , s.conflicts , s.temp_files , s.temp_bytes , s.deadlocks FROM pg_catalog.pg_stat_database s JOIN pg_catalog.pg_database d ON d.datname = s.datname WHERE d.datistemplate = false;\n"},{"metrics":[{"description":"Value of checksum monitoring status for pg_catalog.pg_hba_file_rules (pg_hba.conf).\n0 = valid config. 1 = settings changed. \nSettings history is available for review in the table `monitor.pg_hba_checksum`.\nTo reset current config to valid after alert, run monitor.pg_hba_checksum_set_valid(). Note this will clear the history table.\n","metric_name":"ccp_pg_hba_checksum","value_column":"status"}],"sql":"SELECT monitor.pg_hba_checksum() AS status;"}] From 97ec15f8e57061d07588fa055e4e5b1ad8999382 Mon Sep 17 00:00:00 2001 From: Ben Blattberg Date: Thu, 8 May 2025 09:51:24 -0500 Subject: [PATCH 10/10] add static attribute --- internal/collector/generated/postgres_5m_metrics.json | 2 +- internal/collector/postgres_5m_metrics.yaml | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/internal/collector/generated/postgres_5m_metrics.json b/internal/collector/generated/postgres_5m_metrics.json index da5aad3701..371a7fa182 100644 --- a/internal/collector/generated/postgres_5m_metrics.json +++ b/internal/collector/generated/postgres_5m_metrics.json @@ -1 +1 @@ -[{"metrics":[{"attribute_columns":["dbname"],"description":"Database size in bytes","metric_name":"ccp_database_size_bytes","static_attributes":{"server":"localhost:5432"},"value_column":"bytes"}],"sql":"SELECT datname as dbname , pg_database_size(datname) as bytes FROM pg_catalog.pg_database WHERE datistemplate = false;\n"},{"metrics":[{"description":"Count of sequences that have reached greater than or equal to 75% of their max available numbers.\nFunction monitor.sequence_status() can provide more details if run directly on system.\n","metric_name":"ccp_sequence_exhaustion_count","static_attributes":{"server":"localhost:5432"},"value_column":"count"}],"sql":"SELECT count(*) AS count FROM (\n SELECT CEIL((s.max_value-min_value::NUMERIC+1)/s.increment_by::NUMERIC) AS slots\n , CEIL((COALESCE(s.last_value,s.min_value)-s.min_value::NUMERIC+1)/s.increment_by::NUMERIC) AS used\n FROM pg_catalog.pg_sequences s\n) x WHERE (ROUND(used/slots*100)::int) \u003e 75;\n"},{"metrics":[{"attribute_columns":["dbname"],"description":"Number of times disk blocks were found already in the buffer cache, so that a read was not necessary","metric_name":"ccp_stat_database_blks_hit","static_attributes":{"server":"localhost:5432"},"value_column":"blks_hit"},{"attribute_columns":["dbname"],"description":"Number of disk blocks read in this database","metric_name":"ccp_stat_database_blks_read","static_attributes":{"server":"localhost:5432"},"value_column":"blks_read"},{"attribute_columns":["dbname"],"description":"Number of queries canceled due to conflicts with recovery in this database","metric_name":"ccp_stat_database_conflicts","static_attributes":{"server":"localhost:5432"},"value_column":"conflicts"},{"attribute_columns":["dbname"],"description":"Number of deadlocks detected in this database","metric_name":"ccp_stat_database_deadlocks","static_attributes":{"server":"localhost:5432"},"value_column":"deadlocks"},{"attribute_columns":["dbname"],"description":"Total amount of data written to temporary files by queries in this database","metric_name":"ccp_stat_database_temp_bytes","static_attributes":{"server":"localhost:5432"},"value_column":"temp_bytes"},{"attribute_columns":["dbname"],"description":"Number of rows deleted by queries in this database","metric_name":"ccp_stat_database_temp_files","static_attributes":{"server":"localhost:5432"},"value_column":"temp_files"},{"attribute_columns":["dbname"],"description":"Number of rows deleted by queries in this database","metric_name":"ccp_stat_database_tup_deleted","static_attributes":{"server":"localhost:5432"},"value_column":"tup_deleted"},{"attribute_columns":["dbname"],"description":"Number of rows fetched by queries in this database","metric_name":"ccp_stat_database_tup_fetched","static_attributes":{"server":"localhost:5432"},"value_column":"tup_fetched"},{"attribute_columns":["dbname"],"description":"Number of rows inserted by queries in this database","metric_name":"ccp_stat_database_tup_inserted","static_attributes":{"server":"localhost:5432"},"value_column":"tup_inserted"},{"attribute_columns":["dbname"],"description":"Number of rows returned by queries in this database","metric_name":"ccp_stat_database_tup_returned","static_attributes":{"server":"localhost:5432"},"value_column":"tup_returned"},{"attribute_columns":["dbname"],"description":"Number of rows updated by queries in this database","metric_name":"ccp_stat_database_tup_updated","static_attributes":{"server":"localhost:5432"},"value_column":"tup_updated"},{"attribute_columns":["dbname"],"description":"Number of transactions in this database that have been committed","metric_name":"ccp_stat_database_xact_commit","static_attributes":{"server":"localhost:5432"},"value_column":"xact_commit"},{"attribute_columns":["dbname"],"description":"Number of transactions in this database that have been rolled back","metric_name":"ccp_stat_database_xact_rollback","static_attributes":{"server":"localhost:5432"},"value_column":"xact_rollback"}],"sql":"SELECT s.datname AS dbname , s.xact_commit , s.xact_rollback , s.blks_read , s.blks_hit , s.tup_returned , s.tup_fetched , s.tup_inserted , s.tup_updated , s.tup_deleted , s.conflicts , s.temp_files , s.temp_bytes , s.deadlocks FROM pg_catalog.pg_stat_database s JOIN pg_catalog.pg_database d ON d.datname = s.datname WHERE d.datistemplate = false;\n"},{"metrics":[{"description":"Value of checksum monitoring status for pg_catalog.pg_hba_file_rules (pg_hba.conf).\n0 = valid config. 1 = settings changed. \nSettings history is available for review in the table `monitor.pg_hba_checksum`.\nTo reset current config to valid after alert, run monitor.pg_hba_checksum_set_valid(). Note this will clear the history table.\n","metric_name":"ccp_pg_hba_checksum","value_column":"status"}],"sql":"SELECT monitor.pg_hba_checksum() AS status;"}] +[{"metrics":[{"attribute_columns":["dbname"],"description":"Database size in bytes","metric_name":"ccp_database_size_bytes","static_attributes":{"server":"localhost:5432"},"value_column":"bytes"}],"sql":"SELECT datname as dbname , pg_database_size(datname) as bytes FROM pg_catalog.pg_database WHERE datistemplate = false;\n"},{"metrics":[{"description":"Count of sequences that have reached greater than or equal to 75% of their max available numbers.\nFunction monitor.sequence_status() can provide more details if run directly on system.\n","metric_name":"ccp_sequence_exhaustion_count","static_attributes":{"server":"localhost:5432"},"value_column":"count"}],"sql":"SELECT count(*) AS count FROM (\n SELECT CEIL((s.max_value-min_value::NUMERIC+1)/s.increment_by::NUMERIC) AS slots\n , CEIL((COALESCE(s.last_value,s.min_value)-s.min_value::NUMERIC+1)/s.increment_by::NUMERIC) AS used\n FROM pg_catalog.pg_sequences s\n) x WHERE (ROUND(used/slots*100)::int) \u003e 75;\n"},{"metrics":[{"attribute_columns":["dbname"],"description":"Number of times disk blocks were found already in the buffer cache, so that a read was not necessary","metric_name":"ccp_stat_database_blks_hit","static_attributes":{"server":"localhost:5432"},"value_column":"blks_hit"},{"attribute_columns":["dbname"],"description":"Number of disk blocks read in this database","metric_name":"ccp_stat_database_blks_read","static_attributes":{"server":"localhost:5432"},"value_column":"blks_read"},{"attribute_columns":["dbname"],"description":"Number of queries canceled due to conflicts with recovery in this database","metric_name":"ccp_stat_database_conflicts","static_attributes":{"server":"localhost:5432"},"value_column":"conflicts"},{"attribute_columns":["dbname"],"description":"Number of deadlocks detected in this database","metric_name":"ccp_stat_database_deadlocks","static_attributes":{"server":"localhost:5432"},"value_column":"deadlocks"},{"attribute_columns":["dbname"],"description":"Total amount of data written to temporary files by queries in this database","metric_name":"ccp_stat_database_temp_bytes","static_attributes":{"server":"localhost:5432"},"value_column":"temp_bytes"},{"attribute_columns":["dbname"],"description":"Number of rows deleted by queries in this database","metric_name":"ccp_stat_database_temp_files","static_attributes":{"server":"localhost:5432"},"value_column":"temp_files"},{"attribute_columns":["dbname"],"description":"Number of rows deleted by queries in this database","metric_name":"ccp_stat_database_tup_deleted","static_attributes":{"server":"localhost:5432"},"value_column":"tup_deleted"},{"attribute_columns":["dbname"],"description":"Number of rows fetched by queries in this database","metric_name":"ccp_stat_database_tup_fetched","static_attributes":{"server":"localhost:5432"},"value_column":"tup_fetched"},{"attribute_columns":["dbname"],"description":"Number of rows inserted by queries in this database","metric_name":"ccp_stat_database_tup_inserted","static_attributes":{"server":"localhost:5432"},"value_column":"tup_inserted"},{"attribute_columns":["dbname"],"description":"Number of rows returned by queries in this database","metric_name":"ccp_stat_database_tup_returned","static_attributes":{"server":"localhost:5432"},"value_column":"tup_returned"},{"attribute_columns":["dbname"],"description":"Number of rows updated by queries in this database","metric_name":"ccp_stat_database_tup_updated","static_attributes":{"server":"localhost:5432"},"value_column":"tup_updated"},{"attribute_columns":["dbname"],"description":"Number of transactions in this database that have been committed","metric_name":"ccp_stat_database_xact_commit","static_attributes":{"server":"localhost:5432"},"value_column":"xact_commit"},{"attribute_columns":["dbname"],"description":"Number of transactions in this database that have been rolled back","metric_name":"ccp_stat_database_xact_rollback","static_attributes":{"server":"localhost:5432"},"value_column":"xact_rollback"}],"sql":"SELECT s.datname AS dbname , s.xact_commit , s.xact_rollback , s.blks_read , s.blks_hit , s.tup_returned , s.tup_fetched , s.tup_inserted , s.tup_updated , s.tup_deleted , s.conflicts , s.temp_files , s.temp_bytes , s.deadlocks FROM pg_catalog.pg_stat_database s JOIN pg_catalog.pg_database d ON d.datname = s.datname WHERE d.datistemplate = false;\n"},{"metrics":[{"description":"Value of checksum monitoring status for pg_catalog.pg_hba_file_rules (pg_hba.conf).\n0 = valid config. 1 = settings changed. \nSettings history is available for review in the table `monitor.pg_hba_checksum`.\nTo reset current config to valid after alert, run monitor.pg_hba_checksum_set_valid(). Note this will clear the history table.\n","metric_name":"ccp_pg_hba_checksum","static_attributes":{"server":"localhost:5432"},"value_column":"status"}],"sql":"SELECT monitor.pg_hba_checksum() AS status;"}] diff --git a/internal/collector/postgres_5m_metrics.yaml b/internal/collector/postgres_5m_metrics.yaml index 7de7d94caa..95764fe3e1 100644 --- a/internal/collector/postgres_5m_metrics.yaml +++ b/internal/collector/postgres_5m_metrics.yaml @@ -150,3 +150,5 @@ 0 = valid config. 1 = settings changed. Settings history is available for review in the table `monitor.pg_hba_checksum`. To reset current config to valid after alert, run monitor.pg_hba_checksum_set_valid(). Note this will clear the history table. + static_attributes: + server: "localhost:5432"