From a9f071d194148c99bcffbbf01c06cc69d6d96fe0 Mon Sep 17 00:00:00 2001
From: "Hahn Axel (hahn)" <axel.hahn@unibe.ch>
Date: Wed, 7 Jun 2023 14:19:01 +0200
Subject: [PATCH] first public version for postgresql check

---
 check_psqlserver | 146 ++++++++++++++++++++++++++++++++---------------
 1 file changed, 99 insertions(+), 47 deletions(-)

diff --git a/check_psqlserver b/check_psqlserver
index 275a17f..6c4a3b4 100755
--- a/check_psqlserver
+++ b/check_psqlserver
@@ -1,8 +1,6 @@
 #!/bin/bash
 # ======================================================================
 #
-# !!! WORK IN PROGRESS !!! DO NOT USE YET !!!
-#
 # Check PSQL SERVER
 #
 # requirements:
@@ -10,29 +8,27 @@
 #
 # installation:
 # - execute check_psqlserver -i
-#
+# 
+# ----------------------------------------------------------------------
+# Postgresql docs:
+# https://www.postgresql.org/docs/current/monitoring-stats.html
 # ----------------------------------------------------------------------
-# 2023-06-xx  v0.0  <axel.hahn@unibe.ch>
+# 2023-06-07  v0.2  <axel.hahn@unibe.ch>
 # ======================================================================
 
 
 . $(dirname $0)/inc_pluginfunctions
 self_APPNAME=$( basename $0 | tr [:lower:] [:upper:] )
-self_APPVERSION=0.1
-
-# --- set HOME
-HOME=/etc/icinga2-passive-client
-# HOME=/etc/icingaclient
+self_APPVERSION=0.2
 
 # --- other vars...
-cfgfile=$HOME/.psql.conf
+cfgfile=/etc/icingaclient/.psql.conf
 myuser=icingamonitor
 
 # new line
 NL="
 "
 
-lastvalue=
 out=" "
 
 # ----------------------------------------------------------------------
@@ -46,6 +42,7 @@ function _uninstall(){
     unset PGHOST
     unset PGUSER
     unset PGPASSWORD
+    unset PGDATABASE
 }
 
 # (re)install database user for monitoring
@@ -85,6 +82,8 @@ function _install(){
 export PGUSER=${myuser}
 export PGPASSWORD=${mypw}
 export PGHOST=localhost
+
+# set default database because a user db won't be created
 export PGDATABASE=postgres
 EOF
     ls -l $cfgfile
@@ -94,6 +93,7 @@ EOF
     fi
 }
 
+# show help
 function _usage(){
     local _self=$( basename $0 )
     cat <<EOH
@@ -101,8 +101,6 @@ ______________________________________________________________________
 
 ${self_APPNAME} :: v${self_APPVERSION}
 
-THIS IS AN PRE ALPHA VERSION - DO NOT USE THIS
-
 (c) Institute for Medical Education - Univerity of Bern
 Licence: GNU GPL 3
 ______________________________________________________________________
@@ -117,7 +115,13 @@ OPTIONS:
 
 PARAMETERS:
   -m  method; valid methods are:
-      dbstat          first implmenetation test
+      activity        running processes and queries
+      dbrows          Count of database row actions
+      conflicts       Detected conflicts from pg_stat_database_conflicts
+      diskblock       Count of diskblocks physically read or coming from cache
+      problems        Problems and troublemakers
+      replication     Replication status (table output only)
+      transactions    Count of transactions over all databases
 
 EXAMPLES:
   $_self -i
@@ -126,30 +130,31 @@ EXAMPLES:
 EOH
 }
 
