Hace unos días me encontré con la necesidad de contar con una herramienta rápida para chequear las sesiones actualmente corriendo en una base de datos PostgreSQL. La idea era contar con una herramienta para monitorear por consola y adicionalmente poder integrarlo al servidor Zabbix que actualmente tengo corriendo para monitorear todos los servidores.

Como no encontre nada simple decidí hacer un pequeñisimo script para pode monitorear algunas variables. La versión inicial monitorea:

  • Cantidad de sesiones/conexiones
  • Cantidad de sessiones corriendo alguna consulta SQL
  • Tiempo que llevan las consultas corriendo
  • Listado general de consultas corriendo
  • Informacion detallada por cada pid de Postgresql (Queries)
  • El código se explica por si solo y es bastante simple.

    #!/bin/bash
    #
    # Script para monitoreo de servidor PostgreSQL
    #
    # @author Emiliano Romero <emilianoromero@gmail.com>
    # @www about.me/reflex
     
    # Config Vars
    DEFAULTDB="db3g"
    DEFAULTUSER="postgres"
    DEFAULTPASSWD=""
    # Static Vars
    VERSION="0.1rc1"
    if [ "$OUTPUTFORMAT" == "" ]; then
    	OUTPUTFORMAT=1
    fi
    ######################
    # FUNTIONS           #
    ######################
    # Help
    function showhelp {
            echo "PGMon $VERSION"
    	echo "Usage PGMon [MonitorType] [TypeOptions]"
    	echo "   -s: Sessions Monitor"
    	echo "       -n: Shows number of open connections"
    	echo "       -b: Shows number of busy connections"
    	echo "       -d: Shows list of running queries"
    	echo "       -p <pid>: Shows detailed information about <pid> PostgreSQL process"
    	echo "   -h: Shows this help information"
    	echo " "
    	echo "Examples: pgmon -s -d"
    	echo "          pgmon -s -p 1234"
    }
    # Sessions Monitor
    function sessionmon {
    	case $2 in
    	# Count sessions
    	-n)
    		sessionmon_count
    	;;
    	-b)
    		sessionmon_running
    	;;
    	-d)
    		sessionmon_detail $*
    	;;
    	-p)
    		sessionmon_pid $*
    	;;
    	*)
    		showhelp
    	;;
    	esac
    }
    # Sessions Total Count
    function sessionmon_count {
    	sesscount=$(SQLExec 'SELECT COUNT(*) FROM "pg_stat_activity";')
    	formatecho "Sessions Number:" $sesscount
    }
    # Sessions Busy Count
    function sessionmon_running {
    	sesscount=$(SQLExec 'SELECT COUNT(*) FROM "pg_stat_activity" where "current_query"!='"'"'<IDLE>'"'"';')	
    	formatecho "Busy Sessions:" $sesscount
    }
    # Sessions Detail
    function sessionmon_detail {
    	cols=$(tput cols)
    	sqllen=$(($cols - 60))
    	if [ $sqllen -lt 1 ]; then
    		sqllen=1
    	fi
    	SQLExec_formated 'SELECT "datname" as database,"procpid" as pid,"usename", substring(replace(regexp_replace("current_query",E'"'"'/\\*.*\\*/'"'"','"'"''"'"'),E'"'"'\n'"'"','"'"''"'"') from 1 for '"$sqllen"') as query, date_trunc('"'"'seconds'"'"', (now() - "query_start")) as running, "client_addr" as ip from "pg_stat_activity" where "current_query" != '"'"'<IDLE>'"'"' order by running desc;'
    }
    # Sessions PID Details
    function sessionmon_pid {
    	COLOR_TITLE="\e[1;37m"
    	COLOR_VALUE="\e[0;37m"
    	DATA=$(SQLExec 'SELECT *,date_trunc('"'"'seconds'"'"', (now() - "query_start")) as running FROM "pg_stat_activity" where "procpid"='"$3"'')
    	#datid|datname|procpid|usesysid|usename|current_query|waiting|xact_start|query_start|backend_start|client_addr|client_port
    	# Split
    	IFS="|"; declare -a Array=($DATA)
    	datname=${Array[1]}
    	procpid=${Array[2]}
    	usename=${Array[4]}
    	current_query=${Array[5]}
    	waiting=${Array[6]}
    	xact_start=${Array[7]}
    	query_start=${Array[8]}
    	backend_start=${Array[9]}
    	client_addr=${Array[10]}
    	client_port=${Array[11]}
    	running=${Array[12]}
    	echo -e "\e[1mPostgreSQL PID \e[1;32m$procpid \e[0m\e[1mdetails\e[0m"
    	echo -e "${COLOR_TITLE}Username: ${COLOR_VALUE}$usename \t\t${COLOR_TITLE}IP: ${COLOR_VALUE}$client_addr:$client_port"
    	echo -e "${COLOR_TITLE}Database: ${COLOR_VALUE}$datname"
    	echo -e "${COLOR_TITLE}Waiting: ${COLOR_VALUE}$waiting"
    	echo -e "${COLOR_TITLE}Connection Start: ${COLOR_VALUE}$backend_start"
    	echo -e "${COLOR_TITLE}Running: \e[1;31m$running"
    	echo -e "${COLOR_TITLE}SQL Query ${COLOR_VALUE}"
    	echo -e "$current_query"
    }
    #SQLExec
    function SQLExec {
    	echo "$1" | psql -tA -U $DEFAULTUSER $DEFAULTDB
     
    }
    # SQLExec for printing
    function SQLExec_formated {
    	echo "$1" | psql -U $DEFAULTUSER $DEFAULTDB
    }
    # FormatEcho <text> <value>
    function formatecho {
    	if [ $OUTPUTFORMAT -eq 0 ]; then
    		echo $2
    	else
    		echo "$1 $2"
    	fi
    }
     
    ####################
    #      MAIN        #
    ####################
    case $1 in
    	-s)
    		sessionmon $*
    	;;
    	-h|*)
    		showhelp
    	;;
    esac

    Si necesitamos que el script largue los resultados de la cantidad de sesiones limpio (Sin titulo), simplemente seteamos la variable OUTPUTFORMAT=0.

    OUTPUTFORMAT=0 ./pgmon -s -b

    En estos días subo un nuevo Post para integrarlo con zabbix.