Script KSH , Monitorizar versións de sub-logs máis recentes que as que reflexan os blogs pais

Logo de KSH

Este artigo trata sobre un script que monitoriza uns sublogs que están relacionados cun log pai, o realizara pra o mantemento dunhas máquinas UNIX e está algo modificado pra non comprometer ao sistema no que funcionaba mais poder ensinar un exemplo de cómo se fai.

Explicación

A cousa é que cómo son moitas máquinas UNIX as que tiña que tratar, ian mudando por motivos de mantemento, este script non poido deixalo en ningunha delas por ser un lío “burocrático” da propia empresa e un engorro pra min poder executalo nestas máquinas, asi que directamente o levaba comigo e vou copiando e pegando estas funcións a través do putty, así explotaba satisfactoriamente esta ferramenta e me aforraba un bo tempo ;)

Debido a que o script o fixen orixinalmente pra un sistema e prefiro non dar detalles do mesmo por evitarlles problemas de seguridade, o tiven que retocar un pouco e se o executas non vai funcionar.

Mais o publico como exemplo dun script KSH por se buscas inspiración ou queres ver a súa sintaxis.

Este script orixinalmente servía pra monitorizalos logs máis actuáis dos procesos que habian sido rexistrados por un proceso de mantemento que se executaba periódicamente e deixaba os seus reulstados nun log, que se achaba sempre nunha ruta definida por variable no sistema.

O caso era que me tocaba a tarefa a veces menos tediosa ( caso de 3 procesos ou menos ) e outras máis improductivas de revisar a man, chegando a casos de 14 logs ou máis.

Cando chega un momento no que as túas tarefas non teñen sentido por seren repetitivas, se incrementan a niveis exponenciais e todo é dentro da mesma máquina UNIX, a todo ser humán lle chega esa máxica sensación de “Ei, vou facer un script que me resolva isto! ;D “.

E eso é o que vou a expoñer a continuación, o resultado desa motivación que resultou nun script que en ocasións me aforrou máis de 20 ou 30 minutos de rebuscar en logs.

Sinificados dos nomes do exemplo

Desafortunhadamente tras revisalo resultado da censura autoimposta, poiden apreciar que os nomes das funcións quedaron demasiado largos.

Aquí deixo unha explicación de ditos nomes:

Nome: Explicación:
APLICACION Internamente teñen un nome pra referirse a aplicación da que son, mais o sustituín por “APLICACION”.
aplicación_que_fai_o_log_pai O nome do programa que monitoriza os subprogramas.
unha_das_aplicacións Dita aplicación pertence ao grupo de “APLICACIÓNS”.
unha_das_aplicacións_LOG Aquí iría a variable de contorna que contén a ruta a determinado tipo de logs.
ESTÁ-ok Unha cadea de texto nos logs, que indica a finalización correcta do proceso que crea o log.
ESTÁ-mal Unha cadea de texto nos logs, que indica a finalización con erro do proceso que crea o log.
SUB_APLICACION Sub-aplicación cuxo log é amosado polo log pai.

Nalgúns nomes de funcións ata lles separei o nome sen sentido resultante de esta autocensura por facilitala compresión na súa lectura.

O código

Monitorizalos sublogs máis recentes aos rexistrados nun log dado:
#!/bin/ksh
#############################################
#  Title:  Monitoriza logs rexistrados nun log
#  Author: Delio Docampo Cordeiro
#  Date:   20160702
#############################################
MASCARA_DATA="`date +%Y%m`"
APLICACION_MAY="APLICACION"                                              # Indicar nome aplicación en maiúsculas.
APLICACION_MIN=`echo $APLICACION_MAY | tr -s '[:upper:]' '[:lower:]'`    # A aplicación en minúsculas
ESTADO_LOGS=""

