GNU/Linux >> Linux Esercitazione >  >> Linux

Come gestisco la verbosità del registro all'interno di uno script di shell?

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 .


Linux
  1. Come gestire i file di registro utilizzando Logrotate in Linux

  2. Come creare un file temporaneo nello script della shell?

  3. Come chiamare una funzione Bash nello script Bash all'interno di Awk?

  4. Come sapere se l'output di un comando o di uno script di shell è Stdout o Stderr?

  5. Rientro dell'output su più righe in uno script di shell

Come reindirizzare l'output del comando della shell

Come scrivere uno script di shell in Ubuntu

Come memorizzare un comando Linux come variabile nello script della shell

Come eseguire lo script della shell come servizio SystemD in Linux

Come eseguire un comando in uno script della shell?

Libreria di output di script di shell colorata