Script para generar exports desde windows logando en el Event Log

Una entrada rápida para dummies sobre el export en windows.
Habitualmente la monitorizacion de los exports en plataformas windows es mas compleja que en los linux, esto es debido a que en muchos casos los equipos de gestion de los servidores windows se ciñen a la monitorizacion del visor de eventos no queriendo/pudiendo hacerlo de un fichero de texto plano como es el fichero de log del export.

¿Como solucionamos esto?

Aquí hay un pequeño script que es capaz de llevar a cabo un export y logar en el visor de sucesos el comienzo y le estado final

ECHO OFF
setlocal ENABLEDELAYEDEXPANSION
:: Directorio desde el cual vamos a ejecutar nuestro .bat 
SET SCRIPTDIR=O:\TAREAS\BACKUP
SET ORACLE_SID=%1
SET PARALLELISM=%2
SET MYFILE=DPEXP_%ORACLE_SID%_%%U.dmp
SET MYLOG=DPEXP_%ORACLE_SID%.log
:: RUTA tiene el valor del oracle directory EXPORTS 
SET RUTA=\\SERVIDOR\DIRECTORIO
SET export_log=%RUTA%\DPEXP_%ORACLE_SID%.log

if "%1"=="" goto uso
if "%2"=="" goto SET PARALLELISM=1


EVENTCREATE /T INFORMATION /SO  EXPORT.%ORACLE_SID% /ID 36 /L APPLICATION /D "Comienza el export  de %ORACLE_SID% con paralelismo %PARALLELISM% y log %export_log%"
cd /d %SCRIPTDIR%
del %export_log%
:: Eliminamos los ficheros anteriores por seguridad (a pesar de tener el reuse)

expdp USER/PASS DIRECTORY=EXPORTS  DUMPFILE=%MYFILE% PARALLEL=%PARALLELISM%  LOGFILE=DPEXP_%ORACLE_SID%.log reuse_dumpfiles=Y FULL=Y  METRICS=Y  
SET CORRECTO=%ERRORLEVEL%

IF %CORRECTO% GTR 0  goto error 
IF "%CORRECTO%"=="0"  goto OK

:uso 
echo "USO exportar.bat  SID PARALELISMO "
SET CORRECTO=2
goto end

:error
echo "Error en la realización del export"
EVENTCREATE /T ERROR /SO EXPORT.%ORACLE_SID% /ID 1000 /L APPLICATION /D "ERROR en el export de %ORACLE_SID%"
goto end

:OK 
echo "Backup OK "
EVENTCREATE /T INFORMATION /SO EXPORT.%ORACLE_SID% /ID 1000 /L APPLICATION /D "Export de  %ORACLE_SID% finalizado OK "
goto end

:end
exit %CORRECTO%

Hay que tener en cuenta que:

  • La cuenta desde la que se lance el .bat debe de tener permisos tanto para ejecutar los binarios de oracle como para lanzar el comando EVENTCREATE
  • El ID que hemos elegido (100 y 36) es arbitrario, es deicr , hemos puesto dos IDs al azar para las pruebas.
  • Hemos de conocer a proiri el path del ORACKE DIRECTORY donde va a ir el export para ponerlo en la variable RUTA

    Si somos capaces de cumplir estas 3 premisas podremos tener en el visor de eventos de windows el comienzo y el resultado de nuestro exdp en windows.

Monitorizando el alert con adrci

Hoy vamos a ver un pequeño script que puede ser muy útil para la monitorizacion.
Vamos a llamar a adrci indicándole que nos muestre los errores del alert desde la última vez que se ejecuto.
Para ello vamos a usar el comando show alert -p , marcándole como rango temporal a buscar la diferencia entre esta ejecución y a anterior.

#!/bin/bash
#
# Script que monitoriza el alert.log de una instancia desde la ultima vez que se ejecutó
# Si esta ultima ejecucion es menor de 5 minutos ejecuta los ultimos 5 minutos
#
#
# Si no guarda diene la guarda de ultima ejecucion sale con un ERROR
#
#  Asuminos timestamp'2015-02-18 00:07:49.767000 +01:00'
#

# Salida de debug
DEBUG=0

 #Comprobamos que se ha llamado de manera correcta
