011: observability - pg_stat_statements, slow-log, io timing
preload pg_stat_statements (+extension in iwanhae/postgres DBs), log_min_duration_statement=500ms, track_io_timing=on.
This commit is contained in:
@@ -0,0 +1,93 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# 011-postgres-observability - Turn on the instrumentation that any future
|
||||||
|
# tuning depends on (A-tier of the 2026-08 tuning review).
|
||||||
|
#
|
||||||
|
# shared_preload_libraries = 'pg_stat_statements' query stats (restart)
|
||||||
|
# track_io_timing = on pg_stat_io timing, cheap on modern Linux
|
||||||
|
# log_min_duration_statement = 500ms slow queries land in the server log
|
||||||
|
#
|
||||||
|
# pg_stat_statements extension is created in `iwanhae` (app db) and
|
||||||
|
# `postgres` (admin db). Inspect with:
|
||||||
|
# SELECT calls, round(total_exec_time::numeric,1) ms, rows, query
|
||||||
|
# FROM pg_stat_statements ORDER BY total_exec_time DESC LIMIT 10;
|
||||||
|
# up: write drop-in; restart only if the lib is not yet loaded; extensions
|
||||||
|
# down: drop extensions (loses collected stats), remove drop-in, restart
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
PGBIN=/etc/postgresql/18/main
|
||||||
|
CONF=$PGBIN/conf.d/011-postgres-observability.conf
|
||||||
|
CLUSTER=$(pg_lsclusters --no-header | awk 'NR==1{print $1"/"$2}')
|
||||||
|
DBS=(iwanhae postgres)
|
||||||
|
|
||||||
|
pg() { runuser -u postgres -- psql -d postgres -v ON_ERROR_STOP=1 -tAc "$1"; }
|
||||||
|
|
||||||
|
lib_loaded() { pg 'SHOW shared_preload_libraries' | grep -q pg_stat_statements; }
|
||||||
|
|
||||||
|
write_conf() {
|
||||||
|
install -d -m 755 "$PGBIN/conf.d"
|
||||||
|
cat > "$CONF" <<'EOF'
|
||||||
|
# managed by sysmig 011-postgres-observability
|
||||||
|
shared_preload_libraries = 'pg_stat_statements'
|
||||||
|
track_io_timing = on
|
||||||
|
log_min_duration_statement = 500ms
|
||||||
|
EOF
|
||||||
|
chown root:postgres "$CONF"
|
||||||
|
chmod 644 "$CONF"
|
||||||
|
}
|
||||||
|
|
||||||
|
case "${1:-}" in
|
||||||
|
up)
|
||||||
|
write_conf
|
||||||
|
if lib_loaded; then
|
||||||
|
pg_ctlcluster "$CLUSTER" reload
|
||||||
|
echo " cluster reloaded (pg_stat_statements already loaded)"
|
||||||
|
else
|
||||||
|
pg_ctlcluster "$CLUSTER" restart
|
||||||
|
pg_isready -q
|
||||||
|
echo " cluster restarted to load pg_stat_statements"
|
||||||
|
fi
|
||||||
|
for db in "${DBS[@]}"; do
|
||||||
|
runuser -u postgres -- psql -d "$db" -v ON_ERROR_STOP=1 -qc \
|
||||||
|
'CREATE EXTENSION IF NOT EXISTS pg_stat_statements'
|
||||||
|
done
|
||||||
|
lib_loaded || { echo "FATAL: pg_stat_statements not loaded" >&2; exit 1; }
|
||||||
|
[[ $(pg 'SHOW track_io_timing') == on ]] || { echo "FATAL: track_io_timing not on" >&2; exit 1; }
|
||||||
|
[[ $(pg 'SHOW log_min_duration_statement') == '500ms' ]] || { echo "FATAL: log_min_duration_statement wrong" >&2; exit 1; }
|
||||||
|
echo " extension created in: ${DBS[*]}"
|
||||||
|
;;
|
||||||
|
status)
|
||||||
|
if [[ $EUID -eq 0 ]]; then
|
||||||
|
q() { runuser -u postgres -- psql -d "$1" -v ON_ERROR_STOP=1 -tAc "$2"; }
|
||||||
|
elif psql -d postgres -tAc 'SELECT 1' >/dev/null 2>&1; then
|
||||||
|
q() { psql -d "$1" -v ON_ERROR_STOP=1 -tAc "$2"; }
|
||||||
|
else
|
||||||
|
echo "? needs root or peer DB access to verify"
|
||||||
|
exit 2
|
||||||
|
fi
|
||||||
|
[[ -f $CONF ]] || { echo "DRIFT drop-in $CONF missing"; exit 1; }
|
||||||
|
if ! q postgres 'SHOW shared_preload_libraries' | grep -q pg_stat_statements; then
|
||||||
|
echo "DRIFT pg_stat_statements not preloaded"; exit 1
|
||||||
|
fi
|
||||||
|
[[ $(q postgres 'SHOW track_io_timing') == on ]] || { echo "DRIFT track_io_timing off"; exit 1; }
|
||||||
|
[[ $(q postgres 'SHOW log_min_duration_statement') == '500ms' ]] || { echo "DRIFT log_min_duration_statement"; exit 1; }
|
||||||
|
for db in "${DBS[@]}"; do
|
||||||
|
[[ $(q "$db" "SELECT count(*) FROM pg_extension WHERE extname='pg_stat_statements'") -ge 1 ]] \
|
||||||
|
|| { echo "DRIFT extension missing in $db"; exit 1; }
|
||||||
|
done
|
||||||
|
echo "OK pg_stat_statements + slow-log(500ms) + io timing"
|
||||||
|
;;
|
||||||
|
down)
|
||||||
|
for db in "${DBS[@]}"; do
|
||||||
|
runuser -u postgres -- psql -d "$db" -v ON_ERROR_STOP=1 -qc \
|
||||||
|
'DROP EXTENSION IF EXISTS pg_stat_statements' \
|
||||||
|
|| { echo "cannot drop extension in $db (in use?) - retry later" >&2; exit 1; }
|
||||||
|
done
|
||||||
|
rm -f "$CONF"
|
||||||
|
if lib_loaded; then
|
||||||
|
pg_ctlcluster "$CLUSTER" restart
|
||||||
|
echo " extensions dropped, drop-in removed, cluster restarted to unload lib"
|
||||||
|
else
|
||||||
|
echo " extensions dropped, drop-in removed (lib was not loaded)"
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
esac
|
||||||
Reference in New Issue
Block a user