GNU/Linux >> Tutoriales Linux >  >> Linux

¿Cómo administro la verbosidad del registro dentro de un script de shell?

Mejorando un poco más la idea de @Fred, podríamos construir una pequeña biblioteca de registro de esta manera:

declare -A _log_levels=([FATAL]=0 [ERROR]=1 [WARN]=2 [INFO]=3 [DEBUG]=4 [VERBOSE]=5)
declare -i _log_level=3
set_log_level() {
  level="${1:-INFO}"
  _log_level="${_log_levels[$level]}"
}

log_execute() {
  level=${1:-INFO}
  if (( $1 >= ${_log_levels[$level]} )); then
    "${@:2}" >/dev/null
  else
    "${@:2}"
  fi
}

log_fatal()   { (( _log_level >= ${_log_levels[FATAL]} ))   && echo "$(date) FATAL  $*";  }
log_error()   { (( _log_level >= ${_log_levels[ERROR]} ))   && echo "$(date) ERROR  $*";  }
log_warning() { (( _log_level >= ${_log_levels[WARNING]} )) && echo "$(date) WARNING  $*";  }
log_info()    { (( _log_level >= ${_log_levels[INFO]} ))    && echo "$(date) INFO   $*";  }
log_debug()   { (( _log_level >= ${_log_levels[DEBUG]} ))   && echo "$(date) DEBUG  $*";  }
log_verbose() { (( _log_level >= ${_log_levels[VERBOSE]} )) && echo "$(date) VERBOSE $*"; }

# functions for logging command output
log_debug_file()   { (( _log_level >= ${_log_levels[DEBUG]} ))   && [[ -f $1 ]] && echo "=== command output start ===" && cat "$1" && echo "=== command output end ==="; }
log_verbose_file() { (( _log_level >= ${_log_levels[VERBOSE]} )) && [[ -f $1 ]] && echo "=== command output start ===" && cat "$1" && echo "=== command output end ==="; }

Digamos que la fuente anterior está en un archivo de biblioteca llamado logging_lib.sh, podríamos usarlo en un script de shell regular de esta manera:

#!/bin/bash

source /path/to/lib/logging_lib.sh

set_log_level DEBUG

log_info  "Starting the script..."

# method 1 of controlling a command's output based on log level
log_execute INFO date

# method 2 of controlling the output based on log level
date &> date.out
log_debug_file date.out

log_debug "This is a debug statement"
...
log_error "This is an error"
...
log_warning "This is a warning"
...
log_fatal "This is a fatal error"
...
log_verbose "This is a verbose log!"

Dará como resultado esta salida:

Fri Feb 24 06:48:18 UTC 2017 INFO    Starting the script...
Fri Feb 24 06:48:18 UTC 2017
=== command output start ===
Fri Feb 24 06:48:18 UTC 2017
=== command output end ===
Fri Feb 24 06:48:18 UTC 2017 DEBUG   This is a debug statement
Fri Feb 24 06:48:18 UTC 2017 ERROR   This is an error
Fri Feb 24 06:48:18 UTC 2017 ERROR   This is a warning
Fri Feb 24 06:48:18 UTC 2017 FATAL   This is a fatal error

Como podemos ver, log_verbose no produjo ningún resultado ya que el nivel de registro está en DEBUG, un nivel por debajo de VERBOSE. Sin embargo, log_debug_file date.out produjo la salida y también lo hizo log_execute INFO , ya que el nivel de registro está establecido en DEBUG, que es>=INFO.

Usando esto como base, también podríamos escribir envoltorios de comandos si necesitamos un ajuste aún más fino:

git_wrapper() {
  # run git command and print the output based on log level
}

Con estos en su lugar, la secuencia de comandos podría mejorarse para tomar un argumento --log-level level que puede determinar el nivel de detalle del registro con el que debe ejecutarse.

Aquí hay una implementación completa de registro para Bash, rica en múltiples registradores:

https://github.com/codeforester/base/blob/master/lib/stdlib.sh

Si alguien tiene curiosidad acerca de por qué algunas variables se nombran con un guión bajo en el código anterior, consulte esta publicación:

  • Corregir mayúsculas y minúsculas variables de Bash y script de shell

Ya tiene lo que parece ser la idea más limpia en su pregunta (una función de contenedor), pero parece pensar que sería complicado. Te sugiero que lo reconsideres. Podría parecerse a lo siguiente (no necesariamente una solución completa, solo para darle una idea básica):

#!/bin/bash

# Argument 1 : Logging level for that command
# Arguments 2... : Command to execute
# Output suppressed if command level >= current logging level 
log()
{
if
  (($1 >= logging_level))
then
  "${@:2}" >/dev/null 2>&1
else
  "${@:2}"
fi
}

logging_level=2

log 1 command1 and its args
log 2 command2 and its args
log 3 command4 and its args

Puede organizar cualquier redirección necesaria (con descriptores de archivo si lo desea) para que se maneje en la función contenedora, de modo que el resto de la secuencia de comandos permanezca legible y libre de redirecciones y condiciones según el nivel de registro seleccionado.


Solución 1. Considere usar descriptores de archivo adicionales. Redirija los descriptores de archivo requeridos a STDOUT o /dev/null dependiendo de la verbosidad seleccionada. Redireccione la salida de cada declaración en su script a un descriptor de archivo correspondiente a su importancia. Eche un vistazo a https:// unix.stackexchange.com/a/218355.


Linux
  1. ¿Cómo asignar la salida de un comando a una variable de shell?

  2. ¿Cómo manejar los interruptores en un script de Shell?

  3. ¿Cómo crear un archivo temporal en Shell Script?

  4. ¿Cómo llamar a una función Bash en Bash Script dentro de Awk?

  5. ¿Cómo saber si la salida de un comando o script de Shell es Stdout o Stderr?

Cómo redirigir la salida del comando de shell

Cómo escribir un script de Shell en Ubuntu

Cómo almacenar un comando de Linux como una variable en el script de Shell

Cómo ejecutar Shell Script como servicio SystemD en Linux

¿Cómo ejecutar un comando en un script de Shell?

Biblioteca de salida de scripts de shell de colores