Cuántas veces nos hemos encontrado con una integración de monitorización cuando entra en juego DG?
Pues lo voy a poner fácil. Lo hacemos en un script con las recomendaciones de Oracle. La versión con la que trabajo es 19c, importante.
En este caso está planificado en nagios, pero sería perfectamente válido para otras plataformas como zabbix. Al final lo que importa es la salida ( Ok, Warning, Critical) y/o el exit code.
La idea es que pasándole el SID pueda distinguir si es Primaria o Standby y poder planificar el script para Standby y Primaria y que solo salte cuando se cumpla el rol para el chequeo.
Las alertas query_apply_lag y query_transport_lag están parametrizadas para saltar a los 5 minutos, es ajustable al entorno.
Os presento uno de los Carli-scripts que os facilitará la vida. Empezamos?
check_dg.sh
check_dg.sh <ORACLE_SID> <query_archive_dest|query_gaps|query_errors|query_loging|query_apply_lag|query_transport_lag|query_datafiles_offline|query_mrp
Tiene buena pinta verdad? Espera que invoquemos con el SID y el chequeo concreto.
En qué me baso?
Monitoring Oracle Data Guard Configuration Health Using SQL 19c
Para ello he desarollado el siguiente script:
[nagios@rac-prueba-001 ~]$ cat /home/oracle/check_dg.sh
#!/bin/bash
# Verificar que se haya pasado ORACLE_SID como argumento
if [ "$#" -ne 2 ]; then
echo "Uso: $0 <ORACLE_SID> <query_archive_dest|query_gaps|query_errors|query_loging|query_apply_lag|query_transport_lag|query_datafiles_offline|query_mrp>"
exit 1
fi
#Variables entorno de BBDD
ORACLE_SID=$1
ORAENV_ASK=NO
. oraenv -s
#Variable chequeo
OPCION_CHECK=$2
# Configuración de conexión
dbname=$ORACLE_SID # El nombre de la base de datos será el mismo que ORACLE_SID
dbuser='system'
dbpass='Temporal01'
# Función para ejecutar un comando SQL y devolver los resultados
ejecutar_sqlplus() {
local sql=$1
$ORACLE_HOME/bin/sqlplus -s "$dbuser/$dbpass@$dbname" <<EOF
SET PAGESIZE 0
SET FEEDBACK OFF
SET VERIFY OFF
SET HEADING OFF
SET ECHO OFF
$sql
EXIT;
EOF
}
# Verificar si la base de datos es primaria
query_role=$(cat <<EOF
SELECT DATABASE_ROLE FROM v\$database;
EOF
)
#################### STANDBY ##########################
# Consulta de chequeo lag apply
query_apply_lag=$(cat <<EOF
SELECT name || ': ' || max(value)
FROM gv\$dataguard_stats
WHERE name = 'apply lag'
AND value > '+00 00:05:00'
GROUP BY NAME;
EOF
)
# Consulta de chequeo lag transport
query_transport_lag=$(cat <<EOF
SELECT name || ': ' || max(value)
FROM gv\$dataguard_stats
WHERE name = 'transport lag'
AND value > '+00 00:05:00'
GROUP BY NAME;
EOF
)
# Data file check (offline files or files that are not accessible)
query_datafiles_offline=$(cat <<EOF
select 'Hay ' || count(*) || ' datafiles en estado offline'
from v\$datafile_header
where status ='OFFLINE'
or ERROR is not null
having count(*)>0;
EOF
)
# Verify that the Media Recovery Process is currently running. Tiene que devolver fila
query_mrp=$(cat <<EOF
select count(*)
from gv\$managed_standby
where process like 'MRP%'
having count(*)>0;
EOF
)
#################### PRIMARIA ########################
# Consulta de chequeo errores arhive dest
query_archive_dest=$(cat <<EOF
WITH AggregatedData AS (
SELECT inst_id, substr(error,1,9) error
from gv\$archive_dest_status
where type='PHYSICAL'
and status!='VALID'
)
SELECT 'Instancia: ' || LISTAGG(inst_id, ',') WITHIN GROUP (ORDER BY inst_id) || ' Errores: ' || LISTAGG(error, ',') WITHIN GROUP (ORDER BY error) AS result
FROM AggregatedData
HAVING COUNT(*) > 0;
EOF
)
# Consulta de chequeo gaps
query_gaps=$(cat <<EOF
select LISTAGG(inst_id, ',') WITHIN GROUP (ORDER BY inst_id) || ' ' || database_mode || ' ' || recovery_mode || ' ' || gap_status
from gv\$archive_dest_status
where type='PHYSICAL'
and gap_status !='NO GAP'
group by database_mode,recovery_mode, gap_status;
EOF
)
# severe Data Guard event occurred in the last day
query_errors=$(cat <<EOF
WITH AggregatedData AS (
SELECT inst_id, COUNT(*) AS count
FROM gv\$dataguard_status
WHERE severity IN ('Error', 'Fatal')
AND timestamp > (sysdate - 1)
GROUP BY inst_id
)
SELECT 'Instancia: ' || LISTAGG(inst_id, ',') WITHIN GROUP (ORDER BY inst_id) || ' Numero errores: ' || LISTAGG(count, ',') WITHIN GROUP (ORDER BY inst_id) AS result
FROM AggregatedData
HAVING COUNT(*) > 0;
EOF
)
# Check if any NOLOGGING activity occurred on the primary database in the last day
query_loging=$(cat <<EOF
SELECT CASE
WHEN COUNT(*) > 0 THEN 'Hay datafiles con NOLOGGING activity en el último día. File ID: ' ||
LISTAGG(file#, ',') WITHIN GROUP (ORDER BY file#)
ELSE NULL
END AS result
FROM v\$datafile
WHERE unrecoverable_time > (sysdate - 1);
EOF
)
role_output=$(ejecutar_sqlplus "$query_role")
if [ "$role_output" = "PRIMARY" ]; then
case $OPCION_CHECK in
query_archive_dest)
check_output=$(ejecutar_sqlplus "$query_archive_dest")
if [ -n "$check_output" ]; then
echo "[CRITICAL] $check_output"
exit 2
fi
;;
query_gaps)
check_output=$(ejecutar_sqlplus "$query_gaps")
if [ -n "$check_output" ]; then
echo "[CRITICAL] $check_output"
exit 2
fi
;;
query_errors)
check_output=$(ejecutar_sqlplus "$query_errors")
if [ -n "$check_output" ]; then
echo "[CRITICAL] $check_output"
exit 2
fi
;;
query_loging)
check_output=$(ejecutar_sqlplus "$query_loging")
if [ -n "$check_output" ]; then
echo "[WARNING] $check_output"
exit 1
fi
;;
query_datafiles_offline)
check_output=$(ejecutar_sqlplus "$query_datafiles_offline")
if [ -n "$check_output" ]; then
echo "[WARNING] $check_output"
exit 1
fi
;;
esac
fi
if [ "$role_output" = "PHYSICAL STANDBY" ]; then
case $OPCION_CHECK in
query_apply_lag)
check_output=$(ejecutar_sqlplus "$query_apply_lag")
if [ -n "$check_output" ]; then
echo "[CRITICAL] $check_output"
exit 2
fi
;;
query_transport_lag)
check_output=$(ejecutar_sqlplus "$query_transport_lag")
if [ -n "$check_output" ]; then
echo "[CRITICAL] $check_output"
exit 2
fi
;;
query_datafiles_offline)
check_output=$(ejecutar_sqlplus "$query_datafiles_offline")
if [ -n "$check_output" ]; then
echo "[WARNING] $check_output"
exit 1
fi
;;
query_mrp)
check_output=$(ejecutar_sqlplus "$query_mrp")
if [ -n "$check_output" ]; then
echo "[OK]"
exit 0
else
echo "[CRITICAL]. No hay procesos activos de replicación."
exit 2
fi
;;
esac
fi
echo "[OK]"
exit 0
Qué esperamos? Devolverá un OK si todo está en orden, WARNING o CRITICAL junto con la información asociada en una sola línea cuando no es así. Es totalmente customizable.
Lo pruebas y me cuentas?
[usuario_monitorizacion@rac-prueba-001 ~]$ /home/oracle/check_dg.sh cdbpro query_archive_dest
[OK]