if  [ $# -ne 1 ]; then
echo "Uso adrci_alert  SID"
exit 3;
fi



# Inicializamos valores para el script
export ORAENV_ASK=NO
export TEMPORAL=/var/tmp/temporal_salida_alert_$$.log
export SALIDA=/var/tmp/salida_salida_alert_$$.log
export SID=$1
export GUARDA=/var/tmp/guarda_alert_${SID}.txt
DIA=`date +%Y-%m-%d`
HORA=`date +%H:%M:%S`
export AHORA="${DIA} ${HORA}.0000000 +01:00"
. oraenv  1>/dev/null



## Comenzamos la ejecucion
if [ $DEBUG -eq 1 ]; then
        echo "DEBUG: ORACLE_BASE=$ORACLE_BASE"
        echo "DEBUG: GUARDA= ${GUARDA}"
        echo "DEBUG: SALIDA= ${SALIDA} "
        echo "DEBUG: ORACLE_SID=$SID"
        echo "DEBUG: AHORA=$AHORA"
fi


# Buscamos ultima iteracion
if [ ! -f  $GUARDA ]; then
        echo "No tenemos ejecucion anterior"
        echo $AHORA > ${GUARDA}
        exit 1;
fi

#  Obtenemos el timestamp de la ultima ejecucion
TIEMPO=`cat ${GUARDA}`

# COmprobamos que han pasado mas de 5 minutos
OLD=`cat ${GUARDA}|awk '{print($1,$2)}'`
NOW="${DIA} ${HORA}.0000000"
SEGOLD=$(date -u -d "$OLD" +"%s")
SEGNOW=$(date -u -d "$NOW" +"%s")
DIFERENCIA=$((SEGNOW-SEGOLD))

# Comenzamos las iteraciones
adrci_homes=( $(adrci exec="show homes" | grep -e rdbms |grep ${SID}))
  for adrci_home in ${adrci_homes[@]}
    do
  #Generamos el fichero de comandos
   echo "SET TERMOUT OFF" > ${TEMPORAL}
   echo "SET ECHO OFF" >> ${TEMPORAL}
   echo "set home ${adrci_home} ;" >> ${TEMPORAL}
   echo "spool ${SALIDA} append " >>${TEMPORAL}
   echo "show alert -p \"message_text like '%ORA-%' and originating_timestamp >= \'${TIEMPO}\' \" -term " >>${TEMPORAL}
   echo "exit; " >> ${TEMPORAL}
     if [ $DEBUG -eq 1 ]; then
       echo "DEBUG: "
       echo "DEBUG:  adrci SCRIPT=${TEMPORAL}"
       echo "DEBUG: EL etemporal es "
       echo "DEBUG: -inicio temporal-"
       cat ${TEMPORAL}
       echo "DEBUG: -fin temporal-"
      fi
   adrci  SCRIPT=${TEMPORAL}   1>/dev/null
   tail -n+4 ${SALIDA}
   rm ${TEMPORAL}
done

#Actualizamos la guarda solamente si hace menos de 5 minutos que lo hemos ejecutado
if [ "$DIFERENCIA" -gt  299 ]; then
        echo $AHORA > ${GUARDA}
fi

## Añadir aqui la integración con monitorizacion

##Borramos la salida 
rm ${SALIDA}
#Salimos correctamente
exit 0 ;

A partir de aqui, solamente tenemos que integrar el tratamiento del fichero $SALIDA que es donde tendremos los errores del alert

Encontrar el proceso que se come la CPU en windows

Una de las principales diferencias de oracle para Unix y Windows radica en que, debido a el tipo de sistema operativo, en Windows tenemos un proceso monolítico oracle.exe, y no la multitud de procesos que nos encontramos en los sistemas Unix. Así pues, cuando queremos saber cual es el proceso que se nos come la CPU, siempre vamos a tener una misma respuesta oracle.exe y, además de eso, probablemente no podamos enlazarlo con los procesos de sistema operativo.

¿Como solucionamos este problema?

Para empezar, mi recomendación es tener en el servidor uno de estos dos programas

  • Pprocess explorer
  • QSlice

Los dos programas son gratuitos y se pueden descargar desde soporte de microsoft, y nos permitirán ver con mayor facilidad el origen de nuestro problema.

Si abrimos el process explorer , veremos algo similar a esto:
process explorer

Aquí podemos ver como uno de los procesos oracle se esta comiendo el 100% de la CPU , si hacemos boton derecho «propiedades», el process explorer nos indicará en una ventana independiente la informacion de este proceso, si vamos a la pestaña «threads» y ordenamos por CPU, tendremos:
proceso oralce.exe

Aqui vemos como los treads que mas CPU están consumiendo son

  • 3076 con el 23%
  • 4976 con el 19,95%

Ahora, teniendo estos dos número de thread, si que podremos ir a nuestra ventana de sql y enlazar este numero de thread con el proceso/sesion de Oracle que está causando la carga


select proc.spid ThreadNO,  
sess.username Usuario,  
sess.osuser OSUser,
sess.machine Maquina,  
sess.status Estado,  
sess.sid SessionID,  
sess.program Program  
from v$process proc, v$session sess, v$bgprocess bg  
where sess.paddr = proc.addr  
and bg.paddr(+) = proc.addr  
and proc.spid in (3076)

Esta informacion tambien puede obtenerse con qslice.exe, solamente que la información del thread está en exadecimal, y habremos de pasarla a decimal, por otra parte, la ventaja del qslice.exe es que es más ligero que el process explorer, con lo que, como decía al principio, mi recomendación es tener los dos en el servidor

Monitorizar el alert.log desde una sql remota

El fichero de alertas de oracle alert.log es uno de los ficheros que tradicionalmente revisamos en busca de errores de la base de datos.
Hasta la versión 11g esta monitorización se hacía por medio del scripts que interactuaban con ficheros del sistema operativo, lo que nos llevaba a tener que mantener estos scripts para las distintas versiones de shells de sistema, o tener que instalar algún tipo de interprete en el sistema que nos lo gestionara de manera multiplataforma.

Una de las grandes ventajas de la 11g es que Oracle nos ha obsequiado con una tabla de base de datos que mapea esta información del alert.log dentro de la base de datos . Estamos hablando de la tabla x$dbgalertext;

Mediante la tabla x$dbgalertext podemos obtener toda la informacion que está en el alert.log, su contenido es:

SQL> desc X$DBGALERTEXT

           Name                            Null?    Type
           ------------------------------- -------- -------------------------
    1      ADDR                                     RAW(4)
    2      INDX                                     NUMBER
    3      INST_ID                                  NUMBER
    4      ORIGINATING_TIMESTAMP                    TIMESTAMP(3) WITH TIME ZONE
    5      NORMALIZED_TIMESTAMP                     TIMESTAMP(3) WITH TIME ZONE
    6      ORGANIZATION_ID                          VARCHAR2(64)
    7      COMPONENT_ID                             VARCHAR2(64)
    8      HOST_ID                                  VARCHAR2(64)
    9      HOST_ADDRESS                             VARCHAR2(16)
   10      MESSAGE_TYPE                             NUMBER
   11      MESSAGE_LEVEL                            NUMBER
   12      MESSAGE_ID                               VARCHAR2(64)
   13      MESSAGE_GROUP                            VARCHAR2(64)
   14      CLIENT_ID                                VARCHAR2(64)
   15      MODULE_ID                                VARCHAR2(64)
   16      PROCESS_ID                               VARCHAR2(32)
   17      THREAD_ID                                VARCHAR2(64)
   18      USER_ID                                  VARCHAR2(64)
   19      INSTANCE_ID                              VARCHAR2(64)
   20      DETAILED_LOCATION                        VARCHAR2(160)
   21      PROBLEM_KEY                              VARCHAR2(64)
   22      UPSTREAM_COMP_ID                         VARCHAR2(100)
   23      DOWNSTREAM_COMP_ID                       VARCHAR2(100)
   24      EXECUTION_CONTEXT_ID                     VARCHAR2(100)
   25      EXECUTION_CONTEXT_SEQUENCE               NUMBER
   26      ERROR_INSTANCE_ID                        NUMBER
   27      ERROR_INSTANCE_SEQUENCE                  NUMBER
   28      VERSION                                  NUMBER
   29      MESSAGE_TEXT                             VARCHAR2(2048)
   30      MESSAGE_ARGUMENTS                        VARCHAR2(128)
   31      SUPPLEMENTAL_ATTRIBUTES                  VARCHAR2(128)
   32      SUPPLEMENTAL_DETAILS                     VARCHAR2(128)
   33      PARTITION                                NUMBER
   34      RECORD_ID                                NUMBER

Ahora bien, ¿como accedemos a ella?

La tabla no puede ser accedida directamente desde un usuario que no sea sys, así que, lo que haremos será el crear una vista sobre esta tabla (a la que llamaremos por ejemplo ficheroalert ) y permitirle que lo vea a nuestro usuario de monitorizacion.


create view ficheroalert as select  * from sys.x$dbgalertext;
grant select on sys.ficheroalert to MONITORIZACION;

A partir de aquí, solamente tenemos que jugar con los campos descritos arriba y podremos obtener la informacion que deseemos.
En mi caso , por ejemplo, me gustaría saber si ha habido algún mensaje ORA- o ERROR en los ultimos 5 munitos.

La consulta que ejecutaré para obtenerlo es:


select to_char(ORIGINATING_TIMESTAMP, 'dd-mon-yyyy hh24:mi:ss'),
      substr(MESSAGE_TEXT, 1, 300) message_text
    from sys.ficheroalert
    where (MESSAGE_TEXT like '%ORA-%'
            or upper(MESSAGE_TEXT) like '%ERROR%')
     and 
           cast(ORIGINATING_TIMESTAMP as DATE) > sysdate - 5/1440;
            - X/1440 es la X en minutos 

Entrada en ingles en Monitoring the alert.log from a remote sql