Migliorando un po' di più l'idea di @Fred, potremmo creare una piccola libreria di logging in questo modo:
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 ==="; }
Diciamo che il sorgente di cui sopra si trova in un file di libreria chiamato logging_lib.sh, potremmo usarlo in un normale script di shell in questo modo:
#!/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!"
Risulterà in questo output:
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
Come possiamo vedere, log_verbose
non ha prodotto alcun output poiché il livello di log è a DEBUG, un livello sotto VERBOSE. Tuttavia, log_debug_file date.out
ha prodotto l'output e così anche log_execute INFO
, poiché il livello di log è impostato su DEBUG, che è>=INFO.
Usando questo come base, potremmo anche scrivere wrapper di comando se abbiamo bisogno di una messa a punto ancora più precisa:
git_wrapper() {
# run git command and print the output based on log level
}
Con questi in atto, lo script potrebbe essere migliorato per accettare un argomento --log-level level
che può determinare la verbosità del registro con cui dovrebbe essere eseguito.
Ecco un'implementazione completa della registrazione per Bash, ricca di più logger:
https://github.com/codeforester/base/blob/master/lib/stdlib.sh
Se qualcuno è curioso di sapere perché alcune variabili sono denominate con un carattere di sottolineatura iniziale nel codice sopra, vedere questo post:
- Corretta la capitalizzazione delle variabili degli script Bash e shell
Hai già quella che sembra essere l'idea più chiara nella tua domanda (una funzione wrapper), ma sembri pensare che sarebbe disordinato. Ti suggerirei di riconsiderare. Potrebbe assomigliare a quanto segue (non necessariamente una soluzione completa, solo per darti un'idea di 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
Puoi fare in modo che qualsiasi reindirizzamento richiesto (con descrittori di file se lo desideri) venga gestito nella funzione wrapper, in modo che il resto dello script rimanga leggibile e libero da reindirizzamenti e condizioni a seconda del livello di registrazione selezionato.
Soluzione 1. Prendi in considerazione l'utilizzo di descrittori di file aggiuntivi. Reindirizza i descrittori di file richiesti a STDOUT o /dev/null a seconda della verbosità selezionata. Reindirizza l'output di ogni istruzione nello script a un descrittore di file corrispondente alla sua importanza. Dai un'occhiata a https:// unix.stackexchange.com/a/218355 .