vixia_aplicación_que_fai_o_log_pai(){
  # Atopa o último log da "aplicación_que_fai_o_log_pai" e nos amosa o contido das liñas
  # que teñen erros ou se atopan en execución (Omite as "non ten").

  # Co siguiente CASE fago que o script poida ser executado en tódolos contornos de outras aplicacións
  # do sistema, ademáis de evitar que esta función se execute sen saber onde.

  case $APLICACION_MAY in
    unha_das_aplicacións)
      ULTIMO_LOG=`ls -rt $unha_das_aplicacións_LOG/*aplicación_que_fai_o_log_pai* | tail -1`
    ;;
    *)
      echo "Indica unha APLICACION valida, por favor."
    ;;
  esac
  echo "Buscando logs con faios, un momento por favor..."

  # A continuación me encargo de leer o fichero do log liña a liña, se o log é moi grande é mellor
  # ir "saturando" la ram pouco a pouco que cargarlo todo na memoria

  while IFS= read -r LINA
  do
    LINA_PROCESADA=`echo "$LINA" | grep "\.log" | grep -v "non ten"` # As liñas con algo como "non ten fallos" no me interesan.
    # Asegurándome de que o grep haxa devolto algo co que traballar, se non, pasando...:
    if [[ ! -z $LINA_PROCESADA ]];
    then
        # Aquí témolas liñas do log que nos interesa tratar.
        # Vai cargar en ELEMENTO cada palabra da liña, usando os espazos como separadores:
        for ELEMENTO in $LINA_PROCESADA
        do
         # Asegurarnos de que é un nome ou ruta de log:
          ELEMENTO_FILTRADO1=`echo $ELEMENTO | grep "\.log"`
          # Se grep devolve algo, o analizamos:
          if [[ ! -z $ELEMENTO_FILTRADO1 ]];
          then
            ELEMENTO_FILTRADO2=`echo $ELEMENTO_FILTRADO1 | grep "/"` # Asegurarnos de que é unha ruta
            # O problema que tiven que resolver, era que a veces pintan os nomes cunha ruta ao log e outras só co nome do log:
            if [[ ! -z $ELEMENTO_FILTRADO2 ]];
            then
              # Estamos seguros de que é unha ruta a un log.
               # Vamos amosando por pantaia pra que non desespere o usuario.
              echo "$ELEMENTO_FILTRADO2"
              # Vamos acumulandoas rutas aos logs que reflexan o log pai:
              LOGS_PROCESOS_TAR=`echo $LOGS_PROCESOS_TAR" "$ELEMENTO_FILTRADO2`
            else
              # Sábase que é un .log mais como non parece unha ruta, ténse que agregar a ruta dos logs.
              # Amosando por patnaia o que vamos atopando:
              echo "<ruta_onde_a_aplicación_verquía_tódolos_seus_logs>$ELEMENTO_FILTRADO1"
              # Si se rexistra no noso "churro" de logs con ruta, agrégalle unha ruta ao metelo no mesmo:
              LOGS_PROCESOS_TAR=`echo $LOGS_PROCESOS_TAR" <ruta_onde_a_aplicación_verquía_tódolos_seus_logs>"$ELEMENTO_FILTRADO1`
            fi
          fi
        done
    fi
  done < "$ULTIMO_LOG"    # Lle pasamos a WHILE o último log pai que atopamos, pra traballar con él no bucle.
  # Finalmente creamos un array en ksh chamado "CONXUNTO_DE_LOGS" o cal conterá os elementos do "churo" que fomos elaborando:
  set -A CONXUNTO_DE_LOGS $LOGS_PROCESOS_TAR
}

