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 .