-function renderCounts(){
-  local _query="$1"
-  local _out=$( psql -c "${_query}")
-  # out+=$( echo "DEBUG: _query=${_query}${NL}" )
-  # echo "DEBUG: _out="; echo "${_out}"
-
-  local _iCounter=0
-  typeset -i _iCounter
-
-  local _header
-  _header=$( echo "${_out}" | head -1 | tr -d ' ')
-  local _data
-  _data=$( echo "${_out}" | head -3 | tail -1 | tr -d ' ')
-
-  # echo "DEBUG: _header=${_header}"
+# render incremental counters from integer results of a given sql query
+# global string  out  output of check
+# param  string       database query
+function renderCounters(){
+  local _query;      _query="$1"
+  local _out;        _out=$( psql -c "${_query}")
+  local _iCounter;   typeset -i _iCounter=0
+  local _header;     _header=$( echo "${_out}" | head -1 | tr -d ' ')
+  local _data;       _data=$( echo "${_out}" | head -3 | tail -1 | tr -d ' ')
+  local _sDeltaUnit; _sDeltaUnit=sec
+  local _iSpeed;     typeset -i _iSpeed=0
+  local _sStoreid;   _sStoreid=$( md5sum <<< "${_query}" | awk '{ print $1 }' )
+  local _iValue;     typeset -i _iValue
+
+  # read psql result and put columns and values to an array
   IFS="|"
   read -ra aCols <<< "$_header"
   read -ra aVals <<< "$_data"
+
   for sColumn in ${aCols[*]}
   do
-    local value=${aVals[$_iCounter]}
-    # echo "DEBUG: $sColumn = $value"
-    out+=$( printf "%25s: %10s \n" "${sColumn}" "${value}${NL}")
-    ph.perfadd "${sColumn}" "${value}"
+    _iValue=${aVals[$_iCounter]}
+    _iSpeed=$( ph.perfdeltaspeed "psql-${sColumn}-${_sStoreid}" ${_iValue} sec $_sDeltaUnit)
+    out=$out$(printf "%25s: %10s %s \n" "${sColumn}" "${_iValue}" "... delta = ${_iSpeed} per $_sDeltaUnit${NL}")
+    ph.perfadd "${sColumn}"   "${_iSpeed}"
     _iCounter+=1
   done
 }
@@ -175,8 +180,6 @@ if [ $bOptInstall -eq 1 -a "$( whoami )" = "root" ]; then
         ph.status "SKIP installation. config file already exists: $cfgfile."
         ph.exit
     fi
-    HOME=/root
-    export HOME
 
     _uninstall
     _install
@@ -187,7 +190,6 @@ fi
 
 # --- uninstall
 if [ $bOptUninstall -eq 1 -a "$( whoami )" = "root" ]; then
-    HOME=/root
 
     _uninstall
     rm -f $cfgfile
@@ -208,21 +210,71 @@ fi
 sMode=$(ph.getValueWithParam '' m "$@")
 
 case "${sMode}" in
-
-    "dbstat")
-        descr="statistics over all databases"
-        renderCounts "select \
-            sum(xact_commit)   as commit,   \
-            sum(xact_rollback) as rollback, \
-            sum(blks_read)     as blkread,  \
-            sum(blks_hit)      as blkhit    \
+    "activity")
+        _out=$( psql -c "select pid,usename,state,query,backend_type,backend_start from pg_stat_activity" )
+        typeset -i iQTotal;  iQTotal=$(  tail -1 <<< "$_out"  | cut -f 1 -d ' ' | tr -d '(' )
+        typeset -i iQActive; iQActive=$( awk '{ print $5 }' <<< "$_out" | grep -c "active"  )
+
+        descr="Running total: $iQTotal ... active: $iQActive"
+        out="${_out}${NL}"
+        ph.perfadd "running-total"  "${iQTotal}"
+        ph.perfadd "running-active" "${iQActive}"
+        ;;
+    "conflicts")
+        descr="Detected conflicts (from pg_stat_database_conflicts)"
+        renderCounters "select                          \
+            sum(confl_tablespace)  as confltablespace,  \
+            sum(confl_lock)        as confllock,        \
+            sum(confl_snapshot)    as conflsnapshot,    \
+            sum(confl_bufferpin)   as conflbufferpin,   \
+            sum(confl_deadlock)    as confldeadlock     \
+            from pg_stat_database_conflicts "
+          ;;
+    "dbrows")
+        descr="Count of database row actions (from pg_stat_database)"
+        renderCounters "select               \
+            sum(tup_returned)     as return, \
+            sum(tup_fetched)      as fetch,  \
+            sum(tup_inserted)     as insert, \
+            sum(tup_updated)      as update, \
+            sum(tup_deleted)      as delete  \
+            from pg_stat_database "
+          ;;
+    "diskblock")
+        descr="Count of diskblocks physically read or coming from cache (from pg_stat_database)"
+        renderCounters "select             \
+            sum(blks_read)     as read,    \
+            sum(blks_hit)      as cached   \
             from pg_stat_database "
           ;;
-    "queries")
-        # psql -c "select * from pg_stat_activity "
-        # psql -c "select * from pg_stat_statements " -> av psql v11
+    "problems")
+        descr="Problems and troublemakers (from pg_stat_database)"
+        renderCounters "select                           \
+            sum(conflicts)          as conflicts,        \
+            sum(deadlocks)          as deadlocks,        \
+            sum(checksum_failures)  as checksumfailures, \
+            sum(temp_files)         as tmpfiles,         \
+            sum(temp_bytes)         as tmpbytes          \
+            from pg_stat_database "
+          ;;
+    "replication")
+        _out=$( psql -c "select * from pg_stat_replication" )
+        if tail -1 <<< "$_out"  | grep "(0 rows)" >/dev/null ; then
+            descr="No data in pg_stat_replication - this is no slave."
+            out=""
+        else
+            descr="status (from pg_stat_replication)"
+            out="${_out}${NL}"
+        fi
         ;;
 
+    "transactions")
+        descr="Count of transactions over all databases (from pg_stat_database)"
+        renderCounters "select             \
+            sum(xact_commit)   as commit,  \
+            sum(xact_rollback) as rollback \
+            from pg_stat_database "
+          ;;
     *)
         echo ERRROR: [${sMode}] is an INVALID mode
         _usage
-- 
GitLab