GNU/Linux >> Znalost Linux >  >> Linux

Jak mohu spravovat podrobnost protokolu uvnitř skriptu shellu?

Abychom myšlenku @Freda ještě trochu vylepšili, mohli bychom vytvořit malou protokolovací knihovnu tímto způsobem:

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

Řekněme, že výše uvedený zdroj je v souboru knihovny s názvem logging_lib.sh, mohli bychom jej použít v běžném skriptu shellu takto:

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

Výsledkem bude tento výstup:

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

Jak vidíme, log_verbose neprodukoval žádný výstup, protože úroveň protokolu je na DEBUG, o jednu úroveň pod VERBOSE. Nicméně log_debug_file date.out vytvořil výstup a stejně tak log_execute INFO , protože úroveň protokolu je nastavena na DEBUG, což je>=INFO.

Když to použijeme jako základ, mohli bychom také napsat obaly příkazů, pokud potřebujeme ještě jemnější doladění:

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

S těmi na místě by mohl být skript vylepšen tak, aby přijal argument --log-level level který může určit podrobnost protokolu, se kterou by měl běžet.

Zde je kompletní implementace protokolování pro Bash, bohatá na více protokolů:

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

Pokud někoho zajímá, proč jsou některé proměnné ve výše uvedeném kódu pojmenovány s podtržítkem na začátku, podívejte se na tento příspěvek:

  • Správná velká písmena proměnných skriptu Bash a shell

Ve své otázce již máte to, co se zdá být nejčistší (funkce wrapper), ale zdá se, že si myslíte, že by to bylo chaotické. Navrhoval bych, abyste to přehodnotili. Mohlo by to vypadat následovně (ne nutně plnohodnotné řešení, jen pro základní představu):

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

Můžete zařídit, aby jakékoli požadované přesměrování (pokud chcete s deskriptory souborů) bylo zpracováno ve funkci wrapper, takže zbytek skriptu zůstane čitelný a bez přesměrování a podmínek v závislosti na zvolené úrovni protokolování.


Řešení 1. Zvažte použití dalších deskriptorů souborů. Přesměrujte požadované deskriptory souborů na STDOUT nebo /dev/null v závislosti na zvolené upovídanosti. Přesměrujte výstup každého příkazu ve vašem skriptu na deskriptor souboru odpovídající jeho důležitosti. Podívejte se na https:// unix.stackexchange.com/a/218355 .


Linux
  1. Jak zacházet s přepínači ve skriptu Shell?

  2. Jak zjistit, zda je výstup příkazového nebo shellového skriptu Stdout nebo Stderr?

  3. Odsazení víceřádkového výstupu ve skriptu shellu

  1. Jak přiřadit výstup příkazu proměnné shellu?

  2. Jak vytvořit dočasný soubor ve skriptu Shell?

  3. Jak volat funkci Bash ve skriptu Bash uvnitř Awk?

  1. Crontab Log:Jak protokolovat výstup mého skriptu Cron

  2. Jak spustit skript shellu při spuštění

  3. Jak spočítat počet karet v každém řádku pomocí skriptu shell?