comproba_lina_log(){
  ########## Comproba liña log , en execución, ESTÁ-Ok, error
  LINA_LOG=$1
  LINA_PROCESADA=`echo $LINA_LOG | grep -i ESTÁ-ok`  # Si está ok.
  if [[ ! -z $LINA_PROCESADA ]];
  then
     # Rematou o empacado , con ESTÁ-ok`
     echo "\033[1;32m""É un esta-ok""\033[m"    # Amosamos en verde a mensaxe "É un esta-ok"
     echo "\033[1;32m""$LINA_PROCESADA""\033[m" # A liña na que nos basamos, pra que revise o usuario.
     ESTADO_LOGS=`echo $ESTADO_LOGS" ESTÁ-ok"`  # Queda rexistrado que este log, ten un estado OK.
  else
    # Está notro estado diferente a ESTÁ-ok
    # No caso de que non remate ok, pudo rematar con error, polo que volvemos a revisalo, esta vez procurando erro:
    LINA_PROCESADA=`echo $LINA_LOG | grep -i ESTÁ-mal`
    if [[ ! -z $LINA_PROCESADA ]];
    then
      # Rematou con ESTÁ-mal
      echo "\033[1;31m""É un esta-mal""\033[m" # Devolvemos "É un está-mal" pintando en vermello por pantaia.
     echo "\033[1;31m""$LINA_PROCESADA""\033[m"
     ESTADO_LOGS=`echo $ESTADO_LOGS" ESTÁ-mal"`
     # Ou remata "ok" ou "mal", se chega aquí é que sigue en execución e pinto a liña máis recente do
     # log fillo en azul, pra que vexa que está traballando:
    else
      echo "Esta en execución"
      echo "\033[0;34m""$LINA_LOG""\033[m"
     ESTADO_LOGS=`echo $ESTADO_LOGS" Executándose"`
    fi
  fi
  ############## FIN COMPROBA LIÑA LOG
}

busca_ultimo_log(){
  ################
  # Dos logs amosados por aplicación_que_fai_o_log_pai, lle pasamos un coa ruta completa, tipo:
  #   <ruta_onde_a_aplicación_verquía_tódolos_seus_logs>SUB_APLICACION.Z_20160628001303.log
  # debemos listar tódolos seus logs, pra logo comprobrar o último enviado.
  # Obxetivo do último log máis actual: <ruta_onde_a_aplicación_verquía_tódolos_seus_logs>SUB_APLICACION.Z_20160629181306.log
  ###############
  # Nos interesa collela ruta, nome de SUB_APLICACION , sen a máscara de data do nome, polo que collemos lo que está antes do último "_":
  BASE_LOG=`echo $1 | rev | cut -d"_" -f 2- | rev`"_"
  BUSQUEDA="$BASE_LOG$MASCARA_DATA""*"    # Procuraremos logs, que estén no rango da data que nos interese definido en MASCARA_DATA.
  ULTIMO_LOG=`ls -rt $BUSQUEDA | tail -1` # Collémolo log máis recente existente no tiempo real do sistema.
  echo "Ultima liña de: \""`ls -l $ULTIMO_LOG`"\":"  # Amosamos a ruta ao último log pra que sepa qué log estamos a tratar.
  LINA_LOG=`cat $ULTIMO_LOG | tail -1` # Collemos dita liña e a gardamos pra procesala posteriormente.
  # Ao parseala esta función, obtemola procesada pra saber rápidamente se este proceso está en execución, se rematou ok ou con erro:
  comproba_lina_log "$LINA_LOG"
}

procesa_logs(){
    # Se lle pasa un array de rutas de logs e este chama a "busca_ultimo_log" por cada log.
    LOGS="$1"
    COUNT=0
    for LOG in ${LOGS[@]}
    do
      COUNT=$(($COUNT+1))                        # Vamos amosando os logs por pantaia.
      echo "== LOG $COUNT ===================="
      busca_ultimo_log "$LOG"
    done
    # Esta parte amosa un resumen moito máis compacto e breve, que sería o que o usuario acabaría poñendo nos seus reportes
    echo "Resumen do estado dos logs:"
    echo "_______________________________________"
     # Sen que nadie note que foi automatizado :P, aforrándónolos 20 o 30 mins de comprobarlos manualmente.
    COUNT=0
    set -A ESTADO_LOGS $ESTADO_LOGS
    for LOG in ${LOGS[@]}
    do
      echo "$LOG - "${ESTADO_LOGS[$COUNT]}
      COUNT=$(($COUNT+1))
    done
}

executa_monitoriza_aplicación_que_fai_o_log_pai_unha_das_aplicacións(){
   # Esta función ensambla todo, pra poder executarlo cómodamente.
  vixia_aplicación_que_fai_o_log_pai
  procesa_logs "${CONXUNTO_DE_LOGS[*]}"  # Aquí iníciase a "maxia" :)
}
executa_monitoriza_aplicación_que_fai_o_log_pai_unha_das_aplicacións # Executámola función que inicia todo.

# FIN!! Ou inicio, según se o lees pra ver cómo está feito, ou no sentido da execución :P