GNU/Linux >> Tutoriels Linux >  >> Linux

Comment gérer la verbosité du journal dans un script shell ?

Améliorant un peu plus l'idée de @Fred, nous pourrions créer une petite bibliothèque de journalisation de cette façon :

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 ==="; }

Supposons que la source ci-dessus se trouve dans un fichier de bibliothèque appelé logging_lib.sh, nous pourrions l'utiliser dans un script shell normal de cette façon :

#!/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!"

Produira cette sortie :

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

Comme nous pouvons le voir, log_verbose n'a produit aucune sortie car le niveau de journalisation est à DEBUG, un niveau en dessous de VERBOSE. Cependant, log_debug_file date.out a produit la sortie et log_execute INFO aussi , puisque le niveau de journalisation est défini sur DEBUG, qui est>=INFO.

En utilisant ceci comme base, nous pourrions également écrire des wrappers de commande si nous avons besoin d'un réglage encore plus fin :

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

Avec ceux-ci en place, le script pourrait être amélioré pour prendre un argument --log-level level qui peut déterminer la verbosité du journal avec laquelle il doit s'exécuter.

Voici une implémentation complète de la journalisation pour Bash, riche de plusieurs enregistreurs :

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

Si quelqu'un est curieux de savoir pourquoi certaines variables sont nommées avec un trait de soulignement dans le code ci-dessus, consultez cet article :

  • Corriger la capitalisation des variables de script bash et shell

Vous avez déjà ce qui semble être l'idée la plus propre dans votre question (une fonction wrapper), mais vous semblez penser que ce serait désordonné. Je vous suggère de reconsidérer. Cela pourrait ressembler à ceci (pas nécessairement une solution à part entière, juste pour vous donner l'idée de base) :

#!/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

Vous pouvez faire en sorte que toute redirection requise (avec des descripteurs de fichiers si vous le souhaitez) soit gérée dans la fonction wrapper, afin que le reste du script reste lisible et exempt de redirections et de conditions en fonction du niveau de journalisation sélectionné.


Solution 1. Envisagez d'utiliser des descripteurs de fichiers supplémentaires. Redirigez les descripteurs de fichiers requis vers STDOUT ou /dev/null en fonction de la verbosité sélectionnée. Redirigez la sortie de chaque instruction de votre script vers un descripteur de fichier correspondant à son importance. Consultez https:// unix.stackexchange.com/a/218355 .


Linux
  1. Comment gérer les fichiers journaux à l'aide de Logrotate sous Linux

  2. Comment créer un fichier temporaire en script shell ?

  3. Comment appeler une fonction Bash dans le script Bash à l'intérieur d'Awk ?

  4. Comment savoir si la sortie d'une commande ou d'un script shell est Stdout ou Stderr ?

  5. Journal Crontab :comment enregistrer la sortie de mon script Cron

Comment rediriger la sortie de la commande shell

Comment écrire un script shell dans Ubuntu

Comment stocker une commande Linux en tant que variable dans un script shell

Comment exécuter un script Shell en tant que service SystemD sous Linux

Comment exécuter une commande dans un script shell ?

Bibliothèque de sortie de script shell coloré